summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/ActivityOptions.java24
-rw-r--r--core/java/android/app/ActivityThread.java11
-rw-r--r--core/java/android/app/AppOpsManager.java263
-rw-r--r--core/java/android/app/Instrumentation.java41
-rw-r--r--core/java/android/app/SyncNotedAppOp.java3
-rw-r--r--core/java/android/app/WallpaperManager.java14
-rw-r--r--core/java/android/app/backup/FullBackup.java22
-rw-r--r--core/java/android/app/servertransaction/LaunchActivityItem.java20
-rw-r--r--core/java/android/bluetooth/le/ScanFilter.java24
-rw-r--r--core/java/android/content/ContentProvider.java3
-rw-r--r--core/java/android/hardware/ISensorPrivacyManager.aidl2
-rw-r--r--core/java/android/hardware/SensorPrivacyManager.java40
-rw-r--r--core/java/android/hardware/camera2/MultiResolutionImageReader.java2
-rw-r--r--core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java35
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDeviceImpl.java8
-rw-r--r--core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java34
-rw-r--r--core/java/android/hardware/camera2/impl/CameraExtensionUtils.java2
-rw-r--r--core/java/android/hardware/camera2/impl/CameraMetadataNative.java21
-rw-r--r--core/java/android/hardware/camera2/params/InputConfiguration.java10
-rw-r--r--core/java/android/hardware/camera2/utils/SurfaceUtils.java17
-rw-r--r--core/java/android/os/BinderProxy.java5
-rw-r--r--core/java/android/os/FileUtils.java20
-rw-r--r--core/java/android/os/Process.java42
-rw-r--r--core/java/android/permission/PermissionUsageHelper.java84
-rw-r--r--core/java/android/provider/Settings.java55
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java3
-rw-r--r--core/java/android/service/voice/SoftwareHotwordDetector.java3
-rw-r--r--core/java/android/service/voice/VoiceInteractionService.java6
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java180
-rw-r--r--core/java/android/view/Display.java6
-rw-r--r--core/java/android/view/DisplayInfo.java15
-rw-r--r--core/java/android/view/RemoteAnimationTarget.java17
-rw-r--r--core/java/android/view/SurfaceView.java153
-rw-r--r--core/java/android/view/WindowInfo.java7
-rw-r--r--core/java/android/view/accessibility/AccessibilityWindowInfo.java29
-rw-r--r--core/java/android/view/inputmethod/InputConnection.java6
-rw-r--r--core/java/android/view/translation/Translator.java29
-rw-r--r--core/java/android/window/TransitionInfo.java46
-rw-r--r--core/java/android/window/WindowContainerTransaction.java6
-rw-r--r--core/java/com/android/internal/app/IAppOpsStartedCallback.aidl3
-rw-r--r--core/java/com/android/internal/jank/FrameTracker.java159
-rw-r--r--core/java/com/android/internal/jank/InteractionJankMonitor.java229
-rw-r--r--core/java/com/android/internal/os/ProcLocksReader.java89
-rw-r--r--core/java/com/android/internal/util/ProcFileReader.java43
-rw-r--r--core/jni/android_graphics_BLASTBufferQueue.cpp8
-rw-r--r--core/jni/android_media_AudioSystem.cpp8
-rw-r--r--core/res/AndroidManifest.xml9
-rw-r--r--core/res/res/layout/splash_screen_view.xml1
-rw-r--r--core/res/res/values-ar/strings.xml2
-rw-r--r--core/res/res/values-de/strings.xml4
-rw-r--r--core/res/res/values-es/strings.xml2
-rw-r--r--core/res/res/values-fa/strings.xml2
-rw-r--r--core/res/res/values-te/strings.xml86
-rw-r--r--core/res/res/values-ur/strings.xml2
-rw-r--r--core/res/res/values/config.xml17
-rw-r--r--core/res/res/values/symbols.xml3
-rw-r--r--core/tests/coretests/src/android/app/backup/FullBackupTest.java33
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java3
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/TestUtils.java8
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java1
-rw-r--r--core/tests/coretests/src/android/view/WindowInfoTest.java3
-rw-r--r--core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java280
-rw-r--r--core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java41
-rw-r--r--core/tests/coretests/src/com/android/internal/os/ProcLocksReaderTest.java90
-rw-r--r--core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java2
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java40
-rw-r--r--graphics/java/android/graphics/BLASTBufferQueue.java10
-rw-r--r--graphics/java/android/graphics/Paint.java16
-rw-r--r--graphics/java/android/graphics/drawable/RippleAnimationSession.java12
-rw-r--r--graphics/java/android/graphics/drawable/RippleDrawable.java7
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java28
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java90
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java107
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java57
-rw-r--r--libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml2
-rw-r--r--libs/WindowManager/Shell/res/layout/bubble_manage_button.xml8
-rw-r--r--libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml30
-rw-r--r--libs/WindowManager/Shell/res/values-te/strings.xml2
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java27
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java25
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java50
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java39
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java291
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java147
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java41
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java132
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/Android.bp8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt63
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt17
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt25
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt15
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt36
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt24
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt43
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt45
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt13
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt44
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt27
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt56
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt22
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt24
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt58
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt53
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt111
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt64
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt80
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt64
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt62
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt19
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt53
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt48
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt39
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt37
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt60
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt52
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/CommonAssertions.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt26
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt16
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt16
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt18
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt10
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt35
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt18
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipShelfHeightTest.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt28
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt27
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt41
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt9
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java17
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java31
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java173
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp6
-rw-r--r--media/java/android/media/AudioManagerInternal.java11
-rw-r--r--media/java/android/media/AudioSystem.java7
-rw-r--r--media/java/android/media/ExifInterface.java9
-rw-r--r--media/java/android/media/MediaMetadataRetriever.java17
-rw-r--r--media/java/android/media/MediaPlayer.java13
-rw-r--r--media/java/android/media/MediaRouter2Manager.java3
-rw-r--r--mms/OWNERS8
-rw-r--r--packages/CarrierDefaultApp/OWNERS7
-rw-r--r--packages/PackageInstaller/res/values-te/strings.xml2
-rw-r--r--packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java29
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ky/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java65
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java3
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java29
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java40
-rw-r--r--packages/Shell/res/values-te/strings.xml2
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/flags/Flag.kt52
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java (renamed from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/Extensions.kt)12
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/FlagReaderPlugin.java71
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml10
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml71
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml18
-rw-r--r--packages/SystemUI/res-keyguard/layout/qs_footer_actions.xml104
-rw-r--r--packages/SystemUI/res-keyguard/values/dimens.xml6
-rw-r--r--packages/SystemUI/res/anim/fp_to_unlock.xml8
-rw-r--r--packages/SystemUI/res/anim/lock_to_unlock.xml4
-rw-r--r--packages/SystemUI/res/drawable/ic_unlock.xml4
-rw-r--r--packages/SystemUI/res/layout/keyguard_status_bar.xml5
-rw-r--r--packages/SystemUI/res/layout/qs_footer_impl.xml87
-rw-r--r--packages/SystemUI/res/layout/quick_qs_status_icons.xml2
-rw-r--r--packages/SystemUI/res/layout/split_shade_header.xml2
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml14
-rw-r--r--packages/SystemUI/res/layout/system_icons.xml2
-rw-r--r--packages/SystemUI/res/layout/udfps_keyguard_view.xml4
-rw-r--r--packages/SystemUI/res/raw/udfps_aod_fp.json16
-rw-r--r--packages/SystemUI/res/raw/udfps_lockscreen_fp.json2
-rw-r--r--packages/SystemUI/res/values-af/strings.xml3
-rw-r--r--packages/SystemUI/res/values-am/strings.xml3
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml3
-rw-r--r--packages/SystemUI/res/values-as/strings.xml3
-rw-r--r--packages/SystemUI/res/values-az/strings.xml3
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml3
-rw-r--r--packages/SystemUI/res/values-be/strings.xml3
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml3
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml3
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml5
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml5
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml3
-rw-r--r--packages/SystemUI/res/values-da/strings.xml3
-rw-r--r--packages/SystemUI/res/values-de/strings.xml5
-rw-r--r--packages/SystemUI/res/values-el/strings.xml3
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml3
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml3
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml3
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml3
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml3
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml3
-rw-r--r--packages/SystemUI/res/values-es/strings.xml3
-rw-r--r--packages/SystemUI/res/values-et/strings.xml3
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml3
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml3
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml3
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml3
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml3
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml3
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml3
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml3
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml3
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml3
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml3
-rw-r--r--packages/SystemUI/res/values-in/strings.xml3
-rw-r--r--packages/SystemUI/res/values-is/strings.xml3
-rw-r--r--packages/SystemUI/res/values-it/strings.xml3
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml3
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml5
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml3
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml3
-rw-r--r--packages/SystemUI/res/values-km/strings.xml3
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml3
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml3
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml7
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml3
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml3
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml3
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml3
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml3
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml3
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml3
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml3
-rw-r--r--packages/SystemUI/res/values-my/strings.xml3
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml3
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml3
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml3
-rw-r--r--packages/SystemUI/res/values-or/strings.xml3
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml3
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml3
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml3
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml3
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml3
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml3
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml3
-rw-r--r--packages/SystemUI/res/values-si/strings.xml3
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml3
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml3
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml3
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml3
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml3
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml3
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml3
-rw-r--r--packages/SystemUI/res/values-te/strings.xml15
-rw-r--r--packages/SystemUI/res/values-th/strings.xml3
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml3
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml3
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml3
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml3
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml3
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml3
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml3
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml3
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml3
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml3
-rw-r--r--packages/SystemUI/res/values/config.xml5
-rw-r--r--packages/SystemUI/res/values/dimens.xml5
-rw-r--r--packages/SystemUI/res/values/strings.xml2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java3
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java56
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java12
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java24
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java5
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java21
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java10
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java16
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java82
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java8
-rw-r--r--packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java102
-rw-r--r--packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java (renamed from packages/SystemUI/src/com/android/systemui/BatteryMeterView.java)81
-rw-r--r--packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java114
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java85
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java)96
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java79
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooter.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsController.kt167
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsView.kt159
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java124
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java188
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java54
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSlider.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java119
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt95
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java171
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java58
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java66
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java878
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java690
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java50
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java239
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt67
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/wrapper/UtilWrapperModule.kt (renamed from tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt)24
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallet/ui/WalletCardCarousel.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java98
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java51
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsTest.java111
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/flags/FlagsTest.java119
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterActionsControllerTest.kt91
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java91
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelSwitchToParentTest.kt162
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java114
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java97
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt60
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt54
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java170
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java81
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java239
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java113
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java65
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java4
-rw-r--r--services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java2
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java26
-rw-r--r--services/core/java/com/android/server/SensorPrivacyService.java59
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java4
-rw-r--r--services/core/java/com/android/server/VpnManagerService.java30
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java164
-rw-r--r--services/core/java/com/android/server/am/CachedAppOptimizer.java13
-rw-r--r--services/core/java/com/android/server/am/ConnectionRecord.java19
-rw-r--r--services/core/java/com/android/server/am/ContentProviderConnection.java19
-rw-r--r--services/core/java/com/android/server/am/ContentProviderRecord.java15
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java6
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java33
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java18
-rw-r--r--services/core/java/com/android/server/audio/AudioSystemAdapter.java8
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java7
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java56
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java123
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java26
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java23
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java10
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java10
-rw-r--r--services/core/java/com/android/server/camera/CameraServiceProxy.java173
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java20
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerShellCommand.java16
-rw-r--r--services/core/java/com/android/server/display/DisplayModeDirector.java91
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java2
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java74
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java20
-rw-r--r--services/core/java/com/android/server/pm/AppsFilter.java30
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java142
-rw-r--r--services/core/java/com/android/server/pm/PackageSettingBase.java48
-rw-r--r--services/core/java/com/android/server/power/hint/HintManagerService.java6
-rw-r--r--services/core/java/com/android/server/vibrator/VibrationThread.java30
-rw-r--r--services/core/java/com/android/server/wm/ActivityClientController.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java19
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java352
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java30
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java18
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java28
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java3
-rw-r--r--services/core/java/com/android/server/wm/BlurController.java10
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java63
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java33
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java8
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java7
-rw-r--r--services/core/java/com/android/server/wm/InsetsStateController.java2
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java8
-rw-r--r--services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java2
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java8
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java20
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java24
-rw-r--r--services/core/java/com/android/server/wm/StartingData.java6
-rw-r--r--services/core/java/com/android/server/wm/Task.java188
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java210
-rw-r--r--services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java15
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java275
-rw-r--r--services/core/java/com/android/server/wm/Transition.java46
-rw-r--r--services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java2
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java41
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java23
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java24
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java19
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java27
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java9
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/OwnerShellData.java98
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/Owners.java28
-rw-r--r--services/java/com/android/server/SystemServer.java3
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java38
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/devicepolicy/OwnerShellDataTest.java129
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java179
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java48
-rw-r--r--services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java2
-rw-r--r--services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java67
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java41
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java88
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java20
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java13
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java60
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskTests.java11
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java15
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java19
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java16
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java39
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java43
-rw-r--r--telephony/OWNERS7
-rw-r--r--telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java4
-rw-r--r--telephony/java/android/telephony/ims/stub/SipTransportImplBase.java46
-rw-r--r--tests/FlickerTests/Android.bp22
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt181
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt11
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt10
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt61
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt5
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt73
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt86
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt39
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt48
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt100
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt29
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt89
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt102
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt22
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt24
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt56
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt10
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt53
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt63
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt73
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml1
-rw-r--r--tools/aapt2/SdkConstants.cpp2
579 files changed, 13186 insertions, 5474 deletions
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 8e1f263ebf03..76f873185267 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -215,6 +215,14 @@ public class ActivityOptions {
"android.activity.launchRootTaskToken";
/**
+ * The {@link com.android.server.wm.TaskFragment} token the activity should be launched into.
+ * @see #setLaunchTaskFragmentToken(IBinder)
+ * @hide
+ */
+ public static final String KEY_LAUNCH_TASK_FRAGMENT_TOKEN =
+ "android.activity.launchTaskFragmentToken";
+
+ /**
* The windowing mode the activity should be launched into.
* @hide
*/
@@ -396,6 +404,7 @@ public class ActivityOptions {
private int mCallerDisplayId = INVALID_DISPLAY;
private WindowContainerToken mLaunchTaskDisplayArea;
private WindowContainerToken mLaunchRootTask;
+ private IBinder mLaunchTaskFragmentToken;
@WindowConfiguration.WindowingMode
private int mLaunchWindowingMode = WINDOWING_MODE_UNDEFINED;
@WindowConfiguration.ActivityType
@@ -1138,6 +1147,7 @@ public class ActivityOptions {
mCallerDisplayId = opts.getInt(KEY_CALLER_DISPLAY_ID, INVALID_DISPLAY);
mLaunchTaskDisplayArea = opts.getParcelable(KEY_LAUNCH_TASK_DISPLAY_AREA_TOKEN);
mLaunchRootTask = opts.getParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN);
+ mLaunchTaskFragmentToken = opts.getBinder(KEY_LAUNCH_TASK_FRAGMENT_TOKEN);
mLaunchWindowingMode = opts.getInt(KEY_LAUNCH_WINDOWING_MODE, WINDOWING_MODE_UNDEFINED);
mLaunchActivityType = opts.getInt(KEY_LAUNCH_ACTIVITY_TYPE, ACTIVITY_TYPE_UNDEFINED);
mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
@@ -1473,6 +1483,17 @@ public class ActivityOptions {
}
/** @hide */
+ public IBinder getLaunchTaskFragmentToken() {
+ return mLaunchTaskFragmentToken;
+ }
+
+ /** @hide */
+ public ActivityOptions setLaunchTaskFragmentToken(IBinder taskFragmentToken) {
+ mLaunchTaskFragmentToken = taskFragmentToken;
+ return this;
+ }
+
+ /** @hide */
public int getLaunchWindowingMode() {
return mLaunchWindowingMode;
}
@@ -1882,6 +1903,9 @@ public class ActivityOptions {
if (mLaunchRootTask != null) {
b.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, mLaunchRootTask);
}
+ if (mLaunchTaskFragmentToken != null) {
+ b.putBinder(KEY_LAUNCH_TASK_FRAGMENT_TOKEN, mLaunchTaskFragmentToken);
+ }
if (mLaunchWindowingMode != WINDOWING_MODE_UNDEFINED) {
b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode);
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 49836773fb82..ae812ece4c98 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -530,6 +530,9 @@ public final class ActivityThread extends ClientTransactionHandler
// A reusable token for other purposes, e.g. content capture, translation. It shouldn't be
// used without security checks
public IBinder shareableActivityToken;
+ // The token of the initial TaskFragment that embedded this activity. Do not rely on it
+ // after creation because the activity could be reparented.
+ @Nullable public IBinder mInitialTaskFragmentToken;
int ident;
@UnsupportedAppUsage
Intent intent;
@@ -623,7 +626,8 @@ public final class ActivityThread extends ClientTransactionHandler
List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client,
IBinder assistToken, FixedRotationAdjustments fixedRotationAdjustments,
- IBinder shareableActivityToken, boolean launchedFromBubble) {
+ IBinder shareableActivityToken, boolean launchedFromBubble,
+ IBinder initialTaskFragmentToken) {
this.token = token;
this.assistToken = assistToken;
this.shareableActivityToken = shareableActivityToken;
@@ -645,6 +649,7 @@ public final class ActivityThread extends ClientTransactionHandler
mActivityOptions = activityOptions;
mPendingFixedRotationAdjustments = fixedRotationAdjustments;
mLaunchedFromBubble = launchedFromBubble;
+ mInitialTaskFragmentToken = initialTaskFragmentToken;
init();
}
@@ -5662,8 +5667,8 @@ public final class ActivityThread extends ClientTransactionHandler
*/
private void scheduleRelaunchActivityIfPossible(@NonNull ActivityClientRecord r,
boolean preserveWindow) {
- if (r.activity.mFinished || r.token instanceof Binder) {
- // Do not schedule relaunch if the activity is finishing or not a local object (e.g.
+ if ((r.activity != null && r.activity.mFinished) || r.token instanceof Binder) {
+ // Do not schedule relaunch if the activity is finishing or is a local object (e.g.
// created by ActivtiyGroup that server side doesn't recognize it).
return;
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 4ddb546a351e..d932a29beca6 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -2849,14 +2849,14 @@ public class AppOpsManager {
private static final ThreadLocal<Integer> sBinderThreadCallingUid = new ThreadLocal<>();
/**
- * If a thread is currently executing a two-way binder transaction, this stores the
- * ops that were noted blaming any app (the caller, the caller of the caller, etc).
+ * If a thread is currently executing a two-way binder transaction, this stores the op-codes of
+ * the app-ops that were noted during this transaction.
*
* @see #getNotedOpCollectionMode
* @see #collectNotedOpSync
*/
- private static final ThreadLocal<ArrayMap<String, ArrayMap<String, long[]>>>
- sAppOpsNotedInThisBinderTransaction = new ThreadLocal<>();
+ private static final ThreadLocal<ArrayMap<String, long[]>> sAppOpsNotedInThisBinderTransaction =
+ new ThreadLocal<>();
/** Whether noting for an appop should be collected */
private static final @ShouldCollectNoteOp byte[] sAppOpsToNote = new byte[_NUM_OP];
@@ -7205,6 +7205,34 @@ public class AppOpsManager {
* @hide
*/
public interface OnOpStartedListener {
+
+ /**
+ * Represents a start operation that was unsuccessful
+ * @hide
+ */
+ public int START_TYPE_FAILED = 0;
+
+ /**
+ * Represents a successful start operation
+ * @hide
+ */
+ public int START_TYPE_STARTED = 1;
+
+ /**
+ * Represents an operation where a restricted operation became unrestricted, and resumed.
+ * @hide
+ */
+ public int START_TYPE_RESUMED = 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "TYPE_" }, value = {
+ START_TYPE_FAILED,
+ START_TYPE_STARTED,
+ START_TYPE_RESUMED
+ })
+ public @interface StartedType {}
+
/**
* Called when an op was started.
*
@@ -7213,11 +7241,35 @@ public class AppOpsManager {
* @param uid The UID performing the operation.
* @param packageName The package performing the operation.
* @param attributionTag The attribution tag performing the operation.
- * @param flags The flags of this op
+ * @param flags The flags of this op.
* @param result The result of the start.
*/
void onOpStarted(int op, int uid, String packageName, String attributionTag,
@OpFlags int flags, @Mode int result);
+
+ /**
+ * Called when an op was started.
+ *
+ * Note: This is only for op starts. It is not called when an op is noted or stopped.
+ * By default, unless this method is overridden, no code will be executed for resume
+ * events.
+ * @param op The op code.
+ * @param uid The UID performing the operation.
+ * @param packageName The package performing the operation.
+ * @param attributionTag The attribution tag performing the operation.
+ * @param flags The flags of this op.
+ * @param result The result of the start.
+ * @param startType The start type of this start event. Either failed, resumed, or started.
+ * @param attributionFlags The location of this started op in an attribution chain.
+ * @param attributionChainId The ID of the attribution chain of this op, if it is in one.
+ */
+ default void onOpStarted(int op, int uid, String packageName, String attributionTag,
+ @OpFlags int flags, @Mode int result, @StartedType int startType,
+ @AttributionFlags int attributionFlags, int attributionChainId) {
+ if (startType != START_TYPE_RESUMED) {
+ onOpStarted(op, uid, packageName, attributionTag, flags, result);
+ }
+ }
}
AppOpsManager(Context context, IAppOpsService service) {
@@ -7858,8 +7910,10 @@ public class AppOpsManager {
cb = new IAppOpsStartedCallback.Stub() {
@Override
public void opStarted(int op, int uid, String packageName, String attributionTag,
- int flags, int mode) {
- callback.onOpStarted(op, uid, packageName, attributionTag, flags, mode);
+ int flags, int mode, int startType, int attributionFlags,
+ int attributionChainId) {
+ callback.onOpStarted(op, uid, packageName, attributionTag, flags, mode,
+ startType, attributionFlags, attributionChainId);
}
};
mStartedWatchers.put(callback, cb);
@@ -9052,6 +9106,66 @@ public class AppOpsManager {
}
/**
+ * State of a temporarily paused noted app-ops collection.
+ *
+ * @see #pauseNotedAppOpsCollection()
+ *
+ * @hide
+ */
+ public static class PausedNotedAppOpsCollection {
+ final int mUid;
+ final @Nullable ArrayMap<String, long[]> mCollectedNotedAppOps;
+
+ PausedNotedAppOpsCollection(int uid, @Nullable ArrayMap<String,
+ long[]> collectedNotedAppOps) {
+ mUid = uid;
+ mCollectedNotedAppOps = collectedNotedAppOps;
+ }
+ }
+
+ /**
+ * Temporarily suspend collection of noted app-ops when binder-thread calls into the other
+ * process. During such a call there might be call-backs coming back on the same thread which
+ * should not be accounted to the current collection.
+ *
+ * @return a state needed to resume the collection
+ *
+ * @hide
+ */
+ public static @Nullable PausedNotedAppOpsCollection pauseNotedAppOpsCollection() {
+ Integer previousUid = sBinderThreadCallingUid.get();
+ if (previousUid != null) {
+ ArrayMap<String, long[]> previousCollectedNotedAppOps =
+ sAppOpsNotedInThisBinderTransaction.get();
+
+ sBinderThreadCallingUid.remove();
+ sAppOpsNotedInThisBinderTransaction.remove();
+
+ return new PausedNotedAppOpsCollection(previousUid, previousCollectedNotedAppOps);
+ }
+
+ return null;
+ }
+
+ /**
+ * Resume a collection paused via {@link #pauseNotedAppOpsCollection}.
+ *
+ * @param prevCollection The state of the previous collection
+ *
+ * @hide
+ */
+ public static void resumeNotedAppOpsCollection(
+ @Nullable PausedNotedAppOpsCollection prevCollection) {
+ if (prevCollection != null) {
+ sBinderThreadCallingUid.set(prevCollection.mUid);
+
+ if (prevCollection.mCollectedNotedAppOps != null) {
+ sAppOpsNotedInThisBinderTransaction.set(prevCollection.mCollectedNotedAppOps);
+ }
+ }
+ }
+
+ /**
* Finish collection of noted appops on this thread.
*
* <p>Called at the end of a two way binder transaction.
@@ -9091,47 +9205,26 @@ public class AppOpsManager {
*/
@TestApi
public static void collectNotedOpSync(@NonNull SyncNotedAppOp syncOp) {
- collectNotedOpSync(sOpStrToOp.get(syncOp.getOp()), syncOp.getAttributionTag(),
- syncOp.getPackageName());
- }
-
- /**
- * Collect a noted op when inside of a two-way binder call.
- *
- * <p> Delivered to caller via {@link #prefixParcelWithAppOpsIfNeeded}
- *
- * @param code the op code to note for
- * @param attributionTag the attribution tag to note for
- * @param packageName the package to note for
- */
- private static void collectNotedOpSync(int code, @Nullable String attributionTag,
- @NonNull String packageName) {
// If this is inside of a two-way binder call:
// We are inside of a two-way binder call. Delivered to caller via
// {@link #prefixParcelWithAppOpsIfNeeded}
- ArrayMap<String, ArrayMap<String, long[]>> appOpsNoted =
- sAppOpsNotedInThisBinderTransaction.get();
+ int op = sOpStrToOp.get(syncOp.getOp());
+ ArrayMap<String, long[]> appOpsNoted = sAppOpsNotedInThisBinderTransaction.get();
if (appOpsNoted == null) {
appOpsNoted = new ArrayMap<>(1);
sAppOpsNotedInThisBinderTransaction.set(appOpsNoted);
}
- ArrayMap<String, long[]> packageAppOpsNotedForAttribution = appOpsNoted.get(packageName);
- if (packageAppOpsNotedForAttribution == null) {
- packageAppOpsNotedForAttribution = new ArrayMap<>(1);
- appOpsNoted.put(packageName, packageAppOpsNotedForAttribution);
- }
-
- long[] appOpsNotedForAttribution = packageAppOpsNotedForAttribution.get(attributionTag);
+ long[] appOpsNotedForAttribution = appOpsNoted.get(syncOp.getAttributionTag());
if (appOpsNotedForAttribution == null) {
appOpsNotedForAttribution = new long[2];
- packageAppOpsNotedForAttribution.put(attributionTag, appOpsNotedForAttribution);
+ appOpsNoted.put(syncOp.getAttributionTag(), appOpsNotedForAttribution);
}
- if (code < 64) {
- appOpsNotedForAttribution[0] |= 1L << code;
+ if (op < 64) {
+ appOpsNotedForAttribution[0] |= 1L << op;
} else {
- appOpsNotedForAttribution[1] |= 1L << (code - 64);
+ appOpsNotedForAttribution[1] |= 1L << (op - 64);
}
}
@@ -9185,7 +9278,9 @@ public class AppOpsManager {
}
}
- if (isListeningForOpNotedInBinderTransaction()) {
+ Integer binderUid = sBinderThreadCallingUid.get();
+
+ if (binderUid != null && binderUid == uid) {
return COLLECT_SYNC;
} else {
return COLLECT_ASYNC;
@@ -9204,32 +9299,20 @@ public class AppOpsManager {
*/
// TODO (b/186872903) Refactor how sync noted ops are propagated.
public static void prefixParcelWithAppOpsIfNeeded(@NonNull Parcel p) {
- if (!isListeningForOpNotedInBinderTransaction()) {
- return;
- }
- final ArrayMap<String, ArrayMap<String, long[]>> notedAppOps =
- sAppOpsNotedInThisBinderTransaction.get();
+ ArrayMap<String, long[]> notedAppOps = sAppOpsNotedInThisBinderTransaction.get();
if (notedAppOps == null) {
return;
}
p.writeInt(Parcel.EX_HAS_NOTED_APPOPS_REPLY_HEADER);
- final int packageCount = notedAppOps.size();
- p.writeInt(packageCount);
+ int numAttributionWithNotesAppOps = notedAppOps.size();
+ p.writeInt(numAttributionWithNotesAppOps);
- for (int i = 0; i < packageCount; i++) {
+ for (int i = 0; i < numAttributionWithNotesAppOps; i++) {
p.writeString(notedAppOps.keyAt(i));
-
- final ArrayMap<String, long[]> notedTagAppOps = notedAppOps.valueAt(i);
- final int tagCount = notedTagAppOps.size();
- p.writeInt(tagCount);
-
- for (int j = 0; j < tagCount; j++) {
- p.writeString(notedTagAppOps.keyAt(j));
- p.writeLong(notedTagAppOps.valueAt(j)[0]);
- p.writeLong(notedTagAppOps.valueAt(j)[1]);
- }
+ p.writeLong(notedAppOps.valueAt(i)[0]);
+ p.writeLong(notedAppOps.valueAt(i)[1]);
}
}
@@ -9244,55 +9327,37 @@ public class AppOpsManager {
* @hide
*/
public static void readAndLogNotedAppops(@NonNull Parcel p) {
- final int packageCount = p.readInt();
- if (packageCount <= 0) {
- return;
- }
+ int numAttributionsWithNotedAppOps = p.readInt();
- final String myPackageName = ActivityThread.currentPackageName();
+ for (int i = 0; i < numAttributionsWithNotedAppOps; i++) {
+ String attributionTag = p.readString();
+ long[] rawNotedAppOps = new long[2];
+ rawNotedAppOps[0] = p.readLong();
+ rawNotedAppOps[1] = p.readLong();
- synchronized (sLock) {
- for (int i = 0; i < packageCount; i++) {
- final String packageName = p.readString();
-
- final int tagCount = p.readInt();
- for (int j = 0; j < tagCount; j++) {
- final String attributionTag = p.readString();
- final long[] rawNotedAppOps = new long[2];
- rawNotedAppOps[0] = p.readLong();
- rawNotedAppOps[1] = p.readLong();
+ if (rawNotedAppOps[0] != 0 || rawNotedAppOps[1] != 0) {
+ BitSet notedAppOps = BitSet.valueOf(rawNotedAppOps);
- if (rawNotedAppOps[0] == 0 && rawNotedAppOps[1] == 0) {
- continue;
- }
-
- final BitSet notedAppOps = BitSet.valueOf(rawNotedAppOps);
+ synchronized (sLock) {
for (int code = notedAppOps.nextSetBit(0); code != -1;
code = notedAppOps.nextSetBit(code + 1)) {
- if (Objects.equals(myPackageName, packageName)) {
- if (sOnOpNotedCallback != null) {
- sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code,
- attributionTag, packageName));
- } else {
- String message = getFormattedStackTrace();
- sUnforwardedOps.add(new AsyncNotedAppOp(code, Process.myUid(),
- attributionTag, message, System.currentTimeMillis()));
- if (sUnforwardedOps.size() > MAX_UNFORWARDED_OPS) {
- sUnforwardedOps.remove(0);
- }
+ if (sOnOpNotedCallback != null) {
+ sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code, attributionTag));
+ } else {
+ String message = getFormattedStackTrace();
+ sUnforwardedOps.add(
+ new AsyncNotedAppOp(code, Process.myUid(), attributionTag,
+ message, System.currentTimeMillis()));
+ if (sUnforwardedOps.size() > MAX_UNFORWARDED_OPS) {
+ sUnforwardedOps.remove(0);
}
- } else if (isListeningForOpNotedInBinderTransaction()) {
- collectNotedOpSync(code, attributionTag, packageName);
- }
- }
- for (int code = notedAppOps.nextSetBit(0); code != -1;
- code = notedAppOps.nextSetBit(code + 1)) {
- if (Objects.equals(myPackageName, packageName)) {
- sMessageCollector.onNoted(new SyncNotedAppOp(code,
- attributionTag, packageName));
}
}
}
+ for (int code = notedAppOps.nextSetBit(0); code != -1;
+ code = notedAppOps.nextSetBit(code + 1)) {
+ sMessageCollector.onNoted(new SyncNotedAppOp(code, attributionTag));
+ }
}
}
}
@@ -9398,15 +9463,7 @@ public class AppOpsManager {
* @hide
*/
public static boolean isListeningForOpNoted() {
- return sOnOpNotedCallback != null || isListeningForOpNotedInBinderTransaction()
- || isCollectingStackTraces();
- }
-
- /**
- * @return whether we are in a binder transaction and collecting appops.
- */
- private static boolean isListeningForOpNotedInBinderTransaction() {
- return sBinderThreadCallingUid.get() != null;
+ return sOnOpNotedCallback != null || isCollectingStackTraces();
}
/**
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index b2184fe65887..45db0f6ff3e2 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -743,6 +743,17 @@ public class Instrumentation {
}
/**
+ * This overload is used for notifying the {@link android.window.TaskFragmentOrganizer}
+ * implementation internally about started activities.
+ *
+ * @see #onStartActivity(Intent)
+ * @hide
+ */
+ public ActivityResult onStartActivity(Context who, Intent intent, Bundle options) {
+ return onStartActivity(intent);
+ }
+
+ /**
* Used for intercepting any started activity.
*
* <p> A non-null return value here will be considered a hit for this monitor.
@@ -1722,7 +1733,10 @@ public class Instrumentation {
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
- result = am.onStartActivity(intent);
+ if (options == null) {
+ options = ActivityOptions.makeBasic().toBundle();
+ }
+ result = am.onStartActivity(who, intent, options);
}
if (result != null) {
am.mHits++;
@@ -1790,7 +1804,10 @@ public class Instrumentation {
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
- result = am.onStartActivity(intents[0]);
+ if (options == null) {
+ options = ActivityOptions.makeBasic().toBundle();
+ }
+ result = am.onStartActivity(who, intents[0], options);
}
if (result != null) {
am.mHits++;
@@ -1861,7 +1878,10 @@ public class Instrumentation {
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
- result = am.onStartActivity(intent);
+ if (options == null) {
+ options = ActivityOptions.makeBasic().toBundle();
+ }
+ result = am.onStartActivity(who, intent, options);
}
if (result != null) {
am.mHits++;
@@ -1928,7 +1948,10 @@ public class Instrumentation {
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
- result = am.onStartActivity(intent);
+ if (options == null) {
+ options = ActivityOptions.makeBasic().toBundle();
+ }
+ result = am.onStartActivity(who, intent, options);
}
if (result != null) {
am.mHits++;
@@ -1974,7 +1997,10 @@ public class Instrumentation {
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
- result = am.onStartActivity(intent);
+ if (options == null) {
+ options = ActivityOptions.makeBasic().toBundle();
+ }
+ result = am.onStartActivity(who, intent, options);
}
if (result != null) {
am.mHits++;
@@ -2021,7 +2047,10 @@ public class Instrumentation {
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
- result = am.onStartActivity(intent);
+ if (options == null) {
+ options = ActivityOptions.makeBasic().toBundle();
+ }
+ result = am.onStartActivity(who, intent, options);
}
if (result != null) {
am.mHits++;
diff --git a/core/java/android/app/SyncNotedAppOp.java b/core/java/android/app/SyncNotedAppOp.java
index 32d889e81cb0..7c0c08a7fc35 100644
--- a/core/java/android/app/SyncNotedAppOp.java
+++ b/core/java/android/app/SyncNotedAppOp.java
@@ -21,7 +21,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.os.Parcelable;
-import android.os.Process;
import com.android.internal.annotations.Immutable;
import com.android.internal.util.DataClass;
@@ -29,6 +28,8 @@ import com.android.internal.util.DataClass;
/**
* Description of an app-op that was noted for the current process.
*
+ * Note: package name is currently unused in the system.
+ *
* <p>This is either delivered after a
* {@link AppOpsManager.OnOpNotedCallback#onNoted(SyncNotedAppOp) two way binder call} or
* when the app
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 8d332ab1d58b..edfbf1a29f5a 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -221,6 +221,20 @@ public class WallpaperManager {
public static final String COMMAND_REAPPLY = "android.wallpaper.reapply";
/**
+ * Command for {@link #sendWallpaperCommand}: reported when the live wallpaper needs to be
+ * frozen.
+ * @hide
+ */
+ public static final String COMMAND_FREEZE = "android.wallpaper.freeze";
+
+ /**
+ * Command for {@link #sendWallpaperCommand}: reported when the live wallapper doesn't need
+ * to be frozen anymore.
+ * @hide
+ */
+ public static final String COMMAND_UNFREEZE = "android.wallpaper.unfreeze";
+
+ /**
* Extra passed back from setWallpaper() giving the new wallpaper's assigned ID.
* @hide
*/
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index 1b03f2f328e5..bf9a9b060b6b 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -116,7 +116,7 @@ public class FullBackup {
ConfigSection.CLOUD_BACKUP,
ConfigSection.DEVICE_TRANSFER
})
- private @interface ConfigSection {
+ @interface ConfigSection {
String CLOUD_BACKUP = "cloud-backup";
String DEVICE_TRANSFER = "device-transfer";
}
@@ -528,7 +528,8 @@ public class FullBackup {
return mExcludes;
}
- private synchronized int getRequiredTransportFlags()
+ @VisibleForTesting
+ public synchronized int getRequiredTransportFlags()
throws IOException, XmlPullParserException {
if (mRequiredTransportFlags == null) {
maybeParseBackupSchemeLocked();
@@ -587,11 +588,13 @@ public class FullBackup {
if (mDataExtractionRules != 0) {
// New config is present. Use it if it has configuration for this operation
// type.
+ boolean isSectionPresent;
try (XmlResourceParser parser = getParserForResource(mDataExtractionRules)) {
- parseNewBackupSchemeFromXmlLocked(parser, configSection, mExcludes, mIncludes);
+ isSectionPresent = parseNewBackupSchemeFromXmlLocked(parser, configSection,
+ mExcludes, mIncludes);
}
- if (!mExcludes.isEmpty() || !mIncludes.isEmpty()) {
- // Found configuration in the new config, we will use it.
+ if (isSectionPresent) {
+ // Found the relevant section in the new config, we will use it.
mIsUsingNewScheme = true;
return;
}
@@ -630,24 +633,31 @@ public class FullBackup {
.getXml(resourceId);
}
- private void parseNewBackupSchemeFromXmlLocked(XmlPullParser parser,
+ @VisibleForTesting
+ public boolean parseNewBackupSchemeFromXmlLocked(XmlPullParser parser,
@ConfigSection String configSection,
Set<PathWithRequiredFlags> excludes,
Map<String, Set<PathWithRequiredFlags>> includes)
throws IOException, XmlPullParserException {
verifyTopLevelTag(parser, "data-extraction-rules");
+ boolean isSectionPresent = false;
+
int event;
while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
if (event != XmlPullParser.START_TAG || !configSection.equals(parser.getName())) {
continue;
}
+ isSectionPresent = true;
+
parseRequiredTransportFlags(parser, configSection);
parseRules(parser, excludes, includes, Optional.of(0), configSection);
}
logParsingResults(excludes, includes);
+
+ return isSectionPresent;
}
private void parseRequiredTransportFlags(XmlPullParser parser,
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index 34e4fcdb9140..37cbccb89735 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -73,6 +73,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
private IBinder mAssistToken;
private IBinder mShareableActivityToken;
private boolean mLaunchedFromBubble;
+ private IBinder mTaskFragmentToken;
/**
* It is only non-null if the process is the first time to launch activity. It is only an
* optimization for quick look up of the interface so the field is ignored for comparison.
@@ -86,7 +87,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
client, mAssistToken, mFixedRotationAdjustments, mShareableActivityToken,
- mLaunchedFromBubble);
+ mLaunchedFromBubble, mTaskFragmentToken);
client.addLaunchingActivity(token, r);
client.updateProcessState(mProcState, false);
client.updatePendingConfiguration(mCurConfig);
@@ -124,7 +125,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken,
IActivityClientController activityClientController,
FixedRotationAdjustments fixedRotationAdjustments, IBinder shareableActivityToken,
- boolean launchedFromBubble) {
+ boolean launchedFromBubble, IBinder taskFragmentToken) {
LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class);
if (instance == null) {
instance = new LaunchActivityItem();
@@ -133,7 +134,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
voiceInteractor, procState, state, persistentState, pendingResults,
pendingNewIntents, activityOptions, isForward, profilerInfo, assistToken,
activityClientController, fixedRotationAdjustments, shareableActivityToken,
- launchedFromBubble);
+ launchedFromBubble, taskFragmentToken);
return instance;
}
@@ -141,7 +142,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
@Override
public void recycle() {
setValues(this, null, 0, null, null, null, null, null, null, 0, null, null, null, null,
- null, false, null, null, null, null, null, false);
+ null, false, null, null, null, null, null, false, null);
ObjectPool.recycle(this);
}
@@ -172,6 +173,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
dest.writeTypedObject(mFixedRotationAdjustments, flags);
dest.writeStrongBinder(mShareableActivityToken);
dest.writeBoolean(mLaunchedFromBubble);
+ dest.writeStrongBinder(mTaskFragmentToken);
}
/** Read from Parcel. */
@@ -190,7 +192,8 @@ public class LaunchActivityItem extends ClientTransactionItem {
in.readStrongBinder(),
IActivityClientController.Stub.asInterface(in.readStrongBinder()),
in.readTypedObject(FixedRotationAdjustments.CREATOR), in.readStrongBinder(),
- in.readBoolean());
+ in.readBoolean(),
+ in.readStrongBinder());
}
public static final @NonNull Creator<LaunchActivityItem> CREATOR =
@@ -229,7 +232,8 @@ public class LaunchActivityItem extends ClientTransactionItem {
&& Objects.equals(mProfilerInfo, other.mProfilerInfo)
&& Objects.equals(mAssistToken, other.mAssistToken)
&& Objects.equals(mFixedRotationAdjustments, other.mFixedRotationAdjustments)
- && Objects.equals(mShareableActivityToken, other.mShareableActivityToken);
+ && Objects.equals(mShareableActivityToken, other.mShareableActivityToken)
+ && Objects.equals(mTaskFragmentToken, other.mTaskFragmentToken);
}
@Override
@@ -252,6 +256,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
result = 31 * result + Objects.hashCode(mAssistToken);
result = 31 * result + Objects.hashCode(mFixedRotationAdjustments);
result = 31 * result + Objects.hashCode(mShareableActivityToken);
+ result = 31 * result + Objects.hashCode(mTaskFragmentToken);
return result;
}
@@ -301,7 +306,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
ActivityOptions activityOptions, boolean isForward, ProfilerInfo profilerInfo,
IBinder assistToken, IActivityClientController activityClientController,
FixedRotationAdjustments fixedRotationAdjustments, IBinder shareableActivityToken,
- boolean launchedFromBubble) {
+ boolean launchedFromBubble, IBinder taskFragmentToken) {
instance.mIntent = intent;
instance.mIdent = ident;
instance.mInfo = info;
@@ -323,5 +328,6 @@ public class LaunchActivityItem extends ClientTransactionItem {
instance.mFixedRotationAdjustments = fixedRotationAdjustments;
instance.mShareableActivityToken = shareableActivityToken;
instance.mLaunchedFromBubble = launchedFromBubble;
+ instance.mTaskFragmentToken = taskFragmentToken;
}
}
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index cb3bf297670f..8ff018121ab0 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -168,6 +168,15 @@ public final class ScanFilter implements Parcelable {
dest.writeByteArray(mManufacturerDataMask);
}
}
+
+ // IRK
+ if (mDeviceAddress != null) {
+ dest.writeInt(mAddressType);
+ dest.writeInt(mIrk == null ? 0 : 1);
+ if (mIrk != null) {
+ dest.writeByteArray(mIrk);
+ }
+ }
}
/**
@@ -187,8 +196,10 @@ public final class ScanFilter implements Parcelable {
if (in.readInt() == 1) {
builder.setDeviceName(in.readString());
}
+ String address = null;
+ // If we have a non-null address
if (in.readInt() == 1) {
- builder.setDeviceAddress(in.readString());
+ address = in.readString();
}
if (in.readInt() == 1) {
ParcelUuid uuid = in.readParcelable(ParcelUuid.class.getClassLoader());
@@ -245,6 +256,17 @@ public final class ScanFilter implements Parcelable {
}
}
+ // IRK
+ if (address != null) {
+ final int addressType = in.readInt();
+ if (in.readInt() == 1) {
+ final byte[] irk = new byte[16];
+ in.readByteArray(irk);
+ builder.setDeviceAddress(address, addressType, irk);
+ } else {
+ builder.setDeviceAddress(address, addressType);
+ }
+ }
return builder.build();
}
};
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index a741f9649b4c..c714f507242e 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -745,9 +745,6 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
if (Binder.getCallingPid() == Process.myPid()) {
return PermissionChecker.PERMISSION_GRANTED;
}
- if (!attributionSource.checkCallingUid()) {
- return PermissionChecker.PERMISSION_HARD_DENIED;
- }
return PermissionChecker.checkPermissionForDataDeliveryFromDataSource(getContext(),
permission, -1, new AttributionSource(getContext().getAttributionSource(),
attributionSource), /*message*/ null);
diff --git a/core/java/android/hardware/ISensorPrivacyManager.aidl b/core/java/android/hardware/ISensorPrivacyManager.aidl
index d69a9e14b4bf..55711654231e 100644
--- a/core/java/android/hardware/ISensorPrivacyManager.aidl
+++ b/core/java/android/hardware/ISensorPrivacyManager.aidl
@@ -52,4 +52,6 @@ interface ISensorPrivacyManager {
void addUserGlobalIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
void removeUserGlobalIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
+
+ void showSensorUseDialog(int sensor);
} \ No newline at end of file
diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java
index 4526ab770bc6..3c524b2052f7 100644
--- a/core/java/android/hardware/SensorPrivacyManager.java
+++ b/core/java/android/hardware/SensorPrivacyManager.java
@@ -24,15 +24,16 @@ import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
-import android.app.ActivityManager;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.service.SensorPrivacyIndividualEnabledSensorProto;
import android.service.SensorPrivacyToggleSourceProto;
import android.util.ArrayMap;
+import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
@@ -48,6 +49,8 @@ import java.util.concurrent.Executor;
@SystemService(Context.SENSOR_PRIVACY_SERVICE)
public final class SensorPrivacyManager {
+ private static final String LOG_TAG = SensorPrivacyManager.class.getSimpleName();
+
/**
* Unique Id of this manager to identify to the service
* @hide
@@ -379,7 +382,7 @@ public final class SensorPrivacyManager {
@SystemApi
@RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
public boolean isSensorPrivacyEnabled(@Sensors.Sensor int sensor) {
- return isSensorPrivacyEnabled(sensor, getCurrentUserId());
+ return isSensorPrivacyEnabled(sensor, UserHandle.USER_CURRENT);
}
/**
@@ -410,7 +413,7 @@ public final class SensorPrivacyManager {
@RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY)
public void setSensorPrivacy(@Sources.Source int source, @Sensors.Sensor int sensor,
boolean enable) {
- setSensorPrivacy(source, sensor, enable, getCurrentUserId());
+ setSensorPrivacy(source, sensor, enable, UserHandle.USER_CURRENT);
}
/**
@@ -446,7 +449,7 @@ public final class SensorPrivacyManager {
@RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY)
public void setSensorPrivacyForProfileGroup(@Sources.Source int source,
@Sensors.Sensor int sensor, boolean enable) {
- setSensorPrivacyForProfileGroup(source , sensor, enable, getCurrentUserId());
+ setSensorPrivacyForProfileGroup(source , sensor, enable, UserHandle.USER_CURRENT);
}
/**
@@ -481,7 +484,7 @@ public final class SensorPrivacyManager {
@RequiresPermission(Manifest.permission.MANAGE_SENSOR_PRIVACY)
public void suppressSensorPrivacyReminders(int sensor,
boolean suppress) {
- suppressSensorPrivacyReminders(sensor, suppress, getCurrentUserId());
+ suppressSensorPrivacyReminders(sensor, suppress, UserHandle.USER_CURRENT);
}
/**
@@ -505,6 +508,25 @@ public final class SensorPrivacyManager {
}
/**
+ * If sensor privacy for the provided sensor is enabled then this call will show the user the
+ * dialog which is shown when an application attempts to use that sensor. If privacy isn't
+ * enabled then this does nothing.
+ *
+ * This call can only be made by the system uid.
+ *
+ * @throws SecurityException when called by someone other than system uid.
+ *
+ * @hide
+ */
+ public void showSensorUseDialog(int sensor) {
+ try {
+ mService.showSensorUseDialog(sensor);
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Received exception while trying to show sensor use dialog", e);
+ }
+ }
+
+ /**
* A class implementing this interface can register with the {@link
* android.hardware.SensorPrivacyManager} to receive notification when the all-sensor privacy
* state changes.
@@ -609,12 +631,4 @@ public final class SensorPrivacyManager {
}
}
- private int getCurrentUserId() {
- try {
- return ActivityManager.getService().getCurrentUserId();
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- return 0;
- }
}
diff --git a/core/java/android/hardware/camera2/MultiResolutionImageReader.java b/core/java/android/hardware/camera2/MultiResolutionImageReader.java
index 3af1b5b03d35..0dbf29de5253 100644
--- a/core/java/android/hardware/camera2/MultiResolutionImageReader.java
+++ b/core/java/android/hardware/camera2/MultiResolutionImageReader.java
@@ -91,7 +91,7 @@ public class MultiResolutionImageReader implements AutoCloseable {
* </p>
* <p>
* The {@code maxImages} parameter determines the maximum number of
- * {@link Image} objects that can be be acquired from each of the {@code ImageReader}
+ * {@link Image} objects that can be acquired from each of the {@code ImageReader}
* within the {@code MultiResolutionImageReader}. However, requesting more buffers will
* use up more memory, so it is important to use only the minimum number necessary. The
* application is strongly recommended to acquire no more than {@code maxImages} images
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index d5a35bc31e68..02245e49e611 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -446,16 +446,12 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
}
}
- @Override
- protected void finalize() throws Throwable {
- if (mHandlerThread != null) {
- mHandlerThread.quitSafely();
- }
- super.finalize();
- }
+ public void release(boolean skipCloseNotification) {
+ boolean notifyClose = false;
- public void release() {
synchronized (mInterfaceLock) {
+ mHandlerThread.quitSafely();
+
if (mSessionProcessor != null) {
try {
mSessionProcessor.deInitSession();
@@ -469,6 +465,7 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
if (mExtensionClientId >= 0) {
CameraExtensionCharacteristics.unregisterClient(mExtensionClientId);
if (mInitialized) {
+ notifyClose = true;
CameraExtensionCharacteristics.releaseSession();
}
}
@@ -482,6 +479,16 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
mClientRepeatingRequestSurface = null;
mClientCaptureSurface = null;
}
+
+ if (notifyClose && !skipCloseNotification) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallbacks.onClosed(
+ CameraAdvancedExtensionSessionImpl.this));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
private void notifyConfigurationFailure() {
@@ -491,7 +498,7 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
}
}
- release();
+ release(true /*skipCloseNotification*/);
final long ident = Binder.clearCallingIdentity();
try {
@@ -507,15 +514,7 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
android.hardware.camera2.CameraCaptureSession.StateCallback {
@Override
public void onClosed(@NonNull CameraCaptureSession session) {
- release();
-
- final long ident = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(() -> mCallbacks.onClosed(
- CameraAdvancedExtensionSessionImpl.this));
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
+ release(false /*skipCloseNotification*/);
}
@Override
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 0bf812e03984..fc728a22ed5a 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -697,12 +697,12 @@ public class CameraDeviceImpl extends CameraDevice
}
if (mCurrentExtensionSession != null) {
- mCurrentExtensionSession.release();
+ mCurrentExtensionSession.release(false /*skipCloseNotification*/);
mCurrentExtensionSession = null;
}
if (mCurrentAdvancedExtensionSession != null) {
- mCurrentAdvancedExtensionSession.release();
+ mCurrentAdvancedExtensionSession.release(false /*skipCloseNotification*/);
mCurrentAdvancedExtensionSession = null;
}
@@ -1352,12 +1352,12 @@ public class CameraDeviceImpl extends CameraDevice
}
if (mCurrentExtensionSession != null) {
- mCurrentExtensionSession.release();
+ mCurrentExtensionSession.release(true /*skipCloseNotification*/);
mCurrentExtensionSession = null;
}
if (mCurrentAdvancedExtensionSession != null) {
- mCurrentAdvancedExtensionSession.release();
+ mCurrentAdvancedExtensionSession.release(true /*skipCloseNotification*/);
mCurrentAdvancedExtensionSession = null;
}
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index 7d29a7d275cf..ecd24914c566 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -630,18 +630,13 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
new CameraExtensionUtils.HandlerExecutor(mHandler), requestHandler);
}
- @Override
- protected void finalize() throws Throwable {
- if (mHandlerThread != null) {
- mHandlerThread.quitSafely();
- }
- super.finalize();
- }
-
/** @hide */
- public void release() {
+ public void release(boolean skipCloseNotification) {
+ boolean notifyClose = false;
+
synchronized (mInterfaceLock) {
mInternalRepeatingRequestEnabled = false;
+ mHandlerThread.quitSafely();
try {
mPreviewExtender.onDeInit();
@@ -654,6 +649,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
if (mExtensionClientId >= 0) {
CameraExtensionCharacteristics.unregisterClient(mExtensionClientId);
if (mInitialized) {
+ notifyClose = true;
CameraExtensionCharacteristics.releaseSession();
}
}
@@ -704,6 +700,15 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
mCameraRepeatingSurface = mClientRepeatingRequestSurface = null;
mCameraBurstSurface = mClientCaptureSurface = null;
}
+
+ if (notifyClose && !skipCloseNotification) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallbacks.onClosed(CameraExtensionSessionImpl.this));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
private void notifyConfigurationFailure() {
@@ -713,7 +718,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
}
}
- release();
+ release(true /*skipCloseNotification*/);
final long ident = Binder.clearCallingIdentity();
try {
@@ -745,14 +750,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
android.hardware.camera2.CameraCaptureSession.StateCallback {
@Override
public void onClosed(@NonNull CameraCaptureSession session) {
- release();
-
- final long ident = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(() -> mCallbacks.onClosed(CameraExtensionSessionImpl.this));
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
+ release(false /*skipCloseNotification*/);
}
@Override
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
index 9acf9bf0c803..afefcbe80bf1 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
@@ -75,7 +75,7 @@ public final class CameraExtensionUtils {
ImageWriter writer = null;
Image img = null;
SurfaceInfo surfaceInfo = new SurfaceInfo();
- int nativeFormat = SurfaceUtils.getSurfaceFormat(s);
+ int nativeFormat = SurfaceUtils.detectSurfaceFormat(s);
int dataspace = SurfaceUtils.getSurfaceDataspace(s);
Size surfaceSize = SurfaceUtils.getSurfaceSize(s);
surfaceInfo.mFormat = nativeFormat;
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 8fd9a6abf7b6..196134b397cb 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -1720,21 +1720,21 @@ public class CameraMetadataNative implements Parcelable {
new SetCommand() {
@Override
public <T> void setValue(CameraMetadataNative metadata, T value) {
- metadata.setAWBRegions((MeteringRectangle[]) value);
+ metadata.setAWBRegions(value);
}
});
sSetCommandMap.put(CaptureRequest.CONTROL_AF_REGIONS.getNativeKey(),
new SetCommand() {
@Override
public <T> void setValue(CameraMetadataNative metadata, T value) {
- metadata.setAFRegions((MeteringRectangle[]) value);
+ metadata.setAFRegions(value);
}
});
sSetCommandMap.put(CaptureRequest.CONTROL_AE_REGIONS.getNativeKey(),
new SetCommand() {
@Override
public <T> void setValue(CameraMetadataNative metadata, T value) {
- metadata.setAERegions((MeteringRectangle[]) value);
+ metadata.setAERegions(value);
}
});
}
@@ -1815,30 +1815,33 @@ public class CameraMetadataNative implements Parcelable {
return true;
}
- private <T> boolean setAFRegions(MeteringRectangle[] afRegions) {
+ private <T> boolean setAFRegions(T afRegions) {
if (afRegions == null) {
return false;
}
setBase(CaptureRequest.CONTROL_AF_REGIONS_SET, true);
- setBase(CaptureRequest.CONTROL_AF_REGIONS, afRegions);
+ // The cast to CaptureRequest.Key is needed since java does not support template
+ // specialization and we need to route this method to
+ // setBase(CaptureRequest.Key<T> key, T value)
+ setBase((CaptureRequest.Key)CaptureRequest.CONTROL_AF_REGIONS, afRegions);
return true;
}
- private <T> boolean setAERegions(MeteringRectangle[] aeRegions) {
+ private <T> boolean setAERegions(T aeRegions) {
if (aeRegions == null) {
return false;
}
setBase(CaptureRequest.CONTROL_AE_REGIONS_SET, true);
- setBase(CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
+ setBase((CaptureRequest.Key)CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
return true;
}
- private <T> boolean setAWBRegions(MeteringRectangle[] awbRegions) {
+ private <T> boolean setAWBRegions(T awbRegions) {
if (awbRegions == null) {
return false;
}
setBase(CaptureRequest.CONTROL_AWB_REGIONS_SET, true);
- setBase(CaptureRequest.CONTROL_AWB_REGIONS, awbRegions);
+ setBase((CaptureRequest.Key)CaptureRequest.CONTROL_AWB_REGIONS, awbRegions);
return true;
}
diff --git a/core/java/android/hardware/camera2/params/InputConfiguration.java b/core/java/android/hardware/camera2/params/InputConfiguration.java
index 8dfc0a7b41ca..70c85a1fb26c 100644
--- a/core/java/android/hardware/camera2/params/InputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/InputConfiguration.java
@@ -42,7 +42,7 @@ public final class InputConfiguration {
private final boolean mIsMultiResolution;
/**
- * Create an input configration with the width, height, and user-defined format.
+ * Create an input configuration with the width, height, and user-defined format.
*
* <p>Images of a user-defined format are accessible by applications. Use
* {@link android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP}
@@ -64,7 +64,7 @@ public final class InputConfiguration {
}
/**
- * Create an input configration with the format and a list of multi-resolution input stream
+ * Create an input configuration with the format and a list of multi-resolution input stream
* info.
*
* <p>Use {@link
@@ -108,7 +108,7 @@ public final class InputConfiguration {
}
/**
- * Get the width of this input configration.
+ * Get the width of this input configuration.
*
* @return width of this input configuration.
*/
@@ -117,7 +117,7 @@ public final class InputConfiguration {
}
/**
- * Get the height of this input configration.
+ * Get the height of this input configuration.
*
* @return height of this input configuration.
*/
@@ -126,7 +126,7 @@ public final class InputConfiguration {
}
/**
- * Get the format of this input configration.
+ * Get the format of this input configuration.
*
* @return format of this input configuration.
*/
diff --git a/core/java/android/hardware/camera2/utils/SurfaceUtils.java b/core/java/android/hardware/camera2/utils/SurfaceUtils.java
index 57d8ded79e8e..fd1a33161740 100644
--- a/core/java/android/hardware/camera2/utils/SurfaceUtils.java
+++ b/core/java/android/hardware/camera2/utils/SurfaceUtils.java
@@ -160,6 +160,23 @@ public class SurfaceUtils {
}
/**
+ * Detect and retrieve the Surface format without any
+ * additional overrides.
+ *
+ * @param surface The surface to be queried for format.
+ * @return format of the surface.
+ *
+ * @throws IllegalArgumentException if the surface is already abandoned.
+ */
+ public static int detectSurfaceFormat(Surface surface) {
+ checkNotNull(surface);
+ int surfaceType = nativeDetectSurfaceType(surface);
+ if (surfaceType == BAD_VALUE) throw new IllegalArgumentException("Surface was abandoned");
+
+ return surfaceType;
+ }
+
+ /**
* Get the Surface dataspace.
*
* @param surface The surface to be queried for dataspace.
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index d44b016cb5d0..3d466a0bf007 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -560,6 +560,9 @@ public final class BinderProxy implements IBinder {
}
}
+ final AppOpsManager.PausedNotedAppOpsCollection prevCollection =
+ AppOpsManager.pauseNotedAppOpsCollection();
+
if ((flags & FLAG_ONEWAY) == 0 && AppOpsManager.isListeningForOpNoted()) {
flags |= FLAG_COLLECT_NOTED_APP_OPS;
}
@@ -567,6 +570,8 @@ public final class BinderProxy implements IBinder {
try {
return transactNative(code, data, reply, flags);
} finally {
+ AppOpsManager.resumeNotedAppOpsCollection(prevCollection);
+
if (transactListener != null) {
transactListener.onTransactEnded(session);
}
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index f3e0ce9cd19e..edfcb3d6f12a 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -1460,17 +1460,17 @@ public final class FileUtils {
/** {@hide} */
@VisibleForTesting
public static ParcelFileDescriptor convertToModernFd(FileDescriptor fd) {
- try {
- Context context = AppGlobals.getInitialApplication();
- if (UserHandle.getAppId(Process.myUid()) == getMediaProviderAppId(context)) {
- // Never convert modern fd for MediaProvider, because this requires
- // MediaStore#scanFile and can cause infinite loops when MediaProvider scans
- return null;
- }
- return MediaStore.getOriginalMediaFormatFileDescriptor(context,
- ParcelFileDescriptor.dup(fd));
+ Context context = AppGlobals.getInitialApplication();
+ if (UserHandle.getAppId(Process.myUid()) == getMediaProviderAppId(context)) {
+ // Never convert modern fd for MediaProvider, because this requires
+ // MediaStore#scanFile and can cause infinite loops when MediaProvider scans
+ return null;
+ }
+
+ try (ParcelFileDescriptor dupFd = ParcelFileDescriptor.dup(fd)) {
+ return MediaStore.getOriginalMediaFormatFileDescriptor(context, dupFd);
} catch (Exception e) {
- Log.d(TAG, "Failed to convert to modern format file descriptor", e);
+ // Ignore error
return null;
}
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 6bca336dae91..9f37c4877199 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -34,12 +34,9 @@ import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
-import java.io.BufferedReader;
import java.io.FileDescriptor;
-import java.io.FileReader;
import java.io.IOException;
import java.util.Map;
-import java.util.StringTokenizer;
import java.util.concurrent.TimeoutException;
/**
@@ -1472,43 +1469,4 @@ public class Process {
}
private static native int nativePidFdOpen(int pid, int flags) throws ErrnoException;
-
- /**
- * Checks if a process corresponding to a specific pid owns any file locks.
- * @param pid The process ID for which we want to know the existence of file locks.
- * @return true If the process holds any file locks, false otherwise.
- * @throws IOException if /proc/locks can't be accessed.
- *
- * @hide
- */
- public static boolean hasFileLocks(int pid) throws Exception {
- BufferedReader br = null;
-
- try {
- br = new BufferedReader(new FileReader("/proc/locks"));
- String line;
-
- while ((line = br.readLine()) != null) {
- StringTokenizer st = new StringTokenizer(line);
-
- for (int i = 0; i < 5 && st.hasMoreTokens(); i++) {
- String str = st.nextToken();
- try {
- if (i == 4 && Integer.parseInt(str) == pid) {
- return true;
- }
- } catch (NumberFormatException nfe) {
- throw new Exception("Exception parsing /proc/locks at \" "
- + line + " \", token #" + i);
- }
- }
- }
-
- return false;
- } finally {
- if (br != null) {
- br.close();
- }
- }
- }
}
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 03f94c549512..19f204b377c8 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -31,7 +31,9 @@ import static android.app.AppOpsManager.OPSTR_FINE_LOCATION;
import static android.app.AppOpsManager.OPSTR_PHONE_CALL_CAMERA;
import static android.app.AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE;
import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO;
+import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.media.AudioSystem.MODE_IN_COMMUNICATION;
import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
@@ -63,7 +65,8 @@ import java.util.Objects;
*
* @hide
*/
-public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedListener {
+public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedListener,
+ AppOpsManager.OnOpStartedListener {
/** Whether to show the mic and camera icons. */
private static final String PROPERTY_CAMERA_MIC_ICONS_ENABLED = "camera_mic_icons_enabled";
@@ -160,9 +163,10 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis
mUserContexts = new ArrayMap<>();
mUserContexts.put(Process.myUserHandle(), mContext);
// TODO ntmyren: make this listen for flag enable/disable changes
- String[] ops = { OPSTR_CAMERA, OPSTR_RECORD_AUDIO };
- mContext.getSystemService(AppOpsManager.class).startWatchingActive(ops,
- context.getMainExecutor(), this);
+ String[] opStrs = { OPSTR_CAMERA, OPSTR_RECORD_AUDIO };
+ mAppOpsManager.startWatchingActive(opStrs, context.getMainExecutor(), this);
+ int[] ops = { OP_CAMERA, OP_RECORD_AUDIO };
+ mAppOpsManager.startWatchingStarted(ops, this);
}
private Context getUserContext(UserHandle user) {
@@ -182,25 +186,65 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis
public void onOpActiveChanged(@NonNull String op, int uid, @NonNull String packageName,
@Nullable String attributionTag, boolean active, @AttributionFlags int attributionFlags,
int attributionChainId) {
- if (attributionChainId == ATTRIBUTION_CHAIN_ID_NONE
- || attributionFlags == ATTRIBUTION_FLAGS_NONE
- || (attributionFlags & ATTRIBUTION_FLAG_TRUSTED) == 0) {
- // If this is not a chain, or it is untrusted, return
+ if (active) {
+ // Started callback handles these
return;
}
- if (!active) {
- // if any link in the chain is finished, remove the chain.
- // TODO ntmyren: be smarter about this
- mAttributionChains.remove(attributionChainId);
+ // if any link in the chain is finished, remove the chain. Then, find any other chains that
+ // contain this op/package/uid/tag combination, and remove them, as well.
+ // TODO ntmyren: be smarter about this
+ mAttributionChains.remove(attributionChainId);
+ int numChains = mAttributionChains.size();
+ ArrayList<Integer> toRemove = new ArrayList<>();
+ for (int i = 0; i < numChains; i++) {
+ int chainId = mAttributionChains.keyAt(i);
+ ArrayList<AccessChainLink> chain = mAttributionChains.valueAt(i);
+ int chainSize = chain.size();
+ for (int j = 0; j < chainSize; j++) {
+ AccessChainLink link = chain.get(j);
+ if (link.packageAndOpEquals(op, packageName, attributionTag, uid)) {
+ toRemove.add(chainId);
+ break;
+ }
+ }
+ }
+ mAttributionChains.removeAll(toRemove);
+ }
+
+ @Override
+ public void onOpStarted(int op, int uid, String packageName, String attributionTag,
+ @AppOpsManager.OpFlags int flags, @AppOpsManager.Mode int result) {
+ // not part of an attribution chain. Do nothing
+ }
+
+ @Override
+ public void onOpStarted(int op, int uid, String packageName, String attributionTag,
+ @AppOpsManager.OpFlags int flags, @AppOpsManager.Mode int result,
+ @StartedType int startedType, @AttributionFlags int attributionFlags,
+ int attributionChainId) {
+ if (startedType == START_TYPE_FAILED || attributionChainId == ATTRIBUTION_CHAIN_ID_NONE
+ || attributionFlags == ATTRIBUTION_FLAGS_NONE
+ || (attributionFlags & ATTRIBUTION_FLAG_TRUSTED) == 0) {
+ // If this is not a successful start, or it is not a chain, or it is untrusted, return
return;
}
+ addLinkToChainIfNotPresent(AppOpsManager.opToPublicName(op), packageName, uid,
+ attributionTag, attributionFlags, attributionChainId);
+ }
+
+ private void addLinkToChainIfNotPresent(String op, String packageName, int uid,
+ String attributionTag, int attributionFlags, int attributionChainId) {
ArrayList<AccessChainLink> currentChain = mAttributionChains.computeIfAbsent(
attributionChainId, k -> new ArrayList<>());
AccessChainLink link = new AccessChainLink(op, packageName, attributionTag, uid,
attributionFlags);
+ if (currentChain.contains(link)) {
+ return;
+ }
+
int currSize = currentChain.size();
if (currSize == 0 || link.isEnd() || !currentChain.get(currSize - 1).isEnd()) {
// if the list is empty, this link is the end, or the last link in the current chain
@@ -613,5 +657,21 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis
public boolean isStart() {
return (flags & ATTRIBUTION_FLAG_RECEIVER) != 0;
}
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof AccessChainLink)) {
+ return false;
+ }
+ AccessChainLink other = (AccessChainLink) obj;
+ return other.flags == flags && packageAndOpEquals(other.usage.op,
+ other.usage.packageName, other.usage.attributionTag, other.usage.uid);
+ }
+
+ public boolean packageAndOpEquals(String op, String packageName, String attributionTag,
+ int uid) {
+ return Objects.equals(op, usage.op) && Objects.equals(packageName, usage.packageName)
+ && Objects.equals(attributionTag, usage.attributionTag) && uid == usage.uid;
+ }
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 589ecc0a4de5..dc4a74766ed9 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10119,6 +10119,61 @@ public final class Settings {
@Readable
public static final String GAME_DASHBOARD_ALWAYS_ON = "game_dashboard_always_on";
+
+ /**
+ * For this device state, no specific auto-rotation lock setting should be applied.
+ * If the user toggles the auto-rotate lock in this state, the setting will apply to the
+ * previously valid device state.
+ * @hide
+ */
+ public static final int DEVICE_STATE_ROTATION_LOCK_IGNORED = 0;
+ /**
+ * For this device state, the setting for auto-rotation is locked.
+ * @hide
+ */
+ public static final int DEVICE_STATE_ROTATION_LOCK_LOCKED = 1;
+ /**
+ * For this device state, the setting for auto-rotation is unlocked.
+ * @hide
+ */
+ public static final int DEVICE_STATE_ROTATION_LOCK_UNLOCKED = 2;
+
+ /**
+ * The different settings that can be used as values with
+ * {@link #DEVICE_STATE_ROTATION_LOCK}.
+ * @hide
+ */
+ @IntDef(prefix = {"DEVICE_STATE_ROTATION_LOCK_"}, value = {
+ DEVICE_STATE_ROTATION_LOCK_IGNORED,
+ DEVICE_STATE_ROTATION_LOCK_LOCKED,
+ DEVICE_STATE_ROTATION_LOCK_UNLOCKED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface DeviceStateRotationLockSetting {
+ }
+
+ /**
+ * Rotation lock setting keyed on device state.
+ *
+ * This holds a serialized map using int keys that represent Device States and value of
+ * {@link DeviceStateRotationLockSetting} representing the rotation lock setting for that
+ * device state.
+ *
+ * Serialized as key0:value0:key1:value1:...:keyN:valueN.
+ *
+ * Example: "0:1:1:2:2:1"
+ * This example represents a map of:
+ * <ul>
+ * <li>0 -> DEVICE_STATE_ROTATION_LOCK_LOCKED</li>
+ * <li>1 -> DEVICE_STATE_ROTATION_LOCK_UNLOCKED</li>
+ * <li>2 -> DEVICE_STATE_ROTATION_LOCK_IGNORED</li>
+ * </ul>
+ *
+ * @hide
+ */
+ public static final String DEVICE_STATE_ROTATION_LOCK =
+ "device_state_rotation_lock";
+
/**
* These entries are considered common between the personal and the managed profile,
* since the managed profile doesn't get to change them.
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 41374167cc56..face870ca1b4 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -783,6 +783,9 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
* This may happen if another detector has been instantiated or the
* {@link VoiceInteractionService} hosting this detector has been shut down.
*/
+ // TODO: Remove this RequiresPermission since it isn't actually enforced. Also fix the javadoc
+ // about permissions enforcement (when it throws vs when it just returns false) for other
+ // methods in this class.
@RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD})
@Override
public boolean stopRecognition() {
diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java
index 02294e5720ae..f7a3415259fd 100644
--- a/core/java/android/service/voice/SoftwareHotwordDetector.java
+++ b/core/java/android/service/voice/SoftwareHotwordDetector.java
@@ -82,6 +82,9 @@ class SoftwareHotwordDetector extends AbstractHotwordDetector {
try {
mManagerService.startListeningFromMic(
mAudioFormat, new BinderCallback(mHandler, mCallback));
+ } catch (SecurityException e) {
+ Slog.e(TAG, "startRecognition failed: " + e);
+ return false;
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 6a0fec790242..f52c9ff210d6 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -520,6 +520,12 @@ public class VoiceInteractionService extends Service {
// Ignore.
}
+ try {
+ mSystemService.shutdownHotwordDetectionService();
+ } catch (Exception ex) {
+ // Ignore.
+ }
+
mSoftwareHotwordDetector = null;
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index a3e328da5cb9..4bf60495f3af 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -16,6 +16,8 @@
package android.service.wallpaper;
+import static android.app.WallpaperManager.COMMAND_FREEZE;
+import static android.app.WallpaperManager.COMMAND_UNFREEZE;
import static android.graphics.Matrix.MSCALE_X;
import static android.graphics.Matrix.MSCALE_Y;
import static android.graphics.Matrix.MSKEW_X;
@@ -42,12 +44,14 @@ import android.content.res.TypedArray;
import android.graphics.BLASTBufferQueue;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.GraphicBuffer;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
+import android.hardware.HardwareBuffer;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.os.Build;
@@ -56,6 +60,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -200,6 +205,12 @@ public abstract class WallpaperService extends Service {
boolean mVisible;
boolean mReportedVisible;
boolean mDestroyed;
+ // Set to true after receiving WallpaperManager#COMMAND_FREEZE. It's reset back to false
+ // after receiving WallpaperManager#COMMAND_UNFREEZE. COMMAND_FREEZE is fully applied once
+ // mScreenshotSurfaceControl isn't null. When this happens, then Engine is notified through
+ // doVisibilityChanged that main wallpaper surface is no longer visible and the wallpaper
+ // host receives onVisibilityChanged(false) callback.
+ private boolean mFrozenRequested = false;
// Current window state.
boolean mCreated;
@@ -264,6 +275,8 @@ public abstract class WallpaperService extends Service {
SurfaceControl mSurfaceControl = new SurfaceControl();
SurfaceControl mBbqSurfaceControl;
BLASTBufferQueue mBlastBufferQueue;
+ private SurfaceControl mScreenshotSurfaceControl;
+ private Point mScreenshotSize = new Point();
final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() {
{
@@ -1349,11 +1362,15 @@ public abstract class WallpaperService extends Service {
if (!mDestroyed) {
mVisible = visible;
reportVisibility();
- if (visible) processLocalColors(mPendingXOffset, mPendingXOffsetStep);
+ if (mReportedVisible) processLocalColors(mPendingXOffset, mPendingXOffsetStep);
}
}
void reportVisibility() {
+ if (mScreenshotSurfaceControl != null && mVisible) {
+ if (DEBUG) Log.v(TAG, "Frozen so don't report visibility change");
+ return;
+ }
if (!mDestroyed) {
mDisplayState = mDisplay == null ? Display.STATE_UNKNOWN : mDisplay.getState();
boolean visible = mVisible && mDisplayState != Display.STATE_OFF;
@@ -1370,6 +1387,10 @@ public abstract class WallpaperService extends Service {
updateSurface(true, false, false);
}
onVisibilityChanged(visible);
+ if (mReportedVisible && mFrozenRequested) {
+ if (DEBUG) Log.v(TAG, "Freezing wallpaper after visibility update");
+ freeze();
+ }
}
}
}
@@ -1830,6 +1851,9 @@ public abstract class WallpaperService extends Service {
void doCommand(WallpaperCommand cmd) {
Bundle result;
if (!mDestroyed) {
+ if (COMMAND_FREEZE.equals(cmd.action) || COMMAND_UNFREEZE.equals(cmd.action)) {
+ updateFrozenState(/* frozenRequested= */ !COMMAND_UNFREEZE.equals(cmd.action));
+ }
result = onCommand(cmd.action, cmd.x, cmd.y, cmd.z,
cmd.extras, cmd.sync);
} else {
@@ -1844,6 +1868,159 @@ public abstract class WallpaperService extends Service {
}
}
+ private void updateFrozenState(boolean frozenRequested) {
+ if (mIWallpaperEngine.mWallpaperManager.getWallpaperInfo() == null
+ // Procees the unfreeze command in case the wallaper became static while
+ // being paused.
+ && frozenRequested) {
+ if (DEBUG) Log.v(TAG, "Ignoring the freeze command for static wallpapers");
+ return;
+ }
+ mFrozenRequested = frozenRequested;
+ boolean isFrozen = mScreenshotSurfaceControl != null;
+ if (mFrozenRequested == isFrozen) {
+ return;
+ }
+ if (mFrozenRequested) {
+ freeze();
+ } else {
+ unfreeze();
+ }
+ }
+
+ private void freeze() {
+ if (!mReportedVisible || mDestroyed) {
+ // Screenshot can't be taken until visibility is reported to the wallpaper host.
+ return;
+ }
+ if (!showScreenshotOfWallpaper()) {
+ return;
+ }
+ // Prevent a wallpaper host from rendering wallpaper behind a screeshot.
+ doVisibilityChanged(false);
+ // Remember that visibility is requested since it's not guaranteed that
+ // mWindow#dispatchAppVisibility will be called when letterboxed application with
+ // wallpaper background transitions to the Home screen.
+ mVisible = true;
+ }
+
+ private void unfreeze() {
+ cleanUpScreenshotSurfaceControl();
+ if (mVisible) {
+ doVisibilityChanged(true);
+ }
+ }
+
+ private void cleanUpScreenshotSurfaceControl() {
+ // TODO(b/194399558): Add crossfade transition.
+ if (mScreenshotSurfaceControl != null) {
+ new SurfaceControl.Transaction()
+ .remove(mScreenshotSurfaceControl)
+ .show(mBbqSurfaceControl)
+ .apply();
+ mScreenshotSurfaceControl = null;
+ }
+ }
+
+ void scaleAndCropScreenshot() {
+ if (mScreenshotSurfaceControl == null) {
+ return;
+ }
+ if (mScreenshotSize.x <= 0 || mScreenshotSize.y <= 0) {
+ Log.w(TAG, "Unexpected screenshot size: " + mScreenshotSize);
+ return;
+ }
+ // Don't scale down and using the same scaling factor for both dimensions to
+ // avoid stretching wallpaper image.
+ float scaleFactor = Math.max(1, Math.max(
+ ((float) mSurfaceSize.x) / mScreenshotSize.x,
+ ((float) mSurfaceSize.y) / mScreenshotSize.y));
+ int diffX = ((int) (mScreenshotSize.x * scaleFactor)) - mSurfaceSize.x;
+ int diffY = ((int) (mScreenshotSize.y * scaleFactor)) - mSurfaceSize.y;
+ if (DEBUG) {
+ Log.v(TAG, "Adjusting screenshot: scaleFactor=" + scaleFactor
+ + " diffX=" + diffX + " diffY=" + diffY + " mSurfaceSize=" + mSurfaceSize
+ + " mScreenshotSize=" + mScreenshotSize);
+ }
+ new SurfaceControl.Transaction()
+ .setMatrix(
+ mScreenshotSurfaceControl,
+ /* dsdx= */ scaleFactor, /* dtdx= */ 0,
+ /* dtdy= */ 0, /* dsdy= */ scaleFactor)
+ .setWindowCrop(
+ mScreenshotSurfaceControl,
+ new Rect(
+ /* left= */ diffX / 2,
+ /* top= */ diffY / 2,
+ /* right= */ diffX / 2 + mScreenshotSize.x,
+ /* bottom= */ diffY / 2 + mScreenshotSize.y))
+ .setPosition(mScreenshotSurfaceControl, -diffX / 2, -diffY / 2)
+ .apply();
+ }
+
+ private boolean showScreenshotOfWallpaper() {
+ if (mDestroyed || mSurfaceControl == null || !mSurfaceControl.isValid()) {
+ if (DEBUG) Log.v(TAG, "Failed to screenshot wallpaper: surface isn't valid");
+ return false;
+ }
+
+ final Rect bounds = new Rect(0, 0, mSurfaceSize.x, mSurfaceSize.y);
+ if (bounds.isEmpty()) {
+ Log.w(TAG, "Failed to screenshot wallpaper: surface bounds are empty");
+ return false;
+ }
+
+ if (mScreenshotSurfaceControl != null) {
+ Log.e(TAG, "Screenshot is unexpectedly not null");
+ // Destroying previous screenshot since it can have different size.
+ cleanUpScreenshotSurfaceControl();
+ }
+
+ SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
+ SurfaceControl.captureLayers(
+ new SurfaceControl.LayerCaptureArgs.Builder(mSurfaceControl)
+ // Needed because SurfaceFlinger#validateScreenshotPermissions
+ // uses this parameter to check whether a caller only attempts
+ // to screenshot itself when call doesn't come from the system.
+ .setUid(Process.myUid())
+ .setChildrenOnly(false)
+ .setSourceCrop(bounds)
+ .build());
+
+ if (screenshotBuffer == null) {
+ Log.w(TAG, "Failed to screenshot wallpaper: screenshotBuffer is null");
+ return false;
+ }
+
+ final HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer();
+
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+
+ // TODO(b/194399558): Add crossfade transition.
+ mScreenshotSurfaceControl = new SurfaceControl.Builder()
+ .setName("Wallpaper snapshot for engine " + this)
+ .setFormat(hardwareBuffer.getFormat())
+ .setParent(mSurfaceControl)
+ .setSecure(screenshotBuffer.containsSecureLayers())
+ .setCallsite("WallpaperService.Engine.showScreenshotOfWallpaper")
+ .setBLASTLayer()
+ .build();
+
+ mScreenshotSize.set(mSurfaceSize.x, mSurfaceSize.y);
+
+ GraphicBuffer graphicBuffer = GraphicBuffer.createFromHardwareBuffer(hardwareBuffer);
+
+ t.setBuffer(mScreenshotSurfaceControl, graphicBuffer);
+ t.setColorSpace(mScreenshotSurfaceControl, screenshotBuffer.getColorSpace());
+ // Place on top everything else.
+ t.setLayer(mScreenshotSurfaceControl, Integer.MAX_VALUE);
+ t.show(mScreenshotSurfaceControl);
+ t.hide(mBbqSurfaceControl);
+ t.apply();
+
+ return true;
+ }
+
void reportSurfaceDestroyed() {
if (mSurfaceCreated) {
mSurfaceCreated = false;
@@ -2166,6 +2343,7 @@ public abstract class WallpaperService extends Service {
final boolean reportDraw = message.arg1 != 0;
mEngine.updateSurface(true, false, reportDraw);
mEngine.doOffsetsChanged(true);
+ mEngine.scaleAndCropScreenshot();
} break;
case MSG_WINDOW_MOVED: {
// Do nothing. What does it mean for a Wallpaper to move?
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 9cb0d1ff2c3f..e7ff978266a2 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -1463,10 +1463,10 @@ public final class Display {
return false;
}
final Configuration config = mResources.getConfiguration();
- // TODO(b/179308296) Temporarily exclude Launcher from being given max bounds, by checking
- // if the caller is the recents component.
+ // TODO(b/179308296) Temporarily - never report max bounds to only Launcher if the feature
+ // is disabled.
return config != null && !config.windowConfiguration.getMaxBounds().isEmpty()
- && !isRecentsComponent();
+ && (mDisplayInfo.shouldConstrainMetricsForLauncher || !isRecentsComponent());
}
/**
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 8e5f905e9c74..657251046551 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -306,6 +306,13 @@ public final class DisplayInfo implements Parcelable {
public float brightnessDefault;
/**
+ * @hide
+ * True if Display#getRealSize and getRealMetrics should be constrained for Launcher, false
+ * otherwise.
+ */
+ public boolean shouldConstrainMetricsForLauncher = false;
+
+ /**
* The {@link RoundedCorners} if present, otherwise {@code null}.
*/
@Nullable
@@ -381,7 +388,8 @@ public final class DisplayInfo implements Parcelable {
&& brightnessMinimum == other.brightnessMinimum
&& brightnessMaximum == other.brightnessMaximum
&& brightnessDefault == other.brightnessDefault
- && Objects.equals(roundedCorners, other.roundedCorners);
+ && Objects.equals(roundedCorners, other.roundedCorners)
+ && shouldConstrainMetricsForLauncher == other.shouldConstrainMetricsForLauncher;
}
@Override
@@ -432,6 +440,7 @@ public final class DisplayInfo implements Parcelable {
brightnessMaximum = other.brightnessMaximum;
brightnessDefault = other.brightnessDefault;
roundedCorners = other.roundedCorners;
+ shouldConstrainMetricsForLauncher = other.shouldConstrainMetricsForLauncher;
}
public void readFromParcel(Parcel source) {
@@ -488,6 +497,7 @@ public final class DisplayInfo implements Parcelable {
for (int i = 0; i < numUserDisabledFormats; i++) {
userDisabledHdrTypes[i] = source.readInt();
}
+ shouldConstrainMetricsForLauncher = source.readBoolean();
}
@Override
@@ -542,6 +552,7 @@ public final class DisplayInfo implements Parcelable {
for (int i = 0; i < userDisabledHdrTypes.length; i++) {
dest.writeInt(userDisabledHdrTypes[i]);
}
+ dest.writeBoolean(shouldConstrainMetricsForLauncher);
}
@Override
@@ -796,6 +807,8 @@ public final class DisplayInfo implements Parcelable {
sb.append(brightnessMaximum);
sb.append(", brightnessDefault ");
sb.append(brightnessDefault);
+ sb.append(", shouldConstrainMetricsForLauncher ");
+ sb.append(shouldConstrainMetricsForLauncher);
sb.append("}");
return sb.toString();
}
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index cdc099b8e2ea..bd68401e6534 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -197,6 +197,12 @@ public class RemoteAnimationTarget implements Parcelable {
public ActivityManager.RunningTaskInfo taskInfo;
/**
+ * {@code true} if picture-in-picture permission is granted in {@link android.app.AppOpsManager}
+ */
+ @UnsupportedAppUsage
+ public boolean allowEnterPip;
+
+ /**
* The {@link android.view.WindowManager.LayoutParams.WindowType} of this window. It's only used
* for non-app window.
*/
@@ -206,10 +212,11 @@ public class RemoteAnimationTarget implements Parcelable {
Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position,
Rect localBounds, Rect screenSpaceBounds,
WindowConfiguration windowConfig, boolean isNotInRecents,
- SurfaceControl startLeash, Rect startBounds, ActivityManager.RunningTaskInfo taskInfo) {
+ SurfaceControl startLeash, Rect startBounds, ActivityManager.RunningTaskInfo taskInfo,
+ boolean allowEnterPip) {
this(taskId, mode, leash, isTranslucent, clipRect, contentInsets, prefixOrderIndex,
position, localBounds, screenSpaceBounds, windowConfig, isNotInRecents, startLeash,
- startBounds, taskInfo, INVALID_WINDOW_TYPE);
+ startBounds, taskInfo, allowEnterPip, INVALID_WINDOW_TYPE);
}
public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent,
@@ -217,7 +224,7 @@ public class RemoteAnimationTarget implements Parcelable {
Rect localBounds, Rect screenSpaceBounds,
WindowConfiguration windowConfig, boolean isNotInRecents,
SurfaceControl startLeash, Rect startBounds,
- ActivityManager.RunningTaskInfo taskInfo,
+ ActivityManager.RunningTaskInfo taskInfo, boolean allowEnterPip,
@WindowManager.LayoutParams.WindowType int windowType) {
this.mode = mode;
this.taskId = taskId;
@@ -235,6 +242,7 @@ public class RemoteAnimationTarget implements Parcelable {
this.startLeash = startLeash;
this.startBounds = startBounds == null ? null : new Rect(startBounds);
this.taskInfo = taskInfo;
+ this.allowEnterPip = allowEnterPip;
this.windowType = windowType;
}
@@ -255,6 +263,7 @@ public class RemoteAnimationTarget implements Parcelable {
startLeash = in.readTypedObject(SurfaceControl.CREATOR);
startBounds = in.readTypedObject(Rect.CREATOR);
taskInfo = in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
+ allowEnterPip = in.readBoolean();
windowType = in.readInt();
}
@@ -281,6 +290,7 @@ public class RemoteAnimationTarget implements Parcelable {
dest.writeTypedObject(startLeash, 0 /* flags */);
dest.writeTypedObject(startBounds, 0 /* flags */);
dest.writeTypedObject(taskInfo, 0 /* flags */);
+ dest.writeBoolean(allowEnterPip);
dest.writeInt(windowType);
}
@@ -299,6 +309,7 @@ public class RemoteAnimationTarget implements Parcelable {
pw.print(prefix); pw.print("windowConfiguration="); pw.println(windowConfiguration);
pw.print(prefix); pw.print("leash="); pw.println(leash);
pw.print(prefix); pw.print("taskInfo="); pw.println(taskInfo);
+ pw.print(prefix); pw.print("allowEnterPip="); pw.println(allowEnterPip);
pw.print(prefix); pw.print("windowType="); pw.print(windowType);
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index c39426d64f73..a4e7a43cc934 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -33,6 +33,7 @@ import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.RenderNode;
@@ -237,15 +238,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
new SurfaceControl.Transaction();
/**
- * Transaction that should be used for
- * {@link RenderNode.PositionUpdateListener#positionChanged(long, int, int, int, int)}
- * The callback is invoked from a thread pool so it's not thread safe with other render thread
- * transactions. Keep the transactions for position changed callbacks on its own transaction.
- */
- private final SurfaceControl.Transaction mPositionChangedTransaction =
- new SurfaceControl.Transaction();
-
- /**
* A temporary transaction holder that should only be used when applying right away. There
* should be no assumption about thread safety for this transaction.
*/
@@ -295,7 +287,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
int defStyleRes, boolean disableBackgroundLayer) {
super(context, attrs, defStyleAttr, defStyleRes);
mUseBlastAdapter = useBlastAdapter(context);
- mRenderNode.addPositionUpdateListener(mPositionListener);
setWillNotDraw(true);
mDisableBackgroundLayer = disableBackgroundLayer;
@@ -943,6 +934,24 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
}
+
+ // The position update listener is used to safely share the surface size between render thread
+ // workers and the UI thread. Both threads need to know the surface size to determine the scale.
+ // The parent layer scales the surface size to view size. The child (BBQ) layer scales
+ // the buffer to the surface size. Both scales along with the window crop must be applied
+ // synchronously otherwise we may see flickers.
+ // When the listener is updated, we will get at least a single position update call so we can
+ // guarantee any changes we post will be applied.
+ private void replacePositionUpdateListener(int surfaceWidth, int surfaceHeight,
+ @Nullable Transaction geometryTransaction) {
+ if (mPositionListener != null) {
+ mRenderNode.removePositionUpdateListener(mPositionListener);
+ }
+ mPositionListener = new SurfaceViewPositionUpdateListener(surfaceWidth, surfaceHeight,
+ geometryTransaction);
+ mRenderNode.addPositionUpdateListener(mPositionListener);
+ }
+
private boolean performSurfaceTransaction(ViewRootImpl viewRoot, Translator translator,
boolean creating, boolean sizeChanged, boolean hintChanged) {
boolean realSizeChanged = false;
@@ -985,13 +994,13 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
// While creating the surface, we will set it's initial
// geometry. Outside of that though, we should generally
// leave it to the RenderThread.
- //
- // There is one more case when the buffer size changes we aren't yet
- // prepared to sync (as even following the transaction applying
- // we still need to latch a buffer).
- // b/28866173
- if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
- onSetSurfacePositionAndScaleRT(mTmpTransaction, mSurfaceControl,
+ Transaction geometryTransaction = new Transaction();
+ geometryTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
+ if ((sizeChanged || hintChanged) && !creating) {
+ setBufferSize(geometryTransaction);
+ }
+ if (sizeChanged || creating || !isHardwareAccelerated()) {
+ onSetSurfacePositionAndScaleRT(geometryTransaction, mSurfaceControl,
mScreenRect.left, /*positionLeft*/
mScreenRect.top /*positionTop*/ ,
mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/,
@@ -1002,17 +1011,31 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
// use SCALING_MODE_SCALE and submit a larger size than the surface
// size.
if (mClipSurfaceToBounds && mClipBounds != null) {
- mTmpTransaction.setWindowCrop(mSurfaceControl, mClipBounds);
+ geometryTransaction.setWindowCrop(mSurfaceControl, mClipBounds);
} else {
- mTmpTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
+ geometryTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
mSurfaceHeight);
}
- }
- mTmpTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
- if ((sizeChanged || hintChanged) && !creating) {
- setBufferSize(mTmpTransaction);
- }
+ boolean applyChangesOnRenderThread =
+ sizeChanged && !creating && isHardwareAccelerated();
+ if (isHardwareAccelerated()) {
+ // This will consume the passed in transaction and the transaction will be
+ // applied on a render worker thread.
+ replacePositionUpdateListener(mSurfaceWidth, mSurfaceHeight,
+ applyChangesOnRenderThread ? geometryTransaction : null);
+ }
+ if (DEBUG_POSITION) {
+ Log.d(TAG, String.format(
+ "%d updateSurfacePosition %s"
+ + "position = [%d, %d, %d, %d] surfaceSize = %dx%d",
+ System.identityHashCode(this),
+ applyChangesOnRenderThread ? "RenderWorker" : "UiThread",
+ mScreenRect.left, mScreenRect.top, mScreenRect.right,
+ mScreenRect.bottom, mSurfaceWidth, mSurfaceHeight));
+ }
+ }
+ mTmpTransaction.merge(geometryTransaction);
mTmpTransaction.apply();
updateEmbeddedAccessibilityMatrix();
@@ -1242,7 +1265,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
mBlastSurfaceControl.setTransformHint(mTransformHint);
if (mBlastBufferQueue != null) {
mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight,
- mFormat);
+ mFormat, transaction);
}
} else {
transaction.setBufferSize(mSurfaceControl, mSurfaceWidth, mSurfaceHeight);
@@ -1399,19 +1422,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
mTmpTransaction.apply();
}
- private void applySurfaceTransforms(SurfaceControl surface, SurfaceControl.Transaction t,
- Rect position) {
- onSetSurfacePositionAndScaleRT(t, surface,
- position.left /*positionLeft*/,
- position.top /*positionTop*/,
- position.width() / (float) mSurfaceWidth /*postScaleX*/,
- position.height() / (float) mSurfaceHeight /*postScaleY*/);
-
- if (mViewVisibility) {
- t.show(surface);
- }
- }
-
/**
* @return The last render position of the backing surface or an empty rect.
*
@@ -1421,13 +1431,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
return mRTLastReportedPosition;
}
- private void setParentSpaceRectangle(Rect position, long frameNumber, Transaction t) {
- final ViewRootImpl viewRoot = getViewRootImpl();
- applySurfaceTransforms(mSurfaceControl, t, position);
- applyChildSurfaceTransaction_renderWorker(t, viewRoot.mSurface, frameNumber);
- applyOrMergeTransaction(t, frameNumber);
- }
-
private void applyOrMergeTransaction(Transaction t, long frameNumber) {
final ViewRootImpl viewRoot = getViewRootImpl();
boolean useBLAST = viewRoot != null && useBLASTSync(viewRoot);
@@ -1440,9 +1443,24 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
private Rect mRTLastReportedPosition = new Rect();
-
- private RenderNode.PositionUpdateListener mPositionListener =
- new RenderNode.PositionUpdateListener() {
+ private Point mRTLastReportedSurfaceSize = new Point();
+
+ private class SurfaceViewPositionUpdateListener implements RenderNode.PositionUpdateListener {
+ int mRtSurfaceWidth = -1;
+ int mRtSurfaceHeight = -1;
+ private final SurfaceControl.Transaction mPositionChangedTransaction =
+ new SurfaceControl.Transaction();
+ boolean mPendingTransaction = false;
+
+ SurfaceViewPositionUpdateListener(int surfaceWidth, int surfaceHeight,
+ @Nullable Transaction t) {
+ mRtSurfaceWidth = surfaceWidth;
+ mRtSurfaceHeight = surfaceHeight;
+ if (t != null) {
+ mPositionChangedTransaction.merge(t);
+ mPendingTransaction = true;
+ }
+ }
@Override
public void positionChanged(long frameNumber, int left, int top, int right, int bottom) {
@@ -1464,21 +1482,34 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
if (mRTLastReportedPosition.left == left
&& mRTLastReportedPosition.top == top
&& mRTLastReportedPosition.right == right
- && mRTLastReportedPosition.bottom == bottom) {
+ && mRTLastReportedPosition.bottom == bottom
+ && mRTLastReportedSurfaceSize.x == mRtSurfaceWidth
+ && mRTLastReportedSurfaceSize.y == mRtSurfaceHeight
+ && !mPendingTransaction) {
return;
}
try {
if (DEBUG_POSITION) {
Log.d(TAG, String.format(
"%d updateSurfacePosition RenderWorker, frameNr = %d, "
- + "position = [%d, %d, %d, %d]",
- System.identityHashCode(this), frameNumber,
- left, top, right, bottom));
+ + "position = [%d, %d, %d, %d] surfaceSize = %dx%d",
+ System.identityHashCode(SurfaceView.this), frameNumber,
+ left, top, right, bottom, mRtSurfaceWidth, mRtSurfaceHeight));
}
mRTLastReportedPosition.set(left, top, right, bottom);
- setParentSpaceRectangle(mRTLastReportedPosition, frameNumber,
- mPositionChangedTransaction);
- // Now overwrite mRTLastReportedPosition with our values
+ mRTLastReportedSurfaceSize.set(mRtSurfaceWidth, mRtSurfaceHeight);
+ onSetSurfacePositionAndScaleRT(mPositionChangedTransaction, mSurfaceControl,
+ mRTLastReportedPosition.left /*positionLeft*/,
+ mRTLastReportedPosition.top /*positionTop*/,
+ mRTLastReportedPosition.width() / (float) mRtSurfaceWidth /*postScaleX*/,
+ mRTLastReportedPosition.height() / (float) mRtSurfaceHeight /*postScaleY*/);
+ if (mViewVisibility) {
+ mPositionChangedTransaction.show(mSurfaceControl);
+ }
+ applyChildSurfaceTransaction_renderWorker(mPositionChangedTransaction,
+ getViewRootImpl().mSurface, frameNumber);
+ applyOrMergeTransaction(mPositionChangedTransaction, frameNumber);
+ mPendingTransaction = false;
} catch (Exception ex) {
Log.e(TAG, "Exception from repositionChild", ex);
}
@@ -1502,7 +1533,13 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
System.identityHashCode(this), frameNumber));
}
mRTLastReportedPosition.setEmpty();
-
+ mRTLastReportedSurfaceSize.set(-1, -1);
+ if (mPendingTransaction) {
+ Log.w(TAG, System.identityHashCode(SurfaceView.this)
+ + "Pending transaction cleared.");
+ mPositionChangedTransaction.clear();
+ mPendingTransaction = false;
+ }
if (mSurfaceControl == null) {
return;
}
@@ -1521,7 +1558,9 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
mRtHandlingPositionUpdates = false;
}
}
- };
+ }
+
+ private SurfaceViewPositionUpdateListener mPositionListener = null;
private SurfaceHolder.Callback[] getSurfaceCallbacks() {
SurfaceHolder.Callback[] callbacks;
diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java
index 57dfc62b4f8f..1edbbba09eef 100644
--- a/core/java/android/view/WindowInfo.java
+++ b/core/java/android/view/WindowInfo.java
@@ -16,6 +16,7 @@
package android.view;
+import android.app.ActivityTaskManager;
import android.graphics.Region;
import android.os.IBinder;
import android.os.Parcel;
@@ -51,6 +52,7 @@ public class WindowInfo implements Parcelable {
public boolean inPictureInPicture;
public boolean hasFlagWatchOutsideTouch;
public int displayId = Display.INVALID_DISPLAY;
+ public int taskId = ActivityTaskManager.INVALID_TASK_ID;
private WindowInfo() {
/* do nothing - hide constructor */
@@ -67,6 +69,7 @@ public class WindowInfo implements Parcelable {
public static WindowInfo obtain(WindowInfo other) {
WindowInfo window = obtain();
window.displayId = other.displayId;
+ window.taskId = other.taskId;
window.type = other.type;
window.layer = other.layer;
window.token = other.token;
@@ -103,6 +106,7 @@ public class WindowInfo implements Parcelable {
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(displayId);
+ parcel.writeInt(taskId);
parcel.writeInt(type);
parcel.writeInt(layer);
parcel.writeStrongBinder(token);
@@ -129,6 +133,7 @@ public class WindowInfo implements Parcelable {
builder.append("WindowInfo[");
builder.append("title=").append(title);
builder.append(", displayId=").append(displayId);
+ builder.append(", taskId=").append(taskId);
builder.append(", type=").append(type);
builder.append(", layer=").append(layer);
builder.append(", token=").append(token);
@@ -146,6 +151,7 @@ public class WindowInfo implements Parcelable {
private void initFromParcel(Parcel parcel) {
displayId = parcel.readInt();
+ taskId = parcel.readInt();
type = parcel.readInt();
layer = parcel.readInt();
token = parcel.readStrongBinder();
@@ -169,6 +175,7 @@ public class WindowInfo implements Parcelable {
private void clear() {
displayId = Display.INVALID_DISPLAY;
+ taskId = ActivityTaskManager.INVALID_TASK_ID;
type = 0;
layer = 0;
token = null;
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index edcb59a79c70..76e226163ca1 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -19,6 +19,7 @@ package android.view.accessibility;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
+import android.app.ActivityTaskManager;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Parcel;
@@ -114,6 +115,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
private int mBooleanProperties;
private int mId = UNDEFINED_WINDOW_ID;
private int mParentId = UNDEFINED_WINDOW_ID;
+ private int mTaskId = ActivityTaskManager.INVALID_TASK_ID;
private Region mRegionInScreen = new Region();
private LongArray mChildIds;
private CharSequence mTitle;
@@ -307,6 +309,28 @@ public final class AccessibilityWindowInfo implements Parcelable {
}
/**
+ * Gets the task ID.
+ *
+ * @return The task ID.
+ *
+ * @hide
+ */
+ public int getTaskId() {
+ return mTaskId;
+ }
+
+ /**
+ * Sets the task ID.
+ *
+ * @param taskId The task ID.
+ *
+ * @hide
+ */
+ public void setTaskId(int taskId) {
+ mTaskId = taskId;
+ }
+
+ /**
* Sets the unique id of the IAccessibilityServiceConnection over which
* this instance can send requests to the system.
*
@@ -578,6 +602,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
parcel.writeInt(mBooleanProperties);
parcel.writeInt(mId);
parcel.writeInt(mParentId);
+ parcel.writeInt(mTaskId);
mRegionInScreen.writeToParcel(parcel, flags);
parcel.writeCharSequence(mTitle);
parcel.writeLong(mAnchorId);
@@ -608,6 +633,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
mBooleanProperties = other.mBooleanProperties;
mId = other.mId;
mParentId = other.mParentId;
+ mTaskId = other.mTaskId;
mRegionInScreen.set(other.mRegionInScreen);
mTitle = other.mTitle;
mAnchorId = other.mAnchorId;
@@ -631,6 +657,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
mBooleanProperties = parcel.readInt();
mId = parcel.readInt();
mParentId = parcel.readInt();
+ mTaskId = parcel.readInt();
mRegionInScreen = Region.CREATOR.createFromParcel(parcel);
mTitle = parcel.readCharSequence();
mAnchorId = parcel.readLong();
@@ -676,6 +703,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
builder.append("title=").append(mTitle);
builder.append(", displayId=").append(mDisplayId);
builder.append(", id=").append(mId);
+ builder.append(", taskId=").append(mTaskId);
builder.append(", type=").append(typeToString(mType));
builder.append(", layer=").append(mLayer);
builder.append(", region=").append(mRegionInScreen);
@@ -719,6 +747,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
mBooleanProperties = 0;
mId = UNDEFINED_WINDOW_ID;
mParentId = UNDEFINED_WINDOW_ID;
+ mTaskId = ActivityTaskManager.INVALID_TASK_ID;
mRegionInScreen.setEmpty();
mChildIds = null;
mConnectionId = UNDEFINED_WINDOW_ID;
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 38019c9a34f8..5f036a348808 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -1013,8 +1013,10 @@ public interface InputConnection {
*
* @param imeConsumesInput {@code true} when the IME is consuming input and the cursor should be
* hidden, {@code false} when input to the editor resumes and the cursor should be shown again.
- * @return {@code true} on success, {@code false} if the input connection is no longer valid, or
- * the protocol is not supported.
+ * @return For editor authors, the return value will always be ignored. For IME authors, this
+ * method returns {@code true} if the request was sent (whether or not the associated
+ * editor does something based on this request), {@code false} if the input connection
+ * is no longer valid.
*/
default boolean setImeConsumesInput(boolean imeConsumesInput) {
return false;
diff --git a/core/java/android/view/translation/Translator.java b/core/java/android/view/translation/Translator.java
index edd0d16a5ccb..606f39d6e25e 100644
--- a/core/java/android/view/translation/Translator.java
+++ b/core/java/android/view/translation/Translator.java
@@ -18,6 +18,7 @@ package android.view.translation;
import static android.view.translation.TranslationManager.STATUS_SYNC_CALL_FAIL;
import static android.view.translation.TranslationManager.SYNC_CALLS_TIMEOUT_MS;
+import static android.view.translation.UiTranslationController.DEBUG;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
@@ -38,7 +39,6 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.IResultReceiver;
import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
@@ -395,27 +395,26 @@ public class Translator {
private static class TranslationResponseCallbackImpl extends ITranslationCallback.Stub {
- private final WeakReference<Consumer<TranslationResponse>> mCallback;
- private final WeakReference<Executor> mExecutor;
+ private final Consumer<TranslationResponse> mCallback;
+ private final Executor mExecutor;
TranslationResponseCallbackImpl(Consumer<TranslationResponse> callback, Executor executor) {
- mCallback = new WeakReference<>(callback);
- mExecutor = new WeakReference<>(executor);
+ mCallback = callback;
+ mExecutor = executor;
}
@Override
public void onTranslationResponse(TranslationResponse response) throws RemoteException {
- final Consumer<TranslationResponse> callback = mCallback.get();
+ if (DEBUG) {
+ Log.i(TAG, "onTranslationResponse called.");
+ }
final Runnable runnable =
- () -> callback.accept(response);
- if (callback != null) {
- final Executor executor = mExecutor.get();
- final long token = Binder.clearCallingIdentity();
- try {
- executor.execute(runnable);
- } finally {
- restoreCallingIdentity(token);
- }
+ () -> mCallback.accept(response);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(runnable);
+ } finally {
+ restoreCallingIdentity(token);
}
}
}
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index a81439914ea1..1c5b39e8dc16 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -23,6 +23,7 @@ import static android.app.ActivityOptions.ANIM_SCALE_UP;
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_NONE;
@@ -91,8 +92,19 @@ public final class TransitionInfo implements Parcelable {
/** The container is the display. */
public static final int FLAG_IS_DISPLAY = 1 << 5;
+ /** The container can show on top of lock screen. */
+ public static final int FLAG_OCCLUDES_KEYGUARD = 1 << 6;
+
+ /**
+ * Only for IS_DISPLAY containers. Is set if the display has system alert windows. This is
+ * used to prevent seamless rotation.
+ * TODO(b/194540864): Once we can include all windows in transition, then replace this with
+ * something like FLAG_IS_SYSTEM_ALERT instead. Then we can do mixed rotations.
+ */
+ public static final int FLAG_DISPLAY_HAS_ALERT_WINDOWS = 1 << 7;
+
/** The first unused bit. This can be used by remotes to attach custom flags to this change. */
- public static final int FLAG_FIRST_CUSTOM = 1 << 6;
+ public static final int FLAG_FIRST_CUSTOM = 1 << 8;
/** @hide */
@IntDef(prefix = { "FLAG_" }, value = {
@@ -103,6 +115,8 @@ public final class TransitionInfo implements Parcelable {
FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT,
FLAG_IS_VOICE_INTERACTION,
FLAG_IS_DISPLAY,
+ FLAG_OCCLUDES_KEYGUARD,
+ FLAG_DISPLAY_HAS_ALERT_WINDOWS,
FLAG_FIRST_CUSTOM
})
public @interface ChangeFlags {}
@@ -205,6 +219,10 @@ public final class TransitionInfo implements Parcelable {
return mOptions;
}
+ /**
+ * @return the list of {@link Change}s in this transition. The list is sorted top-to-bottom
+ * in Z (meaning index 0 is the top-most container).
+ */
@NonNull
public List<Change> getChanges() {
return mChanges;
@@ -234,7 +252,7 @@ public final class TransitionInfo implements Parcelable {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append("{t=" + transitTypeToString(mType) + " f=" + Integer.toHexString(mFlags)
+ sb.append("{t=" + transitTypeToString(mType) + " f=0x" + Integer.toHexString(mFlags)
+ " ro=" + mRootOffset + " c=[");
for (int i = 0; i < mChanges.size(); ++i) {
if (i > 0) {
@@ -283,6 +301,12 @@ public final class TransitionInfo implements Parcelable {
if ((flags & FLAG_IS_DISPLAY) != 0) {
sb.append((sb.length() == 0 ? "" : "|") + "IS_DISPLAY");
}
+ if ((flags & FLAG_OCCLUDES_KEYGUARD) != 0) {
+ sb.append((sb.length() == 0 ? "" : "|") + "OCCLUDES_KEYGUARD");
+ }
+ if ((flags & FLAG_DISPLAY_HAS_ALERT_WINDOWS) != 0) {
+ sb.append((sb.length() == 0 ? "" : "|") + "DISPLAY_HAS_ALERT_WINDOWS");
+ }
if ((flags & FLAG_FIRST_CUSTOM) != 0) {
sb.append((sb.length() == 0 ? "" : "|") + "FIRST_CUSTOM");
}
@@ -330,6 +354,7 @@ public final class TransitionInfo implements Parcelable {
private ActivityManager.RunningTaskInfo mTaskInfo = null;
private int mStartRotation = ROTATION_UNDEFINED;
private int mEndRotation = ROTATION_UNDEFINED;
+ private int mRotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
public Change(@Nullable WindowContainerToken container, @NonNull SurfaceControl leash) {
mContainer = container;
@@ -349,6 +374,7 @@ public final class TransitionInfo implements Parcelable {
mTaskInfo = in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
mStartRotation = in.readInt();
mEndRotation = in.readInt();
+ mRotationAnimation = in.readInt();
}
/** Sets the parent of this change's container. The parent must be a participant or null. */
@@ -395,6 +421,14 @@ public final class TransitionInfo implements Parcelable {
mEndRotation = end;
}
+ /**
+ * Sets the app-requested animation type for rotation. Will be one of the
+ * ROTATION_ANIMATION_ values in {@link android.view.WindowManager.LayoutParams};
+ */
+ public void setRotationAnimation(int anim) {
+ mRotationAnimation = anim;
+ }
+
/** @return the container that is changing. May be null if non-remotable (eg. activity) */
@Nullable
public WindowContainerToken getContainer() {
@@ -466,6 +500,11 @@ public final class TransitionInfo implements Parcelable {
return mEndRotation;
}
+ /** @return the rotation animation. */
+ public int getRotationAnimation() {
+ return mRotationAnimation;
+ }
+
/** @hide */
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -480,6 +519,7 @@ public final class TransitionInfo implements Parcelable {
dest.writeTypedObject(mTaskInfo, flags);
dest.writeInt(mStartRotation);
dest.writeInt(mEndRotation);
+ dest.writeInt(mRotationAnimation);
}
@NonNull
@@ -507,7 +547,7 @@ public final class TransitionInfo implements Parcelable {
return "{" + mContainer + "(" + mParent + ") leash=" + mLeash
+ " m=" + modeToString(mMode) + " f=" + flagsToString(mFlags) + " sb="
+ mStartAbsBounds + " eb=" + mEndAbsBounds + " eo=" + mEndRelOffset + " r="
- + mStartRotation + "->" + mEndRotation + "}";
+ + mStartRotation + "->" + mEndRotation + ":" + mRotationAnimation + "}";
}
}
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index a735bbc88e36..342df4f9eee3 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -506,15 +506,17 @@ public final class WindowContainerTransaction implements Parcelable {
* {@link #setAdjacentRoots(WindowContainerToken, WindowContainerToken)}, but can be used with
* fragmentTokens when that TaskFragments haven't been created (but will be created in the same
* {@link WindowContainerTransaction}).
+ * To reset it, pass {@code null} for {@code fragmentToken2}.
* @param fragmentToken1 client assigned unique token to create TaskFragment with specified
* in {@link TaskFragmentCreationParams#getFragmentToken()}.
* @param fragmentToken2 client assigned unique token to create TaskFragment with specified
- * in {@link TaskFragmentCreationParams#getFragmentToken()}.
+ * in {@link TaskFragmentCreationParams#getFragmentToken()}. If it is
+ * {@code null}, the transaction will reset the adjacent TaskFragment.
* @hide
*/
@NonNull
public WindowContainerTransaction setAdjacentTaskFragments(
- @NonNull IBinder fragmentToken1, @NonNull IBinder fragmentToken2) {
+ @NonNull IBinder fragmentToken1, @Nullable IBinder fragmentToken2) {
final HierarchyOp hierarchyOp =
new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS)
.setContainer(fragmentToken1)
diff --git a/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl b/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl
index 3a108e7e1d94..06640cb4ee06 100644
--- a/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl
+++ b/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl
@@ -18,5 +18,6 @@ package com.android.internal.app;
// Iterface to observe op starts
oneway interface IAppOpsStartedCallback {
- void opStarted(int op, int uid, String packageName, String attributionTag, int flags, int mode);
+ void opStarted(int op, int uid, String packageName, String attributionTag, int flags, int mode,
+ int startedType, int attributionFlags, int attributionChainId);
}
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 8e7fae7aa061..aa7142eaa39d 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -45,6 +45,7 @@ import android.view.ThreadedRenderer;
import android.view.ViewRootImpl;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.jank.InteractionJankMonitor.Configuration;
import com.android.internal.jank.InteractionJankMonitor.Session;
import com.android.internal.util.FrameworkStatsLog;
@@ -69,6 +70,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
static final int REASON_CANCEL_NORMAL = 16;
static final int REASON_CANCEL_NOT_BEGUN = 17;
static final int REASON_CANCEL_SAME_VSYNC = 18;
+ static final int REASON_CANCEL_TIMEOUT = 19;
/** @hide */
@IntDef({
@@ -97,6 +99,9 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
private final Handler mHandler;
private final ChoreographerWrapper mChoreographer;
+ @VisibleForTesting
+ public final boolean mSurfaceOnly;
+
private long mBeginVsyncId = INVALID_ID;
private long mEndVsyncId = INVALID_ID;
private boolean mMetricsFinalized;
@@ -136,71 +141,86 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
}
public FrameTracker(@NonNull Session session, @NonNull Handler handler,
- @NonNull ThreadedRendererWrapper renderer, @NonNull ViewRootWrapper viewRootWrapper,
+ @Nullable ThreadedRendererWrapper renderer, @Nullable ViewRootWrapper viewRootWrapper,
@NonNull SurfaceControlWrapper surfaceControlWrapper,
@NonNull ChoreographerWrapper choreographer,
- @NonNull FrameMetricsWrapper metrics, int traceThresholdMissedFrames,
- int traceThresholdFrameTimeMillis, @Nullable FrameTrackerListener listener) {
+ @Nullable FrameMetricsWrapper metrics,
+ int traceThresholdMissedFrames, int traceThresholdFrameTimeMillis,
+ @Nullable FrameTrackerListener listener, @NonNull Configuration config) {
+ mSurfaceOnly = config.isSurfaceOnly();
mSession = session;
- mRendererWrapper = renderer;
- mMetricsWrapper = metrics;
- mViewRoot = viewRootWrapper;
+ mHandler = handler;
mChoreographer = choreographer;
mSurfaceControlWrapper = surfaceControlWrapper;
- mHandler = handler;
- mObserver = new HardwareRendererObserver(
- this, mMetricsWrapper.getTiming(), handler, false /*waitForPresentTime*/);
+
+ // HWUI instrumentation init.
+ mRendererWrapper = mSurfaceOnly ? null : renderer;
+ mMetricsWrapper = mSurfaceOnly ? null : metrics;
+ mViewRoot = mSurfaceOnly ? null : viewRootWrapper;
+ mObserver = mSurfaceOnly
+ ? null
+ : new HardwareRendererObserver(this, mMetricsWrapper.getTiming(),
+ handler, /* waitForPresentTime= */ false);
+
mTraceThresholdMissedFrames = traceThresholdMissedFrames;
mTraceThresholdFrameTimeMillis = traceThresholdFrameTimeMillis;
mListener = listener;
- // If the surface isn't valid yet, wait until it's created.
- if (viewRootWrapper.getSurfaceControl().isValid()) {
- mSurfaceControl = viewRootWrapper.getSurfaceControl();
- }
- mSurfaceChangedCallback = new ViewRootImpl.SurfaceChangedCallback() {
- @Override
- public void surfaceCreated(SurfaceControl.Transaction t) {
- synchronized (FrameTracker.this) {
- if (mSurfaceControl == null) {
- mSurfaceControl = viewRootWrapper.getSurfaceControl();
- if (mBeginVsyncId != INVALID_ID) {
- mSurfaceControlWrapper.addJankStatsListener(
- FrameTracker.this, mSurfaceControl);
- postTraceStartMarker();
+ if (mSurfaceOnly) {
+ mSurfaceControl = config.getSurfaceControl();
+ mSurfaceChangedCallback = null;
+ } else {
+ // HWUI instrumentation init.
+ // If the surface isn't valid yet, wait until it's created.
+ if (mViewRoot.getSurfaceControl().isValid()) {
+ mSurfaceControl = mViewRoot.getSurfaceControl();
+ mSurfaceChangedCallback = null;
+ } else {
+ mSurfaceChangedCallback = new ViewRootImpl.SurfaceChangedCallback() {
+ @Override
+ public void surfaceCreated(SurfaceControl.Transaction t) {
+ synchronized (FrameTracker.this) {
+ if (mSurfaceControl == null) {
+ mSurfaceControl = mViewRoot.getSurfaceControl();
+ if (mBeginVsyncId != INVALID_ID) {
+ mSurfaceControlWrapper.addJankStatsListener(
+ FrameTracker.this, mSurfaceControl);
+ postTraceStartMarker();
+ }
+ }
}
}
- }
- }
- @Override
- public void surfaceReplaced(SurfaceControl.Transaction t) {
- }
+ @Override
+ public void surfaceReplaced(SurfaceControl.Transaction t) {
+ }
- @Override
- public void surfaceDestroyed() {
-
- // Wait a while to give the system a chance for the remaining frames to arrive, then
- // force finish the session.
- mHandler.postDelayed(() -> {
- synchronized (FrameTracker.this) {
- if (DEBUG) {
- Log.d(TAG, "surfaceDestroyed: " + mSession.getName()
- + ", finalized=" + mMetricsFinalized
- + ", info=" + mJankInfos.size()
- + ", vsync=" + mBeginVsyncId + "-" + mEndVsyncId);
- }
- if (!mMetricsFinalized) {
- end(REASON_END_SURFACE_DESTROYED);
- finish(mJankInfos.size() - 1);
- }
+ @Override
+ public void surfaceDestroyed() {
+
+ // Wait a while to give the system a chance for the remaining
+ // frames to arrive, then force finish the session.
+ mHandler.postDelayed(() -> {
+ synchronized (FrameTracker.this) {
+ if (DEBUG) {
+ Log.d(TAG, "surfaceDestroyed: " + mSession.getName()
+ + ", finalized=" + mMetricsFinalized
+ + ", info=" + mJankInfos.size()
+ + ", vsync=" + mBeginVsyncId + "-" + mEndVsyncId);
+ }
+ if (!mMetricsFinalized) {
+ end(REASON_END_SURFACE_DESTROYED);
+ finish(mJankInfos.size() - 1);
+ }
+ }
+ }, 50);
}
- }, 50);
+ };
+ // This callback has a reference to FrameTracker,
+ // remember to remove it to avoid leakage.
+ mViewRoot.addSurfaceChangedCallback(mSurfaceChangedCallback);
}
- };
-
- // This callback has a reference to FrameTracker, remember to remove it to avoid leakage.
- viewRootWrapper.addSurfaceChangedCallback(mSurfaceChangedCallback);
+ }
}
/**
@@ -208,16 +228,16 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
*/
public synchronized void begin() {
mBeginVsyncId = mChoreographer.getVsyncId() + 1;
- if (mSurfaceControl != null) {
- postTraceStartMarker();
- }
- mRendererWrapper.addObserver(mObserver);
if (DEBUG) {
Log.d(TAG, "begin: " + mSession.getName() + ", begin=" + mBeginVsyncId);
}
if (mSurfaceControl != null) {
+ postTraceStartMarker();
mSurfaceControlWrapper.addJankStatsListener(this, mSurfaceControl);
}
+ if (!mSurfaceOnly) {
+ mRendererWrapper.addObserver(mObserver);
+ }
if (mListener != null) {
mListener.onCujEvents(mSession, ACTION_SESSION_BEGIN);
}
@@ -273,11 +293,12 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
* Cancel the trace session of the CUJ.
*/
public synchronized void cancel(@Reasons int reason) {
+ mCancelled = true;
+
// We don't need to end the trace section if it never begun.
if (mTracingStarted) {
Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
}
- mCancelled = true;
// Always remove the observers in cancel call to avoid leakage.
removeObservers();
@@ -377,7 +398,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
for (int i = mJankInfos.size() - 1; i >= 0; i--) {
JankInfo info = mJankInfos.valueAt(i);
if (info.frameVsyncId >= mEndVsyncId) {
- if (info.hwuiCallbackFired && info.surfaceControlCallbackFired) {
+ if (isLastIndexCandidate(info)) {
lastIndex = i;
}
} else {
@@ -395,6 +416,12 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
finish(indexOnOrAfterEnd);
}
+ private boolean isLastIndexCandidate(JankInfo info) {
+ return mSurfaceOnly
+ ? info.surfaceControlCallbackFired
+ : info.hwuiCallbackFired && info.surfaceControlCallbackFired;
+ }
+
private void finish(int indexOnOrAfterEnd) {
mMetricsFinalized = true;
@@ -410,7 +437,8 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
for (int i = 0; i <= indexOnOrAfterEnd; i++) {
JankInfo info = mJankInfos.valueAt(i);
- if (info.isFirstFrame) {
+ final boolean isFirstDrawn = !mSurfaceOnly && info.isFirstFrame;
+ if (isFirstDrawn) {
continue;
}
if (info.surfaceControlCallbackFired) {
@@ -435,11 +463,11 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
}
// TODO (b/174755489): Early latch currently gets fired way too often, so we have
// to ignore it for now.
- if (!info.hwuiCallbackFired) {
+ if (!mSurfaceOnly && !info.hwuiCallbackFired) {
Log.w(TAG, "Missing HWUI jank callback for vsyncId: " + info.frameVsyncId);
}
}
- if (info.hwuiCallbackFired) {
+ if (!mSurfaceOnly && info.hwuiCallbackFired) {
maxFrameTimeNanos = Math.max(info.totalDurationNanos, maxFrameTimeNanos);
if (!info.surfaceControlCallbackFired) {
Log.w(TAG, "Missing SF jank callback for vsyncId: " + info.frameVsyncId);
@@ -462,7 +490,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
// Trigger perfetto if necessary.
boolean overMissedFramesThreshold = mTraceThresholdMissedFrames != -1
&& missedFramesCount >= mTraceThresholdMissedFrames;
- boolean overFrameTimeThreshold = mTraceThresholdFrameTimeMillis != -1
+ boolean overFrameTimeThreshold = !mSurfaceOnly && mTraceThresholdFrameTimeMillis != -1
&& maxFrameTimeNanos >= mTraceThresholdFrameTimeMillis * NANOS_IN_MILLISECOND;
if (overMissedFramesThreshold || overFrameTimeThreshold) {
triggerPerfetto();
@@ -473,7 +501,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
mSession.getStatsdInteractionType(),
totalFramesCount,
missedFramesCount,
- maxFrameTimeNanos,
+ maxFrameTimeNanos, /* will be 0 if mSurfaceOnly == true */
missedSfFramesCount,
missedAppFramesCount);
if (mListener != null) {
@@ -496,10 +524,13 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
*/
@VisibleForTesting
public void removeObservers() {
- mRendererWrapper.removeObserver(mObserver);
mSurfaceControlWrapper.removeJankStatsListener(this);
- if (mSurfaceChangedCallback != null) {
- mViewRoot.removeSurfaceChangedCallback(mSurfaceChangedCallback);
+ if (!mSurfaceOnly) {
+ // HWUI part.
+ mRendererWrapper.removeObserver(mObserver);
+ if (mSurfaceChangedCallback != null) {
+ mViewRoot.removeSurfaceChangedCallback(mSurfaceChangedCallback);
+ }
}
}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index aabcd7f82ac7..aae6f5016891 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -18,11 +18,11 @@ package com.android.internal.jank;
import static android.content.Intent.FLAG_RECEIVER_REGISTERED_ONLY;
-import static com.android.internal.jank.FrameTracker.ChoreographerWrapper;
import static com.android.internal.jank.FrameTracker.REASON_CANCEL_NORMAL;
import static com.android.internal.jank.FrameTracker.REASON_CANCEL_NOT_BEGUN;
+import static com.android.internal.jank.FrameTracker.REASON_CANCEL_TIMEOUT;
import static com.android.internal.jank.FrameTracker.REASON_END_NORMAL;
-import static com.android.internal.jank.FrameTracker.SurfaceControlWrapper;
+import static com.android.internal.jank.FrameTracker.REASON_END_UNKNOWN;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_PIP;
@@ -41,6 +41,7 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_TRANSITION_TO_AOD;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_UNLOCK_ANIMATION;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PIP_TRANSITION;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_PAGE_SCROLL;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON;
@@ -58,6 +59,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_ROW_SWIPE;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_SCROLL_FLING;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -72,11 +74,15 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import android.view.Choreographer;
+import android.view.SurfaceControl;
import android.view.View;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.jank.FrameTracker.ChoreographerWrapper;
import com.android.internal.jank.FrameTracker.FrameMetricsWrapper;
import com.android.internal.jank.FrameTracker.FrameTrackerListener;
+import com.android.internal.jank.FrameTracker.Reasons;
+import com.android.internal.jank.FrameTracker.SurfaceControlWrapper;
import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper;
import com.android.internal.jank.FrameTracker.ViewRootWrapper;
import com.android.internal.util.PerfettoTrigger;
@@ -103,7 +109,7 @@ public class InteractionJankMonitor {
private static final String ACTION_PREFIX = InteractionJankMonitor.class.getCanonicalName();
private static final String DEFAULT_WORKER_NAME = TAG + "-Worker";
- private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5L);
+ private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(2L);
private static final String SETTINGS_ENABLED_KEY = "enabled";
private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval";
private static final String SETTINGS_THRESHOLD_MISSED_FRAMES_KEY =
@@ -163,6 +169,8 @@ public class InteractionJankMonitor {
public static final int CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE = 32;
public static final int CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON = 33;
public static final int CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP = 34;
+ public static final int CUJ_PIP_TRANSITION = 35;
+ public static final int CUJ_WALLPAPER_TRANSITION = 36;
private static final int NO_STATSD_LOGGING = -1;
@@ -206,6 +214,8 @@ public class InteractionJankMonitor {
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_QS_TILE,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PIP_TRANSITION,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION,
};
private static volatile InteractionJankMonitor sInstance;
@@ -213,10 +223,10 @@ public class InteractionJankMonitor {
private final DeviceConfig.OnPropertiesChangedListener mPropertiesChangedListener =
this::updateProperties;
- private FrameMetricsWrapper mMetrics;
- private SparseArray<FrameTracker> mRunningTrackers;
- private SparseArray<Runnable> mTimeoutActions;
- private HandlerThread mWorker;
+ private final FrameMetricsWrapper mMetrics;
+ private final SparseArray<FrameTracker> mRunningTrackers;
+ private final SparseArray<Runnable> mTimeoutActions;
+ private final HandlerThread mWorker;
private boolean mEnabled = DEFAULT_ENABLED;
private int mSamplingInterval = DEFAULT_SAMPLING_INTERVAL;
@@ -260,6 +270,8 @@ public class InteractionJankMonitor {
CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE,
CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON,
CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP,
+ CUJ_PIP_TRANSITION,
+ CUJ_WALLPAPER_TRANSITION,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
@@ -310,24 +322,31 @@ public class InteractionJankMonitor {
}
/**
- * Create a {@link FrameTracker} instance.
+ * Creates a {@link FrameTracker} instance.
*
+ * @param config the config used in instrumenting
* @param session the session associates with this tracker
* @return instance of the FrameTracker
*/
@VisibleForTesting
- public FrameTracker createFrameTracker(Configuration conf, Session session) {
- final View v = conf.mView;
- final Context c = v.getContext().getApplicationContext();
- final ThreadedRendererWrapper r = new ThreadedRendererWrapper(v.getThreadedRenderer());
- final ViewRootWrapper vr = new ViewRootWrapper(v.getViewRootImpl());
- final SurfaceControlWrapper sc = new SurfaceControlWrapper();
- final ChoreographerWrapper cg = new ChoreographerWrapper(Choreographer.getInstance());
+ public FrameTracker createFrameTracker(Configuration config, Session session) {
+ final View view = config.mView;
+ final ThreadedRendererWrapper threadedRenderer =
+ view == null ? null : new ThreadedRendererWrapper(view.getThreadedRenderer());
+ final ViewRootWrapper viewRoot =
+ view == null ? null : new ViewRootWrapper(view.getViewRootImpl());
+
+ final SurfaceControlWrapper surfaceControl = new SurfaceControlWrapper();
+ final ChoreographerWrapper choreographer =
+ new ChoreographerWrapper(Choreographer.getInstance());
synchronized (this) {
- FrameTrackerListener eventsListener = (s, act) -> handleCujEvents(c, act, s);
- return new FrameTracker(session, mWorker.getThreadHandler(), r, vr, sc, cg, mMetrics,
- mTraceThresholdMissedFrames, mTraceThresholdFrameTimeMillis, eventsListener);
+ FrameTrackerListener eventsListener =
+ (s, act) -> handleCujEvents(config.getContext(), act, s);
+ return new FrameTracker(session, mWorker.getThreadHandler(),
+ threadedRenderer, viewRoot, surfaceControl, choreographer, mMetrics,
+ mTraceThresholdMissedFrames, mTraceThresholdFrameTimeMillis,
+ eventsListener, config);
}
}
@@ -376,7 +395,7 @@ public class InteractionJankMonitor {
}
/**
- * Begin a trace session.
+ * Begins a trace session.
*
* @param v an attached view.
* @param cujType the specific {@link InteractionJankMonitor.CujType}.
@@ -385,8 +404,7 @@ public class InteractionJankMonitor {
public boolean begin(View v, @CujType int cujType) {
try {
return beginInternal(
- new Configuration.Builder(cujType)
- .setView(v)
+ Configuration.Builder.withView(cujType, v)
.build());
} catch (IllegalArgumentException ex) {
Log.d(TAG, "Build configuration failed!", ex);
@@ -395,7 +413,7 @@ public class InteractionJankMonitor {
}
/**
- * Begin a trace session.
+ * Begins a trace session.
*
* @param builder the builder of the configurations for instrumenting the CUJ.
* @return boolean true if the tracker is started successfully, false otherwise.
@@ -431,48 +449,60 @@ public class InteractionJankMonitor {
tracker.begin();
// Cancel the trace if we don't get an end() call in specified duration.
- Runnable timeoutAction = () -> cancel(cujType);
- mTimeoutActions.put(cujType, timeoutAction);
- mWorker.getThreadHandler().postDelayed(timeoutAction, conf.mTimeout);
+ scheduleTimeoutAction(
+ cujType, conf.mTimeout, () -> cancel(cujType, REASON_CANCEL_TIMEOUT));
return true;
}
}
/**
- * End a trace session.
+ * Schedules a timeout action.
+ * @param cuj cuj type
+ * @param timeout duration to timeout
+ * @param action action once timeout
+ */
+ @VisibleForTesting
+ public void scheduleTimeoutAction(@CujType int cuj, long timeout, Runnable action) {
+ mTimeoutActions.put(cuj, action);
+ mWorker.getThreadHandler().postDelayed(action, timeout);
+ }
+
+ /**
+ * Ends a trace session.
*
* @param cujType the specific {@link InteractionJankMonitor.CujType}.
* @return boolean true if the tracker is ended successfully, false otherwise.
*/
public boolean end(@CujType int cujType) {
- //TODO (163505250): This should be no-op if not in droid food rom.
synchronized (this) {
-
// remove the timeout action first.
removeTimeout(cujType);
FrameTracker tracker = getTracker(cujType);
// Skip this call since we haven't started a trace yet.
if (tracker == null) return false;
- tracker.end(FrameTracker.REASON_END_NORMAL);
+ tracker.end(REASON_END_NORMAL);
removeTracker(cujType);
return true;
}
}
/**
- * Cancel the trace session.
+ * Cancels the trace session.
*
* @return boolean true if the tracker is cancelled successfully, false otherwise.
*/
public boolean cancel(@CujType int cujType) {
- //TODO (163505250): This should be no-op if not in droid food rom.
+ return cancel(cujType, REASON_CANCEL_NORMAL);
+ }
+
+ boolean cancel(@CujType int cujType, @Reasons int reason) {
synchronized (this) {
// remove the timeout action first.
removeTimeout(cujType);
FrameTracker tracker = getTracker(cujType);
// Skip this call since we haven't started a trace yet.
if (tracker == null) return false;
- tracker.cancel(FrameTracker.REASON_CANCEL_NORMAL);
+ tracker.cancel(reason);
removeTracker(cujType);
return true;
}
@@ -509,7 +539,7 @@ public class InteractionJankMonitor {
}
/**
- * Trigger the perfetto daemon to collect and upload data.
+ * Triggers the perfetto daemon to collect and upload data.
*/
@VisibleForTesting
public void trigger(Session session) {
@@ -608,6 +638,10 @@ public class InteractionJankMonitor {
return "SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON";
case CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP:
return "STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP";
+ case CUJ_PIP_TRANSITION:
+ return "PIP_TRANSITION";
+ case CUJ_WALLPAPER_TRANSITION:
+ return "WALLPAPER_TRANSITION";
}
return "UNKNOWN";
}
@@ -618,32 +652,64 @@ public class InteractionJankMonitor {
*/
public static class Configuration {
private final View mView;
+ private final Context mContext;
private final long mTimeout;
private final String mTag;
+ private final boolean mSurfaceOnly;
+ private final SurfaceControl mSurfaceControl;
private final @CujType int mCujType;
/**
- * A builder for building Configuration. <br/>
+ * A builder for building Configuration. {@link #setView(View)} is essential
+ * if {@link #setSurfaceOnly(boolean)} is not set, otherwise both
+ * {@link #setSurfaceControl(SurfaceControl)} and {@link #setContext(Context)}
+ * are necessary<br/>
* <b>It may refer to an attached view, don't use static reference for any purpose.</b>
*/
public static class Builder {
private View mAttrView = null;
+ private Context mAttrContext = null;
private long mAttrTimeout = DEFAULT_TIMEOUT_MS;
private String mAttrTag = "";
+ private boolean mAttrSurfaceOnly;
+ private SurfaceControl mAttrSurfaceControl;
private @CujType int mAttrCujType;
/**
+ * Creates a builder which instruments only surface.
* @param cuj The enum defined in {@link InteractionJankMonitor.CujType}.
+ * @param context context
+ * @param surfaceControl surface control
+ * @return builder
*/
- public Builder(@CujType int cuj) {
+ public static Builder withSurface(@CujType int cuj, @NonNull Context context,
+ @NonNull SurfaceControl surfaceControl) {
+ return new Builder(cuj)
+ .setContext(context)
+ .setSurfaceControl(surfaceControl)
+ .setSurfaceOnly(true);
+ }
+
+ /**
+ * Creates a builder which instruments both surface and view.
+ * @param cuj The enum defined in {@link InteractionJankMonitor.CujType}.
+ * @param view view
+ * @return builder
+ */
+ public static Builder withView(@CujType int cuj, @NonNull View view) {
+ return new Builder(cuj).setView(view);
+ }
+
+ private Builder(@CujType int cuj) {
mAttrCujType = cuj;
}
/**
+ * Specifies a view, must be set if {@link #setSurfaceOnly(boolean)} is set to false.
* @param view an attached view
* @return builder
*/
- public Builder setView(@NonNull View view) {
+ private Builder setView(@NonNull View view) {
mAttrView = view;
return this;
}
@@ -669,20 +735,56 @@ public class InteractionJankMonitor {
}
/**
- * Build the {@link Configuration} instance
+ * Indicates if only instrument with surface,
+ * if true, must also setup with {@link #setContext(Context)}
+ * and {@link #setSurfaceControl(SurfaceControl)}.
+ * @param surfaceOnly true if only instrument with surface, false otherwise
+ * @return builder Surface only builder.
+ */
+ private Builder setSurfaceOnly(boolean surfaceOnly) {
+ mAttrSurfaceOnly = surfaceOnly;
+ return this;
+ }
+
+ /**
+ * Specifies a context, must set if {@link #setSurfaceOnly(boolean)} is set.
+ */
+ private Builder setContext(Context context) {
+ mAttrContext = context;
+ return this;
+ }
+
+ /**
+ * Specifies a surface control, must be set if {@link #setSurfaceOnly(boolean)} is set.
+ */
+ private Builder setSurfaceControl(SurfaceControl surfaceControl) {
+ mAttrSurfaceControl = surfaceControl;
+ return this;
+ }
+
+ /**
+ * Builds the {@link Configuration} instance
* @return the instance of {@link Configuration}
* @throws IllegalArgumentException if any invalid attribute is set
*/
public Configuration build() throws IllegalArgumentException {
- return new Configuration(mAttrCujType, mAttrView, mAttrTag, mAttrTimeout);
+ return new Configuration(
+ mAttrCujType, mAttrView, mAttrTag, mAttrTimeout,
+ mAttrSurfaceOnly, mAttrContext, mAttrSurfaceControl);
}
}
- private Configuration(@CujType int cuj, View view, String tag, long timeout) {
+ private Configuration(@CujType int cuj, View view, String tag, long timeout,
+ boolean surfaceOnly, Context context, SurfaceControl surfaceControl) {
mCujType = cuj;
mTag = tag;
mTimeout = timeout;
mView = view;
+ mSurfaceOnly = surfaceOnly;
+ mContext = context != null
+ ? context
+ : (view != null ? view.getContext().getApplicationContext() : null);
+ mSurfaceControl = surfaceControl;
validate();
}
@@ -698,14 +800,47 @@ public class InteractionJankMonitor {
shouldThrow = true;
msg.append("Invalid timeout value; ");
}
- if (mView == null || !mView.isAttachedToWindow()) {
- shouldThrow = true;
- msg.append("Null view or view is not attached yet; ");
+ if (mSurfaceOnly) {
+ if (mContext == null) {
+ shouldThrow = true;
+ msg.append("Must pass in a context if only instrument surface; ");
+ }
+ if (mSurfaceControl == null || !mSurfaceControl.isValid()) {
+ shouldThrow = true;
+ msg.append("Must pass in a valid surface control if only instrument surface; ");
+ }
+ } else {
+ if (mView == null || !mView.isAttachedToWindow()) {
+ shouldThrow = true;
+ msg.append("Null view or unattached view while instrumenting view; ");
+ }
}
if (shouldThrow) {
throw new IllegalArgumentException(msg.toString());
}
}
+
+ /**
+ * @return true if only instrumenting surface, false otherwise
+ */
+ public boolean isSurfaceOnly() {
+ return mSurfaceOnly;
+ }
+
+ /**
+ * @return the surafce control which is instrumenting
+ */
+ public SurfaceControl getSurfaceControl() {
+ return mSurfaceControl;
+ }
+
+ View getView() {
+ return mView;
+ }
+
+ Context getContext() {
+ return mContext;
+ }
}
/**
@@ -715,8 +850,8 @@ public class InteractionJankMonitor {
@CujType
private final int mCujType;
private final long mTimeStamp;
- @FrameTracker.Reasons
- private int mReason = FrameTracker.REASON_END_UNKNOWN;
+ @Reasons
+ private int mReason = REASON_END_UNKNOWN;
private final boolean mShouldNotify;
private final String mName;
@@ -756,15 +891,15 @@ public class InteractionJankMonitor {
return mTimeStamp;
}
- public void setReason(@FrameTracker.Reasons int reason) {
+ public void setReason(@Reasons int reason) {
mReason = reason;
}
- public int getReason() {
+ public @Reasons int getReason() {
return mReason;
}
- /** Determine if should notify the receivers of cuj events */
+ /** Determines if should notify the receivers of cuj events */
public boolean shouldNotify() {
return mShouldNotify;
}
diff --git a/core/java/com/android/internal/os/ProcLocksReader.java b/core/java/com/android/internal/os/ProcLocksReader.java
new file mode 100644
index 000000000000..bd3115fc5d4c
--- /dev/null
+++ b/core/java/com/android/internal/os/ProcLocksReader.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import com.android.internal.util.ProcFileReader;
+
+import libcore.io.IoUtils;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+
+/**
+ * Reads and parses {@code locks} files in the {@code proc} filesystem.
+ * A typical example of /proc/locks
+ *
+ * 1: POSIX ADVISORY READ 18403 fd:09:9070 1073741826 1073742335
+ * 2: POSIX ADVISORY WRITE 18292 fd:09:34062 0 EOF
+ * 2: -> POSIX ADVISORY WRITE 18291 fd:09:34062 0 EOF
+ * 2: -> POSIX ADVISORY WRITE 18293 fd:09:34062 0 EOF
+ * 3: POSIX ADVISORY READ 3888 fd:09:13992 128 128
+ * 4: POSIX ADVISORY READ 3888 fd:09:14230 1073741826 1073742335
+ */
+public class ProcLocksReader {
+ private final String mPath;
+
+ public ProcLocksReader() {
+ mPath = "/proc/locks";
+ }
+
+ public ProcLocksReader(String path) {
+ mPath = path;
+ }
+
+ /**
+ * Checks if a process corresponding to a specific pid owns any file locks.
+ * @param pid The process ID for which we want to know the existence of file locks.
+ * @return true If the process holds any file locks, false otherwise.
+ * @throws IOException if /proc/locks can't be accessed.
+ */
+ public boolean hasFileLocks(int pid) throws Exception {
+ ProcFileReader reader = null;
+ long last = -1;
+ long id; // ordinal position of the lock in the list
+ int owner; // the PID of the process that owns the lock
+
+ try {
+ reader = new ProcFileReader(new FileInputStream(mPath));
+
+ while (reader.hasMoreData()) {
+ id = reader.nextLong(true); // lock id
+ if (id == last) {
+ reader.finishLine(); // blocked lock
+ continue;
+ }
+
+ reader.nextIgnored(); // lock type: POSIX?
+ reader.nextIgnored(); // lock type: MANDATORY?
+ reader.nextIgnored(); // lock type: RW?
+
+ owner = reader.nextInt(); // pid
+ if (owner == pid) {
+ return true;
+ }
+ reader.finishLine();
+ last = id;
+ }
+ } catch (IOException e) {
+ // TODO: let ProcFileReader log the failed line
+ throw new Exception("Exception parsing /proc/locks");
+ } finally {
+ IoUtils.closeQuietly(reader);
+ }
+ return false;
+ }
+}
diff --git a/core/java/com/android/internal/util/ProcFileReader.java b/core/java/com/android/internal/util/ProcFileReader.java
index ead58c7de611..0dd8ad89df61 100644
--- a/core/java/com/android/internal/util/ProcFileReader.java
+++ b/core/java/com/android/internal/util/ProcFileReader.java
@@ -28,8 +28,8 @@ import java.nio.charset.StandardCharsets;
* requires each line boundary to be explicitly acknowledged using
* {@link #finishLine()}. Assumes {@link StandardCharsets#US_ASCII} encoding.
* <p>
- * Currently doesn't support formats based on {@code \0}, tabs, or repeated
- * delimiters.
+ * Currently doesn't support formats based on {@code \0}, tabs.
+ * Consecutive spaces are treated as a single delimiter.
*/
public class ProcFileReader implements Closeable {
private final InputStream mStream;
@@ -75,6 +75,11 @@ public class ProcFileReader implements Closeable {
private void consumeBuf(int count) throws IOException {
// TODO: consider moving to read pointer, but for now traceview says
// these copies aren't a bottleneck.
+
+ // skip all consecutive delimiters.
+ while (count < mTail && mBuffer[count] == ' ') {
+ count++;
+ }
System.arraycopy(mBuffer, count, mBuffer, 0, mTail - count);
mTail -= count;
if (mTail == 0) {
@@ -159,11 +164,18 @@ public class ProcFileReader implements Closeable {
* Parse and return next token as base-10 encoded {@code long}.
*/
public long nextLong() throws IOException {
+ return nextLong(false);
+ }
+
+ /**
+ * Parse and return next token as base-10 encoded {@code long}.
+ */
+ public long nextLong(boolean stopAtInvalid) throws IOException {
final int tokenIndex = nextTokenIndex();
if (tokenIndex == -1) {
throw new ProtocolException("Missing required long");
} else {
- return parseAndConsumeLong(tokenIndex);
+ return parseAndConsumeLong(tokenIndex, stopAtInvalid);
}
}
@@ -176,7 +188,7 @@ public class ProcFileReader implements Closeable {
if (tokenIndex == -1) {
return def;
} else {
- return parseAndConsumeLong(tokenIndex);
+ return parseAndConsumeLong(tokenIndex, false);
}
}
@@ -186,7 +198,10 @@ public class ProcFileReader implements Closeable {
return s;
}
- private long parseAndConsumeLong(int tokenIndex) throws IOException {
+ /**
+ * If stopAtInvalid is true, don't throw IOException but return whatever parsed so far.
+ */
+ private long parseAndConsumeLong(int tokenIndex, boolean stopAtInvalid) throws IOException {
final boolean negative = mBuffer[0] == '-';
// TODO: refactor into something like IntegralToString
@@ -194,7 +209,11 @@ public class ProcFileReader implements Closeable {
for (int i = negative ? 1 : 0; i < tokenIndex; i++) {
final int digit = mBuffer[i] - '0';
if (digit < 0 || digit > 9) {
- throw invalidLong(tokenIndex);
+ if (stopAtInvalid) {
+ break;
+ } else {
+ throw invalidLong(tokenIndex);
+ }
}
// always parse as negative number and apply sign later; this
@@ -226,6 +245,18 @@ public class ProcFileReader implements Closeable {
return (int) value;
}
+ /**
+ * Bypass the next token.
+ */
+ public void nextIgnored() throws IOException {
+ final int tokenIndex = nextTokenIndex();
+ if (tokenIndex == -1) {
+ throw new ProtocolException("Missing required token");
+ } else {
+ consumeBuf(tokenIndex + 1);
+ }
+ }
+
@Override
public void close() throws IOException {
mStream.close();
diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp
index b46b5a23e3fb..d4ae6d769cf7 100644
--- a/core/jni/android_graphics_BLASTBufferQueue.cpp
+++ b/core/jni/android_graphics_BLASTBufferQueue.cpp
@@ -105,9 +105,11 @@ static void nativeSetNextTransaction(JNIEnv* env, jclass clazz, jlong ptr, jlong
}
static void nativeUpdate(JNIEnv* env, jclass clazz, jlong ptr, jlong surfaceControl, jlong width,
- jlong height, jint format) {
+ jlong height, jint format, jlong transactionPtr) {
sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
- queue->update(reinterpret_cast<SurfaceControl*>(surfaceControl), width, height, format);
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionPtr);
+ queue->update(reinterpret_cast<SurfaceControl*>(surfaceControl), width, height, format,
+ transaction);
}
static void nativeFlushShadowQueue(JNIEnv* env, jclass clazz, jlong ptr) {
@@ -144,7 +146,7 @@ static const JNINativeMethod gMethods[] = {
{"nativeGetSurface", "(JZ)Landroid/view/Surface;", (void*)nativeGetSurface},
{"nativeDestroy", "(J)V", (void*)nativeDestroy},
{"nativeSetNextTransaction", "(JJ)V", (void*)nativeSetNextTransaction},
- {"nativeUpdate", "(JJJJI)V", (void*)nativeUpdate},
+ {"nativeUpdate", "(JJJJIJ)V", (void*)nativeUpdate},
{"nativeFlushShadowQueue", "(J)V", (void*)nativeFlushShadowQueue},
{"nativeMergeWithNextTransaction", "(JJJ)V", (void*)nativeMergeWithNextTransaction},
{"nativeSetTransactionCompleteCallback",
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 29c03b3b1185..47db3547f931 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2430,6 +2430,12 @@ android_media_AudioSystem_setAssistantUid(JNIEnv *env, jobject thiz, jint uid)
return (jint)nativeToJavaStatus(status);
}
+static jint android_media_AudioSystem_setHotwordDetectionServiceUid(JNIEnv *env, jobject thiz,
+ jint uid) {
+ status_t status = AudioSystem::setHotwordDetectionServiceUid(uid);
+ return (jint)nativeToJavaStatus(status);
+}
+
static jint
android_media_AudioSystem_setA11yServicesUids(JNIEnv *env, jobject thiz, jintArray uids) {
std::vector<uid_t> nativeUidsVector;
@@ -2802,6 +2808,8 @@ static const JNINativeMethod gMethods[] =
{"setSurroundFormatEnabled", "(IZ)I",
(void *)android_media_AudioSystem_setSurroundFormatEnabled},
{"setAssistantUid", "(I)I", (void *)android_media_AudioSystem_setAssistantUid},
+ {"setHotwordDetectionServiceUid", "(I)I",
+ (void *)android_media_AudioSystem_setHotwordDetectionServiceUid},
{"setA11yServicesUids", "([I)I", (void *)android_media_AudioSystem_setA11yServicesUids},
{"isHapticPlaybackSupported", "()Z",
(void *)android_media_AudioSystem_isHapticPlaybackSupported},
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 95c24ad4a115..17044523cf08 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -550,6 +550,8 @@
<protected-broadcast android:name="com.android.server.telecom.intent.action.CALLS_ADD_ENTRY" />
<protected-broadcast android:name="com.android.settings.location.MODE_CHANGING" />
<protected-broadcast android:name="com.android.settings.bluetooth.ACTION_DISMISS_PAIRING" />
+ <protected-broadcast android:name="com.android.settings.network.DELETE_SUBSCRIPTION" />
+ <protected-broadcast android:name="com.android.settings.network.SWITCH_TO_SUBSCRIPTION" />
<protected-broadcast android:name="com.android.settings.wifi.action.NETWORK_REQUEST" />
<protected-broadcast android:name="NotificationManagerService.TIMEOUT" />
@@ -3466,6 +3468,13 @@
<permission android:name="android.permission.TRIGGER_SHELL_BUGREPORT"
android:protectionLevel="signature" />
+ <!-- Allows an application to trigger profcollect report upload via shell.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.TRIGGER_SHELL_PROFCOLLECT_UPLOAD"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to be the status bar. Currently used only by SystemUI.apk
@hide
@SystemApi -->
diff --git a/core/res/res/layout/splash_screen_view.xml b/core/res/res/layout/splash_screen_view.xml
index aa050f3a364d..2b9f95227f08 100644
--- a/core/res/res/layout/splash_screen_view.xml
+++ b/core/res/res/layout/splash_screen_view.xml
@@ -26,6 +26,7 @@
android:layout_width="wrap_content"
android:layout_gravity="center"
android:padding="0dp"
+ android:background="@null"
android:contentDescription="@string/splash_screen_view_icon_description"/>
<View android:id="@+id/splashscreen_branding_view"
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index cf2f677dfb35..0310b181398d 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -2079,7 +2079,7 @@
<string name="call_notification_hang_up_action" msgid="9130720590159188131">"قطع الاتصال"</string>
<string name="call_notification_incoming_text" msgid="6143109825406638201">"مكالمة واردة"</string>
<string name="call_notification_ongoing_text" msgid="3880832933933020875">"مكالمة جارية"</string>
- <string name="call_notification_screening_text" msgid="8396931408268940208">"رصد مكالمة واردة"</string>
+ <string name="call_notification_screening_text" msgid="8396931408268940208">"يتم فحص المكالمة الواردة"</string>
<plurals name="selected_count" formatted="false" msgid="3946212171128200491">
<item quantity="zero">تم اختيار <xliff:g id="COUNT_1">%1$d</xliff:g> عنصر</item>
<item quantity="two">تم اختيار عنصرين (<xliff:g id="COUNT_1">%1$d</xliff:g>)</item>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 542387f2047e..865f02663299 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -984,7 +984,7 @@
<string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nMöchtest du diese Seite wirklich verlassen?"</string>
<string name="save_password_label" msgid="9161712335355510035">"Bestätigen"</string>
<string name="double_tap_toast" msgid="7065519579174882778">"Tipp: Zum Vergrößern und Verkleinern doppeltippen"</string>
- <string name="autofill_this_form" msgid="3187132440451621492">"AutoFill"</string>
+ <string name="autofill_this_form" msgid="3187132440451621492">"Automatisches Ausfüllen"</string>
<string name="setup_autofill" msgid="5431369130866618567">"Autom.Ausfüll.konf."</string>
<string name="autofill_window_title" msgid="4379134104008111961">"Mit <xliff:g id="SERVICENAME">%1$s</xliff:g> automatisch ausfüllen"</string>
<string name="autofill_address_name_separator" msgid="8190155636149596125">" "</string>
@@ -1937,7 +1937,7 @@
<string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Phishing-Warnung"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Arbeitsprofil"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Gewarnt"</string>
- <string name="notification_verified_content_description" msgid="6401483602782359391">"Bestätigt"</string>
+ <string name="notification_verified_content_description" msgid="6401483602782359391">"Verifiziert"</string>
<string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Maximieren"</string>
<string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Minimieren"</string>
<string name="expand_action_accessibility" msgid="1947657036871746627">"Maximierung ein-/auschalten"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 9a07025ad760..9a29addc10b0 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -271,7 +271,7 @@
<string name="global_action_settings" msgid="4671878836947494217">"Ajustes"</string>
<string name="global_action_assist" msgid="2517047220311505805">"Asistencia"</string>
<string name="global_action_voice_assist" msgid="6655788068555086695">"Asistente voz"</string>
- <string name="global_action_lockdown" msgid="2475471405907902963">"Bloqueo seguro"</string>
+ <string name="global_action_lockdown" msgid="2475471405907902963">"Bloqueo de seguridad"</string>
<string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"&gt; 999"</string>
<string name="notification_hidden_text" msgid="2835519769868187223">"Notificación nueva"</string>
<string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Teclado virtual"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index f388427acab6..fcca1b39330a 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1949,7 +1949,7 @@
<string name="maximize_button_text" msgid="4258922519914732645">"بزرگ کردن"</string>
<string name="close_button_text" msgid="10603510034455258">"بستن"</string>
<string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>:‏ <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
- <string name="call_notification_answer_action" msgid="5999246836247132937">"پاسخ"</string>
+ <string name="call_notification_answer_action" msgid="5999246836247132937">"پاسخ دادن"</string>
<string name="call_notification_answer_video_action" msgid="2086030940195382249">"ویدیو"</string>
<string name="call_notification_decline_action" msgid="3700345945214000726">"رد کردن"</string>
<string name="call_notification_hang_up_action" msgid="9130720590159188131">"قطع تماس"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 893aedae146d..81be9a7988b0 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -68,7 +68,7 @@
<string name="CnipMmi" msgid="4897531155968151160">"కాలింగ్ నంబర్ అందుబాటులో ఉంది"</string>
<string name="CnirMmi" msgid="885292039284503036">"కాలింగ్ నంబర్ పరిమితం చేయబడింది"</string>
<string name="ThreeWCMmi" msgid="2436550866139999411">"మూడు మార్గాల కాలింగ్"</string>
- <string name="RuacMmi" msgid="1876047385848991110">"అవాంఛిత అంతరాయ కాల్‌ల తిరస్కరణ"</string>
+ <string name="RuacMmi" msgid="1876047385848991110">"అవాంఛిత అంతరాయ కాల్స్‌ల తిరస్కరణ"</string>
<string name="CndMmi" msgid="185136449405618437">"కాలింగ్ నంబర్ బట్వాడా"</string>
<string name="DndMmi" msgid="8797375819689129800">"అంతరాయం కలిగించవద్దు"</string>
<string name="CLIRDefaultOnNextCallOn" msgid="4511621022859867988">"కాలర్ ID డిఫాల్ట్‌గా పరిమితానికి ఉంటుంది. తర్వాత కాల్: పరిమితం చేయబడింది"</string>
@@ -86,7 +86,7 @@
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"మొబైల్ నెట్‌వర్క్ అందుబాటులో లేదు"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ప్రాధాన్య నెట్‌వర్క్‌ను మార్చుకోవడానికి ప్రయత్నించండి. మార్చడానికి నొక్కండి."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"అత్యవసర కాలింగ్ అందుబాటులో లేదు"</string>
- <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Wi-Fiతో అత్యవసర కాల్‌లు చేయలేరు"</string>
+ <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Wi-Fiతో అత్యవసర కాల్స్‌ చేయలేరు"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"అలర్ట్‌లు"</string>
<string name="notification_channel_call_forward" msgid="8230490317314272406">"కాల్ ఫార్వార్డింగ్"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"అత్యవసర కాల్‌బ్యాక్ మోడ్"</string>
@@ -124,7 +124,7 @@
<string name="roamingTextSearching" msgid="5323235489657753486">"సేవ కోసం శోధిస్తోంది"</string>
<string name="wfcRegErrorTitle" msgid="3193072971584858020">"Wi‑Fi కాలింగ్‌ని సెటప్ చేయడం సాధ్యపడలేదు"</string>
<string-array name="wfcOperatorErrorAlertMessages">
- <item msgid="468830943567116703">"Wi-Fiతో కాల్‌లను చేయడానికి మరియు సందేశాలను పంపించడానికి, మొదట ఈ సేవను సెటప్ చేయాల్సిందిగా మీ క్యారియర్‌‌కి చెప్పండి. ఆ తర్వాత సెట్టింగ్‌ల నుండి Wi-Fi కాలింగ్‌ని మళ్లీ ఆన్ చేయండి. (లోపం కోడ్: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
+ <item msgid="468830943567116703">"Wi-Fiతో కాల్స్‌ను చేయడానికి మరియు సందేశాలను పంపించడానికి, మొదట ఈ సేవను సెటప్ చేయాల్సిందిగా మీ క్యారియర్‌‌కి చెప్పండి. ఆ తర్వాత సెట్టింగ్‌ల నుండి Wi-Fi కాలింగ్‌ని మళ్లీ ఆన్ చేయండి. (లోపం కోడ్: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
</string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="4795145070505729156">"మీ క్యారియర్‌తో Wi‑Fi కాలింగ్‌ని నమోదు చేయడంలో సమస్య: <xliff:g id="CODE">%1$s</xliff:g>"</item>
@@ -176,10 +176,10 @@
<string name="contentServiceSync" msgid="2341041749565687871">"సమకాలీకరణ"</string>
<string name="contentServiceSyncNotificationTitle" msgid="5766411446676388623">"సమకాలీకరించడం సాధ్యపడదు"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="4562226280528716090">"చాలా ఎక్కువ <xliff:g id="CONTENT_TYPE">%s</xliff:g> తొలగించడానికి ప్రయత్నించారు."</string>
- <string name="low_memory" product="tablet" msgid="5557552311566179924">"టాబ్లెట్ నిల్వ నిండింది. స్థలాన్ని ఖాళీ చేయడానికి కొన్ని ఫైల్‌లను తొలగించండి."</string>
- <string name="low_memory" product="watch" msgid="3479447988234030194">"వాచ్ నిల్వ నిండింది. స్థలాన్ని ఖాళీ చేయడానికి కొన్ని ఫైల్‌లను తొలగించండి."</string>
+ <string name="low_memory" product="tablet" msgid="5557552311566179924">"టాబ్లెట్ నిల్వ నిండింది. స్థలాన్ని ఖాళీ చేయడానికి కొన్ని ఫైళ్లను తొలగించండి."</string>
+ <string name="low_memory" product="watch" msgid="3479447988234030194">"వాచ్ నిల్వ నిండింది. స్థలాన్ని ఖాళీ చేయడానికి కొన్ని ఫైళ్లను తొలగించండి."</string>
<string name="low_memory" product="tv" msgid="6663680413790323318">"Android TV పరికరం నిల్వ నిండింది. కొంత ప్రదేశాన్ని ఖాళీ చేయడానికి కొన్ని ఫైల్‌‌‌లను తొలగించండి."</string>
- <string name="low_memory" product="default" msgid="2539532364144025569">"ఫోన్ నిల్వ నిండింది. స్థలాన్ని ఖాళీ చేయడానికి కొన్ని ఫైల్‌లను తొలగించండి."</string>
+ <string name="low_memory" product="default" msgid="2539532364144025569">"ఫోన్ నిల్వ నిండింది. స్థలాన్ని ఖాళీ చేయడానికి కొన్ని ఫైళ్లను తొలగించండి."</string>
<plurals name="ssl_ca_cert_warning" formatted="false" msgid="2288194355006173029">
<item quantity="other">ప్రమాణపత్ర అధికారాలు ఇన్‌స్టాల్ చేయబడ్డాయి</item>
<item quantity="one">ప్రమాణపత్ర అధికారం ఇన్‌స్టాల్ చేయబడింది</item>
@@ -311,7 +311,7 @@
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS సందేశాలను పంపడం మరియు వీక్షించడం"</string>
<string name="permgrouplab_storage" msgid="1938416135375282333">"ఫైల్స్, మీడియా"</string>
- <string name="permgroupdesc_storage" msgid="6351503740613026600">"మీ పరికరంలోని ఫోటోలు, మీడియా మరియు ఫైల్‌లను యాక్సెస్ చేయడానికి"</string>
+ <string name="permgroupdesc_storage" msgid="6351503740613026600">"మీ పరికరంలోని ఫోటోలు, మీడియా మరియు ఫైళ్లను యాక్సెస్ చేయడానికి"</string>
<string name="permgrouplab_microphone" msgid="2480597427667420076">"మైక్రోఫోన్"</string>
<string name="permgroupdesc_microphone" msgid="1047786732792487722">"ఆడియోను రికార్డ్ చేయడానికి"</string>
<string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"ఫిజికల్ యాక్టివిటీ"</string>
@@ -323,7 +323,7 @@
<string name="permgrouplab_calllog" msgid="7926834372073550288">"కాల్ లాగ్‌లు"</string>
<string name="permgroupdesc_calllog" msgid="2026996642917801803">"ఫోన్ కాల్ లాగ్‌ని చదవండి మరియు రాయండి"</string>
<string name="permgrouplab_phone" msgid="570318944091926620">"ఫోన్"</string>
- <string name="permgroupdesc_phone" msgid="270048070781478204">"ఫోన్ కాల్‌లు చేయడం మరియు నిర్వహించడం"</string>
+ <string name="permgroupdesc_phone" msgid="270048070781478204">"ఫోన్ కాల్స్‌ చేయడం మరియు నిర్వహించడం"</string>
<string name="permgrouplab_sensors" msgid="9134046949784064495">"శరీర సెన్సార్‌లు"</string>
<string name="permgroupdesc_sensors" msgid="2610631290633747752">"మీ అత్యంత కీలకమైన గుర్తుల గురించి సెన్సార్ డేటాని యాక్సెస్ చేస్తుంది"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"విండో కంటెంట్‍ను తిరిగి పొందుతుంది"</string>
@@ -352,10 +352,10 @@
<string name="permdesc_install_shortcut" msgid="4476328467240212503">"వినియోగదారు ప్రమేయం లేకుండానే హోమ్‌స్క్రీన్ సత్వరమార్గాలను జోడించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_uninstall_shortcut" msgid="295263654781900390">"సత్వరమార్గాలను అన్ఇన్‌స్టాల్ చేయడం"</string>
<string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"వినియోగదారు ప్రమేయం లేకుండానే హోమ్‌స్క్రీన్ సత్వరమార్గాలను తీసివేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
- <string name="permlab_processOutgoingCalls" msgid="4075056020714266558">"అవుట్‌గోయింగ్ కాల్‌లను దారి మళ్లించడం"</string>
+ <string name="permlab_processOutgoingCalls" msgid="4075056020714266558">"అవుట్‌గోయింగ్ కాల్స్‌ను దారి మళ్లించడం"</string>
<string name="permdesc_processOutgoingCalls" msgid="7833149750590606334">"కాల్‌ను వేరే నంబర్‌కు దారి మళ్లించే లేదా మొత్తంగా కాల్‌ను ఆపివేసే ఎంపిక సహాయంతో అవుట్‌గోయింగ్ కాల్ సమయంలో డయల్ చేయబడుతున్న నంబర్‌ను చూడటానికి యాప్‌ను అనుమతిస్తుంది."</string>
- <string name="permlab_answerPhoneCalls" msgid="4131324833663725855">"ఫోన్ కాల్‌లకు సమాధానమివ్వు"</string>
- <string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"ఇన్‌కమింగ్ ఫోన్ కాల్‌లకు సమాధానమివ్వడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+ <string name="permlab_answerPhoneCalls" msgid="4131324833663725855">"ఫోన్ కాల్స్‌కు సమాధానమివ్వు"</string>
+ <string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"ఇన్‌కమింగ్ ఫోన్ కాల్స్‌కు సమాధానమివ్వడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_receiveSms" msgid="505961632050451881">"వచన సందేశాలను (SMS) స్వీకరించడం"</string>
<string name="permdesc_receiveSms" msgid="1797345626687832285">"SMS సందేశాలను స్వీకరించడానికి మరియు ప్రాసెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. యాప్ మీ డివైజ్‌కు పంపబడిన సందేశాలను మీకు చూపకుండానే పర్యవేక్షించగలదని లేదా తొలగించగలదని దీని అర్థం."</string>
<string name="permlab_receiveMms" msgid="4000650116674380275">"వచన సందేశాలను (MMS) స్వీకరించడం"</string>
@@ -376,15 +376,15 @@
<string name="permdesc_readSms" product="default" msgid="774753371111699782">"ఈ యాప్‌ మీ ఫోన్‌లో నిల్వ చేసిన అన్ని SMS (వచన) సందేశాలను చదవగలదు."</string>
<string name="permlab_receiveWapPush" msgid="4223747702856929056">"వచన సందేశాలను (WAP) స్వీకరించడం"</string>
<string name="permdesc_receiveWapPush" msgid="1638677888301778457">"WAP సందేశాలను స్వీకరించడానికి మరియు ప్రాసెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. ఈ అనుమతి మీకు పంపబడిన సందేశాలను మీకు చూపకుండానే పర్యవేక్షించగల లేదా తొలగించగల సామర్థ్యాన్ని కలిగి ఉంటుంది."</string>
- <string name="permlab_getTasks" msgid="7460048811831750262">"అమలవుతున్న అనువర్తనాలను పునరుద్ధరించడం"</string>
+ <string name="permlab_getTasks" msgid="7460048811831750262">"అమలవుతున్న యాప్‌లను పునరుద్ధరించడం"</string>
<string name="permdesc_getTasks" msgid="7388138607018233726">"ప్రస్తుతం మరియు ఇటీవల అమలవుతున్న విధుల గురించి వివరణాత్మక సమాచారాన్ని తిరిగి పొందడానికి యాప్‌ను అనుమతిస్తుంది. ఇది పరికరంలో ఉపయోగించబడిన యాప్‌ల గురించి సమాచారాన్ని కనుగొనడానికి యాప్‌ను అనుమతించవచ్చు."</string>
<string name="permlab_manageProfileAndDeviceOwners" msgid="639849495253987493">"ప్రొఫైల్ మరియు పరికర యజమానులను నిర్వహించడం"</string>
- <string name="permdesc_manageProfileAndDeviceOwners" msgid="7304240671781989283">"ప్రొఫైల్ యజమానులను మరియు పరికరం యజమానిని సెట్ చేయడానికి అనువర్తనాలను అనుమతిస్తుంది."</string>
+ <string name="permdesc_manageProfileAndDeviceOwners" msgid="7304240671781989283">"ప్రొఫైల్ యజమానులను మరియు పరికరం యజమానిని సెట్ చేయడానికి యాప్‌లను అనుమతిస్తుంది."</string>
<string name="permlab_reorderTasks" msgid="7598562301992923804">"అమలవుతోన్న యాప్‌లను మళ్లీ క్రమం చేయడం"</string>
<string name="permdesc_reorderTasks" msgid="8796089937352344183">"విధులను ముందుకు మరియు నేపథ్యానికి తరలించడానికి యాప్‌ను అనుమతిస్తుంది. యాప్ మీ ప్రమేయం లేకుండానే దీన్ని చేయవచ్చు."</string>
<string name="permlab_enableCarMode" msgid="893019409519325311">"కారు మోడ్‌ను ప్రారంభించడం"</string>
<string name="permdesc_enableCarMode" msgid="56419168820473508">"కారు మోడ్‌ను ప్రారంభించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
- <string name="permlab_killBackgroundProcesses" msgid="6559320515561928348">"ఇతర అనువర్తనాలను మూసివేయడం"</string>
+ <string name="permlab_killBackgroundProcesses" msgid="6559320515561928348">"ఇతర యాప్‌లను మూసివేయడం"</string>
<string name="permdesc_killBackgroundProcesses" msgid="2357013583055434685">"ఇతర యాప్‌ల నేపథ్య ప్రాసెస్‌లను ముగించడానికి యాప్‌ను అనుమతిస్తుంది. దీని వలన ఇతర యాప్‌లు అమలు కాకుండా ఆపివేయబడవచ్చు."</string>
<string name="permlab_systemAlertWindow" msgid="5757218350944719065">"ఈ యాప్ ఇతర యాప్‌ల పైభాగాన కనిపించగలదు"</string>
<string name="permdesc_systemAlertWindow" msgid="1145660714855738308">"ఈ యాప్ ఇతర యాప్‌ల పైభాగాన లేదా స్క్రీన్ యొక్క ఇతర భాగాలపైన కనిపించగలదు. ఇది సాధారణ యాప్ వినియోగానికి అంతరాయం కలిగించవచ్చు మరియు ఆ ఇతర యాప్‌లు కనిపించే విధానాన్ని మార్చవచ్చు."</string>
@@ -421,9 +421,9 @@
<string name="permlab_readCallLog" msgid="1739990210293505948">"కాల్ లాగ్‌ను చదవడం"</string>
<string name="permdesc_readCallLog" msgid="8964770895425873433">"ఈ యాప్‌ మీ కాల్ చరిత్రను చదవగలదు."</string>
<string name="permlab_writeCallLog" msgid="670292975137658895">"కాల్ లాగ్‌ను వ్రాయడం"</string>
- <string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"ఇన్‌కమింగ్ మరియు అవుట్‌గోయింగ్ కాల్‌ల గురించిన డేటాతో సహా మీ టాబ్లెట్ యొక్క కాల్ లాగ్‌ను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. హానికరమైన యాప్‌లు మీ కాల్ లాగ్‌ను ఎరేజ్ చేయడానికి లేదా సవరించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
- <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"ఇన్‌కమింగ్ మరియు అవుట్‌గోయింగ్ కాల్‌లకు సంబంధించిన డేటాతో సహా మీ Android TV పరికరం కాల్ లాగ్‌ను సవరించడానికి యాప్‌ని అనుమతిస్తుంది. హానికరమైన యాప్‌లు మీ కాల్ లాగ్‌ను తీసివేయడానికి లేదా సవరించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
- <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"ఇన్‌కమింగ్ మరియు అవుట్‌గోయింగ్ కాల్‌ల గురించిన డేటాతో సహా మీ ఫోన్ యొక్క కాల్ లాగ్‌ను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. హానికరమైన యాప్‌లు మీ కాల్ లాగ్‌ను ఎరేజ్ చేయడానికి లేదా సవరించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
+ <string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"ఇన్‌కమింగ్ మరియు అవుట్‌గోయింగ్ కాల్స్‌ల గురించిన డేటాతో సహా మీ టాబ్లెట్ యొక్క కాల్ లాగ్‌ను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. హానికరమైన యాప్‌లు మీ కాల్ లాగ్‌ను ఎరేజ్ చేయడానికి లేదా సవరించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
+ <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"ఇన్‌కమింగ్ మరియు అవుట్‌గోయింగ్ కాల్స్‌కు సంబంధించిన డేటాతో సహా మీ Android TV పరికరం కాల్ లాగ్‌ను సవరించడానికి యాప్‌ని అనుమతిస్తుంది. హానికరమైన యాప్‌లు మీ కాల్ లాగ్‌ను తీసివేయడానికి లేదా సవరించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
+ <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"ఇన్‌కమింగ్ మరియు అవుట్‌గోయింగ్ కాల్స్‌ల గురించిన డేటాతో సహా మీ ఫోన్ యొక్క కాల్ లాగ్‌ను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. హానికరమైన యాప్‌లు మీ కాల్ లాగ్‌ను ఎరేజ్ చేయడానికి లేదా సవరించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
<string name="permlab_bodySensors" msgid="3411035315357380862">"శరీర సెన్సార్‌లను (గుండె స్పందన రేటు మానిటర్‌ల వంటివి) యాక్సెస్ చేయండి"</string>
<string name="permdesc_bodySensors" product="default" msgid="2365357960407973997">"మీ శారీరక పరిస్థితిని అనగా మీ గుండె స్పందన రేటు వంటి వాటిని పర్యవేక్షించే సెన్సార్‌ల నుండి డేటాను యాక్సెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_readCalendar" msgid="6408654259475396200">"క్యాలెండర్ ఈవెంట్‌లు మరియు వివరాలను చదవడం"</string>
@@ -464,15 +464,15 @@
<string name="permdesc_vibrate" msgid="8733343234582083721">"వైబ్రేటర్‌ను నియంత్రించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"వైబ్రేటర్ స్థితిని యాక్సెస్ చేసేందుకు యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_callPhone" msgid="1798582257194643320">"నేరుగా కాల్ చేసే ఫోన్ నంబర్‌లు"</string>
- <string name="permdesc_callPhone" msgid="5439809516131609109">"మీ ప్రమేయం లేకుండా ఫోన్ నంబర్‌లకు కాల్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. దీని వలన అనుకోని ఛార్జీలు విధించబడవచ్చు లేదా కాల్‌లు రావచ్చు. ఇది అత్యవసర నంబర్‌లకు కాల్ చేయడానికి యాప్‌ను అనుమతించదని గుర్తుంచుకోండి. హానికరమైన యాప్‌లు మీ నిర్ధారణ లేకుండానే కాల్‌లు చేయడం ద్వారా మీకు డబ్బు ఖర్చయ్యేలా చేయవచ్చు."</string>
+ <string name="permdesc_callPhone" msgid="5439809516131609109">"మీ ప్రమేయం లేకుండా ఫోన్ నంబర్‌లకు కాల్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. దీని వలన అనుకోని ఛార్జీలు విధించబడవచ్చు లేదా కాల్స్‌ రావచ్చు. ఇది అత్యవసర నంబర్‌లకు కాల్ చేయడానికి యాప్‌ను అనుమతించదని గుర్తుంచుకోండి. హానికరమైన యాప్‌లు మీ నిర్ధారణ లేకుండానే కాల్స్‌ చేయడం ద్వారా మీకు డబ్బు ఖర్చయ్యేలా చేయవచ్చు."</string>
<string name="permlab_accessImsCallService" msgid="442192920714863782">"IMS కాల్ సేవ యాక్సెస్ అనుమతి"</string>
- <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"మీ ప్రమేయం లేకుండా కాల్‌లు చేయడం కోసం IMS సేవను ఉపయోగించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+ <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"మీ ప్రమేయం లేకుండా కాల్స్‌ చేయడం కోసం IMS సేవను ఉపయోగించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_readPhoneState" msgid="8138526903259297969">"ఫోన్ స్థితి మరియు గుర్తింపుని చదవడం"</string>
<string name="permdesc_readPhoneState" msgid="7229063553502788058">"పరికరం యొక్క ఫోన్ ఫీచర్‌లను యాక్సెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. ఈ అనుమతి ఫోన్ నంబర్ మరియు పరికరం IDలను, కాల్ సక్రియంగా ఉందా లేదా అనే విషయాన్ని మరియు కాల్ ద్వారా కనెక్ట్ చేయబడిన రిమోట్ నంబర్‌ను కనుగొనడానికి యాప్‌ను అనుమతిస్తుంది."</string>
- <string name="permlab_manageOwnCalls" msgid="9033349060307561370">"కాల్‌లను సిస్టమ్ ద్వారా వెళ్లేలా చేయి"</string>
- <string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"కాలింగ్ అనుభవాన్ని మెరుగుపరచడం కోసం తన కాల్‌లను సిస్టమ్ ద్వారా వెళ్లేలా చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
- <string name="permlab_callCompanionApp" msgid="3654373653014126884">"సిస్టమ్ ద్వారా కాల్‌లను చూసి, నియంత్రించండి."</string>
- <string name="permdesc_callCompanionApp" msgid="8474168926184156261">"పరికరంలో కొనసాగుతున్న కాల్‌లను చూడడానికి మరియు నియంత్రించడానికి యాప్‌ను అనుమతిస్తుంది. ఇందులో కాల్ కోసం కాల్‌ల నంబర్‌లు మరియు రాష్ట్ర కాల్ వంటి సమాచారం ఉంటుంది."</string>
+ <string name="permlab_manageOwnCalls" msgid="9033349060307561370">"కాల్స్‌ను సిస్టమ్ ద్వారా వెళ్లేలా చేయి"</string>
+ <string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"కాలింగ్ అనుభవాన్ని మెరుగుపరచడం కోసం తన కాల్స్‌ను సిస్టమ్ ద్వారా వెళ్లేలా చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+ <string name="permlab_callCompanionApp" msgid="3654373653014126884">"సిస్టమ్ ద్వారా కాల్స్‌ను చూసి, నియంత్రించండి."</string>
+ <string name="permdesc_callCompanionApp" msgid="8474168926184156261">"పరికరంలో కొనసాగుతున్న కాల్స్‌ను చూడడానికి మరియు నియంత్రించడానికి యాప్‌ను అనుమతిస్తుంది. ఇందులో కాల్ కోసం కాల్స్‌ల నంబర్‌లు మరియు రాష్ట్ర కాల్ వంటి సమాచారం ఉంటుంది."</string>
<string name="permlab_exemptFromAudioRecordRestrictions" msgid="1164725468350759486">"ఆడియో రికార్డ్ పరిమితుల నుండి మినహాయింపు"</string>
<string name="permdesc_exemptFromAudioRecordRestrictions" msgid="2425117015896871976">"ఆడియోను రికార్డ్ చేయడానికి యాప్‌ను పరిమితుల నుండి మినహాయించండి."</string>
<string name="permlab_acceptHandover" msgid="2925523073573116523">"మరో యాప్ నుండి కాల్‌ని కొనసాగించండి"</string>
@@ -672,8 +672,8 @@
<string name="permdesc_sdcardRead" msgid="6872973242228240382">"మీ షేర్ చేసిన నిల్వ యొక్క కంటెంట్‌లను చదవడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_sdcardWrite" msgid="4863021819671416668">"మీ షేర్ చేసిన నిల్వ యొక్క కంటెంట్‌లను సవరించండి లేదా తొలగించండి"</string>
<string name="permdesc_sdcardWrite" msgid="8376047679331387102">"మీ షేర్ చేసిన నిల్వ యొక్క కంటెంట్‌లను రాయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
- <string name="permlab_use_sip" msgid="8250774565189337477">"SIP కాల్‌లను చేయడానికి/స్వీకరించడానికి"</string>
- <string name="permdesc_use_sip" msgid="3590270893253204451">"SIP కాల్‌లను చేయడానికి మరియు స్వీకరించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+ <string name="permlab_use_sip" msgid="8250774565189337477">"SIP కాల్స్‌ను చేయడానికి/స్వీకరించడానికి"</string>
+ <string name="permdesc_use_sip" msgid="3590270893253204451">"SIP కాల్స్‌ను చేయడానికి మరియు స్వీకరించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_register_sim_subscription" msgid="1653054249287576161">"కొత్త టెలికామ్ SIM కనెక్షన్‌లను నమోదు చేయడం"</string>
<string name="permdesc_register_sim_subscription" msgid="4183858662792232464">"కొత్త టెలికామ్ SIM కనెక్షన్‌లను నమోదు చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_register_call_provider" msgid="6135073566140050702">"కొత్త టెలికామ్ కనెక్షన్‌లను నమోదు చేయడం"</string>
@@ -683,7 +683,7 @@
<string name="permlab_bind_incall_service" msgid="5990625112603493016">"ఇన్-కాల్ స్క్రీన్‌తో పరస్పర చర్య చేయడం"</string>
<string name="permdesc_bind_incall_service" msgid="4124917526967765162">"వినియోగదారునికి ఇన్-కాల్ స్క్రీన్ ఎప్పుడు, ఎలా కనిపించాలనే దాన్ని నియంత్రించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_bind_connection_service" msgid="5409268245525024736">"టెలిఫోన్ సేవలతో పరస్పర చర్య చేయడం"</string>
- <string name="permdesc_bind_connection_service" msgid="6261796725253264518">"కాల్‌లు చేయడం/స్వీకరించడం కోసం టెలిఫోన్ సేవలతో పరస్పర చర్య చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+ <string name="permdesc_bind_connection_service" msgid="6261796725253264518">"కాల్స్‌ చేయడం/స్వీకరించడం కోసం టెలిఫోన్ సేవలతో పరస్పర చర్య చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_control_incall_experience" msgid="6436863486094352987">"ఇన్-కాల్ వినియోగదారు అనుభవాన్ని అందించడం"</string>
<string name="permdesc_control_incall_experience" msgid="5896723643771737534">"ఇన్-కాల్ వినియోగదారుని అనుభవాన్ని అందించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_readNetworkUsageHistory" msgid="8470402862501573795">"చారిత్రక నెట్‌వర్క్ వినియోగాన్ని చదవడం"</string>
@@ -693,29 +693,29 @@
<string name="permlab_modifyNetworkAccounting" msgid="7448790834938749041">"నెట్‌వర్క్ వినియోగ అకౌంటింగ్‌ను సవరించడం"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"యాప్‌లలో నెట్‌వర్క్ వినియోగం ఎలా గణించాలనే దాన్ని సవరించడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌ల ద్వారా ఉపయోగించడానికి ఉద్దేశించినది కాదు."</string>
<string name="permlab_accessNotifications" msgid="7130360248191984741">"నోటిఫికేషన్‌లను యాక్సెస్ చేయడం"</string>
- <string name="permdesc_accessNotifications" msgid="761730149268789668">"నోటిఫికేషన్‌లను, ఇతర అనువర్తనాల ద్వారా పోస్ట్ చేయబడిన వాటిని తిరిగి పొందడానికి, పరిశీలించడానికి మరియు క్లియర్ చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+ <string name="permdesc_accessNotifications" msgid="761730149268789668">"నోటిఫికేషన్‌లను, ఇతర యాప్‌ల ద్వారా పోస్ట్ చేయబడిన వాటిని తిరిగి పొందడానికి, పరిశీలించడానికి మరియు క్లియర్ చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_bindNotificationListenerService" msgid="5848096702733262458">"నోటిఫికేషన్ పరిశీలన సేవకు అనుబంధించడం"</string>
- <string name="permdesc_bindNotificationListenerService" msgid="4970553694467137126">"నోటిఫికేషన్ పరిశీలన సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాల కోసం ఎప్పటికీ అవసరం ఉండకూడదు."</string>
+ <string name="permdesc_bindNotificationListenerService" msgid="4970553694467137126">"నోటిఫికేషన్ పరిశీలన సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌ల కోసం ఎప్పటికీ అవసరం ఉండకూడదు."</string>
<string name="permlab_bindConditionProviderService" msgid="5245421224814878483">"షరతు ప్రదాత సేవకు అనుబంధించడం"</string>
- <string name="permdesc_bindConditionProviderService" msgid="6106018791256120258">"షరతు ప్రదాత సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+ <string name="permdesc_bindConditionProviderService" msgid="6106018791256120258">"షరతు ప్రదాత సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
<string name="permlab_bindDreamService" msgid="4776175992848982706">"డ్రీమ్ సేవ‌కి అనుబంధించడం"</string>
- <string name="permdesc_bindDreamService" msgid="9129615743300572973">"డ్రీమ్ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+ <string name="permdesc_bindDreamService" msgid="9129615743300572973">"డ్రీమ్ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
<string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"క్యారియర్ అందించిన కాన్ఫిగరేషన్ యాప్‌ను అభ్యర్థించడం"</string>
- <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"క్యారియర్ అందించిన కాన్ఫిగరేషన్ యాప్‌ను అభ్యర్థించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాల కోసం ఎప్పటికీ అవసరం ఉండకూడదు."</string>
+ <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"క్యారియర్ అందించిన కాన్ఫిగరేషన్ యాప్‌ను అభ్యర్థించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌ల కోసం ఎప్పటికీ అవసరం ఉండకూడదు."</string>
<string name="permlab_accessNetworkConditions" msgid="1270732533356286514">"నెట్‌వర్క్ పరిస్థితులపై పరిశీలనల గురించి తెలుసుకోవడం"</string>
- <string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"నెట్‌వర్క్ పరిస్థితులపై పరిశీలనల గురించి తెలుసుకోవడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండకూడదు."</string>
+ <string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"నెట్‌వర్క్ పరిస్థితులపై పరిశీలనల గురించి తెలుసుకోవడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండకూడదు."</string>
<string name="permlab_setInputCalibration" msgid="932069700285223434">"ఇన్‌పుట్ పరికరం క్రమాంకనాన్ని మార్చండి"</string>
- <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"టచ్ స్క్రీన్ యొక్క క్రమాంకన పరామితులను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+ <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"టచ్ స్క్రీన్ యొక్క క్రమాంకన పరామితులను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
<string name="permlab_accessDrmCertificates" msgid="6473765454472436597">"DRM ప్రమాణపత్రాలను యాక్సెస్ చేయడం"</string>
- <string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"DRM ప్రమాణపత్రాలను కేటాయించడానికి మరియు ఉపయోగించడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+ <string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"DRM ప్రమాణపత్రాలను కేటాయించడానికి మరియు ఉపయోగించడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
<string name="permlab_handoverStatus" msgid="7620438488137057281">"Android Beam బదిలీ స్థితిని స్వీకరించడం"</string>
<string name="permdesc_handoverStatus" msgid="3842269451732571070">"ప్రస్తుత Android Beam బదిలీలకు సంబంధించిన సమాచారాన్ని స్వీకరించడానికి ఈ యాప్‌ను అనుమతిస్తుంది"</string>
<string name="permlab_removeDrmCertificates" msgid="710576248717404416">"DRM ప్రమాణపత్రాలను తీసివేయడం"</string>
- <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"DRM ప్రమాణపత్రాలను తీసివేయడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+ <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"DRM ప్రమాణపత్రాలను తీసివేయడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
<string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"క్యారియర్ సందేశ సేవకు అనుబంధించడం"</string>
- <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"క్యారియర్ సందేశ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+ <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"క్యారియర్ సందేశ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
<string name="permlab_bindCarrierServices" msgid="2395596978626237474">"క్యారియర్ సేవలకు అనుబంధించడం"</string>
- <string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"క్యారియర్ సేవలకు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+ <string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"క్యారియర్ సేవలకు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
<string name="permlab_access_notification_policy" msgid="5524112842876975537">"అంతరాయం కలిగించవద్దును యాక్సెస్ చేయడం"</string>
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"అంతరాయం కలిగించవద్దు ఎంపిక కాన్ఫిగరేషన్ చదవడానికి మరియు వ్రాయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"వీక్షణ అనుమతి వినియోగాన్ని ప్రారంభించండి"</string>
@@ -1258,7 +1258,7 @@
<string name="app_upgrading_toast" msgid="1016267296049455585">"<xliff:g id="APPLICATION">%1$s</xliff:g>ని అప్‌గ్రేడ్ చేస్తోంది…"</string>
<string name="android_upgrading_apk" msgid="1339564803894466737">"<xliff:g id="NUMBER_1">%2$d</xliff:g>లో <xliff:g id="NUMBER_0">%1$d</xliff:g> యాప్‌ను అనుకూలీకరిస్తోంది."</string>
<string name="android_preparing_apk" msgid="589736917792300956">"<xliff:g id="APPNAME">%1$s</xliff:g>ని సిద్ధం చేస్తోంది."</string>
- <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"అనువర్తనాలను ప్రారంభిస్తోంది."</string>
+ <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"యాప్‌లను ప్రారంభిస్తోంది."</string>
<string name="android_upgrading_complete" msgid="409800058018374746">"బూట్‌ను ముగిస్తోంది."</string>
<string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"స్క్రీన్‌ను ఆఫ్ చేయాలా?"</string>
<string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"మీ వేలిముద్రను సెటప్ చేస్తున్నప్పుడు, మీరు పవర్ బటన్‌ను నొక్కారు.\n\nఇది సాధారణంగా మీ స్క్రీన్‌ను ఆఫ్ చేస్తుంది."</string>
@@ -1990,7 +1990,7 @@
<string name="profile_encrypted_detail" msgid="5279730442756849055">"కార్యాలయ ప్రొఫైల్ లాక్ అయింది"</string>
<string name="profile_encrypted_message" msgid="1128512616293157802">"కార్యాలయ ప్రొఫైల్ అన్‌లాక్ చేయుటకు నొక్కండి"</string>
<string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g>కి కనెక్ట్ చేయబడింది"</string>
- <string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"ఫైల్‌లను వీక్షించడానికి నొక్కండి"</string>
+ <string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"ఫైళ్లను వీక్షించడానికి నొక్కండి"</string>
<string name="pin_target" msgid="8036028973110156895">"పిన్ చేయి"</string>
<string name="pin_specific_target" msgid="7824671240625957415">"<xliff:g id="LABEL">%1$s</xliff:g>ను పిన్ చేయండి"</string>
<string name="unpin_target" msgid="3963318576590204447">"అన్‌‌పిన్‌ ‌చేయి"</string>
@@ -2076,8 +2076,8 @@
<string name="harmful_app_warning_title" msgid="8794823880881113856">"హానికరమైన యాప్ గుర్తించబడింది"</string>
<string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> స్లైస్‌లను చూపించాలనుకుంటోంది"</string>
<string name="screenshot_edit" msgid="7408934887203689207">"ఎడిట్ చేయండి"</string>
- <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"కాల్‌లు మరియు నోటిఫికేషన్‌లు వైబ్రేట్ అవుతాయి"</string>
- <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"కాల్‌లు మరియు నోటిఫికేషన్‌లు మ్యూట్ చేయబడతాయి"</string>
+ <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"కాల్స్‌ మరియు నోటిఫికేషన్‌లు వైబ్రేట్ అవుతాయి"</string>
+ <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"కాల్స్‌ మరియు నోటిఫికేషన్‌లు మ్యూట్ చేయబడతాయి"</string>
<string name="notification_channel_system_changes" msgid="2462010596920209678">"సిస్టమ్ మార్పులు"</string>
<string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"అంతరాయం కలిగించవద్దు"</string>
<string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"కొత్తది: అంతరాయం కలిగించవద్దు నోటిఫికేషన్‌లను దాస్తోంది"</string>
@@ -2099,7 +2099,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"సరే"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ఆఫ్ చేయండి"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"మరింత తెలుసుకోండి"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12లో Android అనుకూల నోటిఫికేషన్‌లను, మెరుగైన నోటిఫికేషన్‌లు భర్తీ చేశాయి. సూచించిన చర్యలు, రిప్లయిలను ఈ ఫీచర్ చూపించి, మీ నోటిఫికేషన్‌లను ఆర్గనైజ్ చేస్తుంది.\n\nకాంటాక్ట్ పేర్లు, మెసేజ్‌లు లాంటి వ్యక్తిగత సమాచారంతో సహా నోటిఫికేషన్ కంటెంట్‌ను మెరుగైన నోటిఫికేషన్‌లు యాక్సెస్ చేయవచ్చు. ఫోన్ కాల్‌లకు సమాధానమివ్వడం, \'అంతరాయం కలిగించవద్దు\' ఆప్షన్‌ను కంట్రోల్ చేయడం లాంటి నోటిఫికేషన్‌లను విస్మరించడం లేదా ప్రతిస్పందించడం కూడా ఈ ఫీచర్ చేయగలదు."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12లో Android అనుకూల నోటిఫికేషన్‌లను, మెరుగైన నోటిఫికేషన్‌లు భర్తీ చేశాయి. సూచించిన చర్యలు, రిప్లయిలను ఈ ఫీచర్ చూపించి, మీ నోటిఫికేషన్‌లను ఆర్గనైజ్ చేస్తుంది.\n\nకాంటాక్ట్ పేర్లు, మెసేజ్‌లు లాంటి వ్యక్తిగత సమాచారంతో సహా నోటిఫికేషన్ కంటెంట్‌ను మెరుగైన నోటిఫికేషన్‌లు యాక్సెస్ చేయవచ్చు. ఫోన్ కాల్స్‌కు సమాధానమివ్వడం, \'అంతరాయం కలిగించవద్దు\' ఆప్షన్‌ను కంట్రోల్ చేయడం లాంటి నోటిఫికేషన్‌లను విస్మరించడం లేదా ప్రతిస్పందించడం కూడా ఈ ఫీచర్ చేయగలదు."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"రొటీన్ మోడ్ సమాచార నోటిఫికేషన్"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"మామూలుగా ఛార్జ్ చేసేలోపు బ్యాటరీ ఖాళీ కావచ్చు"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"బ్యాటరీ జీవితకాలాన్ని పెంచడానికి బ్యాటరీ సేవర్ యాక్టివేట్ చేయబడింది"</string>
@@ -2129,7 +2129,7 @@
<string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"విమానం మోడ్‌లో బ్లూటూత్ ఆన్‌లో ఉంటుంది"</string>
<string name="car_loading_profile" msgid="8219978381196748070">"లోడవుతోంది"</string>
<plurals name="file_count" formatted="false" msgid="7063513834724389247">
- <item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ఫైల్‌లు</item>
+ <item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ఫైళ్లు</item>
<item quantity="one"><xliff:g id="FILE_NAME_0">%s</xliff:g> + <xliff:g id="COUNT_1">%d</xliff:g> ఫైల్</item>
</plurals>
<string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"ఎవరికి షేర్ చేయాలనే దానికి సంబంధించి సిఫార్సులేవీ లేవు"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 3f9cee11da36..2936a080723b 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1949,7 +1949,7 @@
<string name="maximize_button_text" msgid="4258922519914732645">"بڑا کریں"</string>
<string name="close_button_text" msgid="10603510034455258">"بند کریں"</string>
<string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
- <string name="call_notification_answer_action" msgid="5999246836247132937">"جواب"</string>
+ <string name="call_notification_answer_action" msgid="5999246836247132937">"جواب دیں"</string>
<string name="call_notification_answer_video_action" msgid="2086030940195382249">"ویڈیو"</string>
<string name="call_notification_decline_action" msgid="3700345945214000726">"مسترد کریں"</string>
<string name="call_notification_hang_up_action" msgid="9130720590159188131">"منقطع کر دیں"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1586f164a0a5..5d87f84332ae 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -666,6 +666,17 @@
display is powered on at the same time. -->
<bool name="config_supportsConcurrentInternalDisplays">true</bool>
+ <!-- Map of DeviceState to rotation lock setting. Each entry must be in the format
+ "key:value", for example: "0:1".
+ The keys are device states, and the values are one of
+ Settings.Secure.DeviceStateRotationLockSetting.
+ Any device state that doesn't have a default set here will be treated as
+ DEVICE_STATE_ROTATION_LOCK_IGNORED meaning it will not have its own rotation lock setting.
+ If this map is missing, the feature is disabled and only one global rotation lock setting
+ will apply, regardless of device state. -->
+ <string-array name="config_perDeviceStateRotationLockDefaults" />
+
+
<!-- Desk dock behavior -->
<!-- The number of degrees to rotate the display when the device is in a desk dock.
@@ -5123,4 +5134,10 @@
<item>@array/config_mainBuiltInDisplayWaterfallCutout</item>
<item>@array/config_secondaryBuiltInDisplayWaterfallCutout</item>
</array>
+
+ <!-- Whether the airplane mode should be reset when device boots in non-safemode after exiting
+ from safemode.
+ This flag should be enabled only when the product does not have any UI to toggle airplane
+ mode like automotive devices.-->
+ <bool name="config_autoResetAirplaneMode">false</bool>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index cd590cbbe2b0..4ca1e3f4c06c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2217,6 +2217,7 @@
<java-symbol type="string" name="config_primaryLocationTimeZoneProviderPackageName" />
<java-symbol type="bool" name="config_enableSecondaryLocationTimeZoneProvider" />
<java-symbol type="string" name="config_secondaryLocationTimeZoneProviderPackageName" />
+ <java-symbol type="bool" name="config_autoResetAirplaneMode" />
<java-symbol type="layout" name="resolver_list" />
<java-symbol type="id" name="resolver_list" />
@@ -3838,6 +3839,8 @@
<java-symbol type="string" name="config_foldedArea" />
<java-symbol type="bool" name="config_supportsConcurrentInternalDisplays" />
<java-symbol type="bool" name="config_unfoldTransitionEnabled" />
+ <java-symbol type="array" name="config_perDeviceStateRotationLockDefaults" />
+
<java-symbol type="array" name="config_disableApksUnlessMatchedSku_apk_list" />
<java-symbol type="array" name="config_disableApkUnlessMatchedSku_skus_list" />
diff --git a/core/tests/coretests/src/android/app/backup/FullBackupTest.java b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
index 08edb4e9be97..bc92da928d1e 100644
--- a/core/tests/coretests/src/android/app/backup/FullBackupTest.java
+++ b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
@@ -16,6 +16,8 @@
package android.app.backup;
+import static android.app.backup.FullBackup.ConfigSection.CLOUD_BACKUP;
+
import android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags;
import android.content.Context;
import android.test.AndroidTestCase;
@@ -414,6 +416,37 @@ public class FullBackupTest extends AndroidTestCase {
assertNull("Didn't throw away invalid \"..\" path.", fileDomainIncludes);
}
+ public void testParseNewBackupSchemeFromXml_emptyCloudSectionIsRespected() throws Exception {
+ mXpp.setInput(new StringReader(
+ "<data-extraction-rules>" +
+ "<cloud-backup>" +
+ "</cloud-backup>" +
+ "</data-extraction-rules>"));
+
+ FullBackup.BackupScheme backupScheme = FullBackup.getBackupSchemeForTest(mContext);
+ boolean result = backupScheme.parseNewBackupSchemeFromXmlLocked(mXpp, CLOUD_BACKUP,
+ excludesSet, includeMap);
+
+ assertTrue(result);
+ }
+
+ public void testParseNewBackupSchemeFromXml_emptyCloudSectionWithEncryptionFlagIsRespected()
+ throws Exception {
+ mXpp.setInput(new StringReader(
+ "<data-extraction-rules>" +
+ "<cloud-backup disableIfNoEncryptionCapabilities=\"true\">" +
+ "</cloud-backup>" +
+ "</data-extraction-rules>"));
+
+ FullBackup.BackupScheme backupScheme = FullBackup.getBackupSchemeForTest(mContext);
+ boolean result = backupScheme.parseNewBackupSchemeFromXmlLocked(mXpp, CLOUD_BACKUP,
+ excludesSet, includeMap);
+
+ assertTrue(result);
+ assertEquals(backupScheme.getRequiredTransportFlags(),
+ BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED);
+ }
+
public void testDoubleDotInPath_isIgnored() throws Exception {
mXpp.setInput(new StringReader(
"<full-backup-content>" +
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index 9915e3852b8d..50639be57f22 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -156,7 +156,8 @@ public class ObjectPoolTests {
.setProcState(procState).setState(bundle).setPersistentState(persistableBundle)
.setPendingResults(resultInfoList()).setPendingNewIntents(referrerIntentList())
.setIsForward(true).setAssistToken(assistToken)
- .setShareableActivityToken(shareableActivityToken).build();
+ .setShareableActivityToken(shareableActivityToken)
+ .setTaskFragmentToken(new Binder()).build();
LaunchActivityItem emptyItem = new LaunchActivityItemBuilder().build();
LaunchActivityItem item = itemSupplier.get();
diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
index 75da0bfba581..1173c9210ed5 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
@@ -112,6 +112,7 @@ class TestUtils {
private IBinder mShareableActivityToken;
private FixedRotationAdjustments mFixedRotationAdjustments;
private boolean mLaunchedFromBubble;
+ private IBinder mTaskFragmentToken;
LaunchActivityItemBuilder setIntent(Intent intent) {
mIntent = intent;
@@ -213,13 +214,18 @@ class TestUtils {
return this;
}
+ LaunchActivityItemBuilder setTaskFragmentToken(IBinder taskFragmentToken) {
+ mTaskFragmentToken = taskFragmentToken;
+ return this;
+ }
+
LaunchActivityItem build() {
return LaunchActivityItem.obtain(mIntent, mIdent, mInfo,
mCurConfig, mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor,
mProcState, mState, mPersistentState, mPendingResults, mPendingNewIntents,
mActivityOptions, mIsForward, mProfilerInfo, mAssistToken,
null /* activityClientController */, mFixedRotationAdjustments,
- mShareableActivityToken, mLaunchedFromBubble);
+ mShareableActivityToken, mLaunchedFromBubble, mTaskFragmentToken);
}
}
}
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index df0c64c810c6..98c9afd2eb6b 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -209,6 +209,7 @@ public class TransactionParcelTests {
.setPendingNewIntents(referrerIntentList()).setIsForward(true)
.setAssistToken(new Binder()).setFixedRotationAdjustments(fixedRotationAdjustments)
.setShareableActivityToken(new Binder())
+ .setTaskFragmentToken(new Binder())
.build();
writeAndPrepareForReading(item);
diff --git a/core/tests/coretests/src/android/view/WindowInfoTest.java b/core/tests/coretests/src/android/view/WindowInfoTest.java
index 05e8bd8b6cab..0a99b08f58ff 100644
--- a/core/tests/coretests/src/android/view/WindowInfoTest.java
+++ b/core/tests/coretests/src/android/view/WindowInfoTest.java
@@ -25,6 +25,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
+import android.app.ActivityTaskManager;
import android.os.IBinder;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
@@ -83,6 +84,7 @@ public class WindowInfoTest {
assertEquals(0, w.layer);
assertEquals(AccessibilityNodeInfo.UNDEFINED_NODE_ID, w.accessibilityIdOfAnchor);
assertEquals(Display.INVALID_DISPLAY, w.displayId);
+ assertEquals(ActivityTaskManager.INVALID_TASK_ID, w.taskId);
assertNull(w.title);
assertNull(w.token);
assertNull(w.childTokens);
@@ -123,6 +125,7 @@ public class WindowInfoTest {
windowInfo.displayId = 2;
windowInfo.layer = 3;
windowInfo.accessibilityIdOfAnchor = 4L;
+ windowInfo.taskId = 5;
windowInfo.title = "title";
windowInfo.token = mock(IBinder.class);
windowInfo.childTokens = new ArrayList<>();
diff --git a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
index 96b4316ffafc..7cd8197ce1e4 100644
--- a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
@@ -23,6 +23,7 @@ import static android.view.SurfaceControl.JankData.JANK_SURFACEFLINGER_DEADLINE_
import static com.android.internal.jank.FrameTracker.SurfaceControlWrapper;
import static com.android.internal.jank.FrameTracker.ViewRootWrapper;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_WALLPAPER_TRANSITION;
import static com.google.common.truth.Truth.assertThat;
@@ -50,6 +51,7 @@ import androidx.test.rule.ActivityTestRule;
import com.android.internal.jank.FrameTracker.ChoreographerWrapper;
import com.android.internal.jank.FrameTracker.FrameMetricsWrapper;
import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper;
+import com.android.internal.jank.InteractionJankMonitor.Configuration;
import com.android.internal.jank.InteractionJankMonitor.Session;
import org.junit.Before;
@@ -69,7 +71,6 @@ public class FrameTrackerTest {
public ActivityTestRule<ViewAttachTestActivity> mRule =
new ActivityTestRule<>(ViewAttachTestActivity.class);
- private FrameTracker mTracker;
private ThreadedRendererWrapper mRenderer;
private FrameMetricsWrapper mWrapper;
private SurfaceControlWrapper mSurfaceControlWrapper;
@@ -85,7 +86,6 @@ public class FrameTrackerTest {
View view = mActivity.getWindow().getDecorView();
assertThat(view.isAttachedToWindow()).isTrue();
- Handler handler = mRule.getActivity().getMainThreadHandler();
mWrapper = Mockito.spy(new FrameMetricsWrapper());
mRenderer = Mockito.spy(new ThreadedRendererWrapper(view.getThreadedRenderer()));
doNothing().when(mRenderer).addObserver(any());
@@ -103,229 +103,355 @@ public class FrameTrackerTest {
mListenerCapture.capture());
mChoreographer = mock(ChoreographerWrapper.class);
+ }
- Session session = new Session(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX);
- mTracker = Mockito.spy(
+ private FrameTracker spyFrameTracker(int cuj, String postfix, boolean surfaceOnly) {
+ Handler handler = mRule.getActivity().getMainThreadHandler();
+ Session session = new Session(cuj, postfix);
+ Configuration config = mock(Configuration.class);
+ when(config.isSurfaceOnly()).thenReturn(surfaceOnly);
+ when(config.getSurfaceControl()).thenReturn(mSurfaceControl);
+ FrameTracker frameTracker = Mockito.spy(
new FrameTracker(session, handler, mRenderer, mViewRootWrapper,
mSurfaceControlWrapper, mChoreographer, mWrapper,
- /*traceThresholdMissedFrames=*/ 1, /*traceThresholdFrameTimeMillis=*/ -1,
- null));
- doNothing().when(mTracker).triggerPerfetto();
- doNothing().when(mTracker).postTraceStartMarker();
+ /* traceThresholdMissedFrames= */ 1,
+ /* traceThresholdFrameTimeMillis= */ -1,
+ /* FrameTrackerListener= */ null, config));
+ doNothing().when(frameTracker).triggerPerfetto();
+ doNothing().when(frameTracker).postTraceStartMarker();
+ return frameTracker;
}
@Test
public void testOnlyFirstWindowFrameOverThreshold() {
+ FrameTracker tracker = spyFrameTracker(
+ CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
// Just provide current timestamp anytime mWrapper asked for VSYNC_TIMESTAMP
when(mWrapper.getMetric(FrameMetrics.VSYNC_TIMESTAMP))
.then(unusedInvocation -> System.nanoTime());
when(mChoreographer.getVsyncId()).thenReturn(100L);
- mTracker.begin();
+ tracker.begin();
verify(mRenderer, only()).addObserver(any());
// send first frame with a long duration - should not be taken into account
- sendFirstWindowFrame(100, JANK_APP_DEADLINE_MISSED, 100L);
+ sendFirstWindowFrame(tracker, 100, JANK_APP_DEADLINE_MISSED, 100L);
// send another frame with a short duration - should not be considered janky
- sendFirstWindowFrame(5, JANK_NONE, 101L);
+ sendFirstWindowFrame(tracker, 5, JANK_NONE, 101L);
// end the trace session, the last janky frame is after the end() so is discarded.
when(mChoreographer.getVsyncId()).thenReturn(102L);
- mTracker.end(FrameTracker.REASON_END_NORMAL);
- sendFrame(5, JANK_NONE, 102L);
- sendFrame(500, JANK_APP_DEADLINE_MISSED, 103L);
+ tracker.end(FrameTracker.REASON_END_NORMAL);
+ sendFrame(tracker, 5, JANK_NONE, 102L);
+ sendFrame(tracker, 500, JANK_APP_DEADLINE_MISSED, 103L);
- verify(mTracker).removeObservers();
- verify(mTracker, never()).triggerPerfetto();
+ verify(tracker).removeObservers();
+ verify(tracker, never()).triggerPerfetto();
}
@Test
public void testSfJank() {
+ FrameTracker tracker = spyFrameTracker(
+ CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
when(mChoreographer.getVsyncId()).thenReturn(100L);
- mTracker.begin();
+ tracker.begin();
verify(mRenderer, only()).addObserver(any());
// send first frame - not janky
- sendFrame(4, JANK_NONE, 100L);
+ sendFrame(tracker, 4, JANK_NONE, 100L);
// send another frame - should be considered janky
- sendFrame(40, JANK_SURFACEFLINGER_DEADLINE_MISSED, 101L);
+ sendFrame(tracker, 40, JANK_SURFACEFLINGER_DEADLINE_MISSED, 101L);
// end the trace session
when(mChoreographer.getVsyncId()).thenReturn(102L);
- mTracker.end(FrameTracker.REASON_END_NORMAL);
- sendFrame(4, JANK_NONE, 102L);
+ tracker.end(FrameTracker.REASON_END_NORMAL);
+ sendFrame(tracker, 4, JANK_NONE, 102L);
- verify(mTracker).removeObservers();
+ verify(tracker).removeObservers();
// We detected a janky frame - trigger Perfetto
- verify(mTracker).triggerPerfetto();
+ verify(tracker).triggerPerfetto();
}
@Test
public void testFirstFrameJankyNoTrigger() {
+ FrameTracker tracker = spyFrameTracker(
+ CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
when(mChoreographer.getVsyncId()).thenReturn(100L);
- mTracker.begin();
+ tracker.begin();
verify(mRenderer, only()).addObserver(any());
// send first frame - janky
- sendFrame(40, JANK_APP_DEADLINE_MISSED, 100L);
+ sendFrame(tracker, 40, JANK_APP_DEADLINE_MISSED, 100L);
// send another frame - not jank
- sendFrame(4, JANK_NONE, 101L);
+ sendFrame(tracker, 4, JANK_NONE, 101L);
// end the trace session
when(mChoreographer.getVsyncId()).thenReturn(102L);
- mTracker.end(FrameTracker.REASON_END_NORMAL);
- sendFrame(4, JANK_NONE, 102L);
+ tracker.end(FrameTracker.REASON_END_NORMAL);
+ sendFrame(tracker, 4, JANK_NONE, 102L);
- verify(mTracker).removeObservers();
+ verify(tracker).removeObservers();
// We detected a janky frame - trigger Perfetto
- verify(mTracker, never()).triggerPerfetto();
+ verify(tracker, never()).triggerPerfetto();
}
@Test
public void testOtherFrameOverThreshold() {
+ FrameTracker tracker = spyFrameTracker(
+ CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
when(mChoreographer.getVsyncId()).thenReturn(100L);
- mTracker.begin();
+ tracker.begin();
verify(mRenderer, only()).addObserver(any());
// send first frame - not janky
- sendFrame(4, JANK_NONE, 100L);
+ sendFrame(tracker, 4, JANK_NONE, 100L);
// send another frame - should be considered janky
- sendFrame(40, JANK_APP_DEADLINE_MISSED, 101L);
+ sendFrame(tracker, 40, JANK_APP_DEADLINE_MISSED, 101L);
// end the trace session
when(mChoreographer.getVsyncId()).thenReturn(102L);
- mTracker.end(FrameTracker.REASON_END_NORMAL);
- sendFrame(4, JANK_NONE, 102L);
+ tracker.end(FrameTracker.REASON_END_NORMAL);
+ sendFrame(tracker, 4, JANK_NONE, 102L);
- verify(mTracker).removeObservers();
+ verify(tracker).removeObservers();
// We detected a janky frame - trigger Perfetto
- verify(mTracker).triggerPerfetto();
+ verify(tracker).triggerPerfetto();
}
@Test
public void testLastFrameOverThresholdBeforeEnd() {
+ FrameTracker tracker = spyFrameTracker(
+ CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
when(mChoreographer.getVsyncId()).thenReturn(100L);
- mTracker.begin();
+ tracker.begin();
verify(mRenderer, only()).addObserver(any());
// send first frame - not janky
- sendFrame(4, JANK_NONE, 100L);
+ sendFrame(tracker, 4, JANK_NONE, 100L);
// send another frame - not janky
- sendFrame(4, JANK_NONE, 101L);
+ sendFrame(tracker, 4, JANK_NONE, 101L);
// end the trace session, simulate one more valid callback came after the end call.
when(mChoreographer.getVsyncId()).thenReturn(102L);
- mTracker.end(FrameTracker.REASON_END_NORMAL);
- sendFrame(50, JANK_APP_DEADLINE_MISSED, 102L);
+ tracker.end(FrameTracker.REASON_END_NORMAL);
+ sendFrame(tracker, 50, JANK_APP_DEADLINE_MISSED, 102L);
// One more callback with VSYNC after the end() vsync id.
- sendFrame(4, JANK_NONE, 103L);
+ sendFrame(tracker, 4, JANK_NONE, 103L);
- verify(mTracker).removeObservers();
+ verify(tracker).removeObservers();
// We detected a janky frame - trigger Perfetto
- verify(mTracker).triggerPerfetto();
+ verify(tracker).triggerPerfetto();
}
@Test
public void testBeginCancel() {
+ FrameTracker tracker = spyFrameTracker(
+ CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
when(mChoreographer.getVsyncId()).thenReturn(100L);
- mTracker.begin();
+ tracker.begin();
verify(mRenderer).addObserver(any());
// First frame - not janky
- sendFrame(4, JANK_NONE, 100L);
+ sendFrame(tracker, 4, JANK_NONE, 100L);
// normal frame - not janky
- sendFrame(4, JANK_NONE, 101L);
+ sendFrame(tracker, 4, JANK_NONE, 101L);
// a janky frame
- sendFrame(50, JANK_APP_DEADLINE_MISSED, 102L);
+ sendFrame(tracker, 50, JANK_APP_DEADLINE_MISSED, 102L);
- mTracker.cancel(FrameTracker.REASON_CANCEL_NORMAL);
- verify(mTracker).removeObservers();
+ tracker.cancel(FrameTracker.REASON_CANCEL_NORMAL);
+ verify(tracker).removeObservers();
// Since the tracker has been cancelled, shouldn't trigger perfetto.
- verify(mTracker, never()).triggerPerfetto();
+ verify(tracker, never()).triggerPerfetto();
}
@Test
public void testCancelIfEndVsyncIdEqualsToBeginVsyncId() {
+ FrameTracker tracker = spyFrameTracker(
+ CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
when(mChoreographer.getVsyncId()).thenReturn(100L);
- mTracker.begin();
+ tracker.begin();
verify(mRenderer, only()).addObserver(any());
// end the trace session
when(mChoreographer.getVsyncId()).thenReturn(101L);
- mTracker.end(FrameTracker.REASON_END_NORMAL);
+ tracker.end(FrameTracker.REASON_END_NORMAL);
// Since the begin vsync id (101) equals to the end vsync id (101), will be treat as cancel.
- verify(mTracker).cancel(FrameTracker.REASON_CANCEL_SAME_VSYNC);
+ verify(tracker).cancel(FrameTracker.REASON_CANCEL_SAME_VSYNC);
// Observers should be removed in this case, or FrameTracker object will be leaked.
- verify(mTracker).removeObservers();
+ verify(tracker).removeObservers();
// Should never trigger Perfetto since it is a cancel.
- verify(mTracker, never()).triggerPerfetto();
+ verify(tracker, never()).triggerPerfetto();
}
@Test
public void testCancelIfEndVsyncIdLessThanBeginVsyncId() {
+ FrameTracker tracker = spyFrameTracker(
+ CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
when(mChoreographer.getVsyncId()).thenReturn(100L);
- mTracker.begin();
+ tracker.begin();
verify(mRenderer, only()).addObserver(any());
// end the trace session at the same vsync id, end vsync id will less than the begin one.
// Because the begin vsync id is supposed to the next frame,
- mTracker.end(FrameTracker.REASON_END_NORMAL);
+ tracker.end(FrameTracker.REASON_END_NORMAL);
// The begin vsync id (101) is larger than the end one (100), will be treat as cancel.
- verify(mTracker).cancel(FrameTracker.REASON_CANCEL_SAME_VSYNC);
+ verify(tracker).cancel(FrameTracker.REASON_CANCEL_SAME_VSYNC);
// Observers should be removed in this case, or FrameTracker object will be leaked.
- verify(mTracker).removeObservers();
+ verify(tracker).removeObservers();
// Should never trigger Perfetto since it is a cancel.
- verify(mTracker, never()).triggerPerfetto();
+ verify(tracker, never()).triggerPerfetto();
}
@Test
public void testCancelWhenSessionNeverBegun() {
- mTracker.cancel(FrameTracker.REASON_CANCEL_NORMAL);
- verify(mTracker).removeObservers();
+ FrameTracker tracker = spyFrameTracker(
+ CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
+ tracker.cancel(FrameTracker.REASON_CANCEL_NORMAL);
+ verify(tracker).removeObservers();
}
@Test
public void testEndWhenSessionNeverBegun() {
- mTracker.end(FrameTracker.REASON_END_NORMAL);
- verify(mTracker).removeObservers();
+ FrameTracker tracker = spyFrameTracker(
+ CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX, /* surfaceOnly= */ false);
+
+ tracker.end(FrameTracker.REASON_END_NORMAL);
+ verify(tracker).removeObservers();
}
- private void sendFirstWindowFrame(long durationMillis,
+ @Test
+ public void testSurfaceOnlyOtherFrameJanky() {
+ FrameTracker tracker = spyFrameTracker(
+ CUJ_WALLPAPER_TRANSITION, CUJ_POSTFIX, /* surfaceOnly= */ true);
+
+ when(mChoreographer.getVsyncId()).thenReturn(100L);
+ tracker.begin();
+ verify(mSurfaceControlWrapper).addJankStatsListener(any(), any());
+
+ // First frame - not janky
+ sendFrame(tracker, JANK_NONE, 100L);
+ // normal frame - not janky
+ sendFrame(tracker, JANK_NONE, 101L);
+ // a janky frame
+ sendFrame(tracker, JANK_APP_DEADLINE_MISSED, 102L);
+
+ when(mChoreographer.getVsyncId()).thenReturn(102L);
+ tracker.end(FrameTracker.REASON_CANCEL_NORMAL);
+
+ // an extra frame to trigger finish
+ sendFrame(tracker, JANK_NONE, 103L);
+
+ verify(mSurfaceControlWrapper).removeJankStatsListener(any());
+ verify(tracker).triggerPerfetto();
+ }
+
+ @Test
+ public void testSurfaceOnlyFirstFrameJanky() {
+ FrameTracker tracker = spyFrameTracker(
+ CUJ_WALLPAPER_TRANSITION, CUJ_POSTFIX, /* surfaceOnly= */ true);
+
+ when(mChoreographer.getVsyncId()).thenReturn(100L);
+ tracker.begin();
+ verify(mSurfaceControlWrapper).addJankStatsListener(any(), any());
+
+ // First frame - janky
+ sendFrame(tracker, JANK_APP_DEADLINE_MISSED, 100L);
+ // normal frame - not janky
+ sendFrame(tracker, JANK_NONE, 101L);
+ // normal frame - not janky
+ sendFrame(tracker, JANK_NONE, 102L);
+
+ when(mChoreographer.getVsyncId()).thenReturn(102L);
+ tracker.end(FrameTracker.REASON_CANCEL_NORMAL);
+
+ // an extra frame to trigger finish
+ sendFrame(tracker, JANK_NONE, 103L);
+
+ verify(mSurfaceControlWrapper).removeJankStatsListener(any());
+ verify(tracker, never()).triggerPerfetto();
+ }
+
+ @Test
+ public void testSurfaceOnlyLastFrameJanky() {
+ FrameTracker tracker = spyFrameTracker(
+ CUJ_WALLPAPER_TRANSITION, CUJ_POSTFIX, /* surfaceOnly= */ true);
+
+ when(mChoreographer.getVsyncId()).thenReturn(100L);
+ tracker.begin();
+ verify(mSurfaceControlWrapper).addJankStatsListener(any(), any());
+
+ // First frame - not janky
+ sendFrame(tracker, JANK_NONE, 100L);
+ // normal frame - not janky
+ sendFrame(tracker, JANK_NONE, 101L);
+ // normal frame - not janky
+ sendFrame(tracker, JANK_NONE, 102L);
+
+ when(mChoreographer.getVsyncId()).thenReturn(102L);
+ tracker.end(FrameTracker.REASON_CANCEL_NORMAL);
+
+ // janky frame, should be ignored, trigger finish
+ sendFrame(tracker, JANK_APP_DEADLINE_MISSED, 103L);
+
+ verify(mSurfaceControlWrapper).removeJankStatsListener(any());
+ verify(tracker, never()).triggerPerfetto();
+ }
+
+ private void sendFirstWindowFrame(FrameTracker tracker, long durationMillis,
@JankType int jankType, long vsyncId) {
- sendFrame(durationMillis, jankType, vsyncId, true /* firstWindowFrame */);
+ sendFrame(tracker, durationMillis, jankType, vsyncId, /* firstWindowFrame= */ true);
}
- private void sendFrame(long durationMillis,
+ private void sendFrame(FrameTracker tracker, long durationMillis,
@JankType int jankType, long vsyncId) {
- sendFrame(durationMillis, jankType, vsyncId, false /* firstWindowFrame */);
+ sendFrame(tracker, durationMillis, jankType, vsyncId, /* firstWindowFrame= */ false);
+ }
+
+ /**
+ * Used for surface only test.
+ */
+ private void sendFrame(FrameTracker tracker, @JankType int jankType, long vsyncId) {
+ sendFrame(tracker, /* durationMillis= */ -1,
+ jankType, vsyncId, /* firstWindowFrame= */ false);
}
- private void sendFrame(long durationMillis,
+ private void sendFrame(FrameTracker tracker, long durationMillis,
@JankType int jankType, long vsyncId, boolean firstWindowFrame) {
- when(mWrapper.getTiming()).thenReturn(new long[] { 0, vsyncId });
- doReturn(firstWindowFrame ? 1L : 0L).when(mWrapper)
- .getMetric(FrameMetrics.FIRST_DRAW_FRAME);
- doReturn(TimeUnit.MILLISECONDS.toNanos(durationMillis))
- .when(mWrapper).getMetric(FrameMetrics.TOTAL_DURATION);
- mTracker.onFrameMetricsAvailable(0);
+ if (!tracker.mSurfaceOnly) {
+ when(mWrapper.getTiming()).thenReturn(new long[]{0, vsyncId});
+ doReturn(firstWindowFrame ? 1L : 0L).when(mWrapper)
+ .getMetric(FrameMetrics.FIRST_DRAW_FRAME);
+ doReturn(TimeUnit.MILLISECONDS.toNanos(durationMillis))
+ .when(mWrapper).getMetric(FrameMetrics.TOTAL_DURATION);
+ tracker.onFrameMetricsAvailable(0);
+ }
mListenerCapture.getValue().onJankDataAvailable(new JankData[] {
new JankData(vsyncId, jankType)
});
diff --git a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
index c153b38d3f02..d7a5e2613175 100644
--- a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
@@ -16,8 +16,6 @@
package com.android.internal.jank;
-import static com.android.internal.jank.FrameTracker.SurfaceControlWrapper;
-import static com.android.internal.jank.FrameTracker.ViewRootWrapper;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_TO_STATSD_INTERACTION_TYPE;
@@ -25,17 +23,17 @@ import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.os.Handler;
import android.os.HandlerThread;
-import android.os.Message;
import android.provider.DeviceConfig;
import android.view.View;
import android.view.ViewAttachTestActivity;
@@ -43,8 +41,12 @@ import android.view.ViewAttachTestActivity;
import androidx.test.filters.SmallTest;
import androidx.test.rule.ActivityTestRule;
+import com.android.internal.jank.FrameTracker.ChoreographerWrapper;
import com.android.internal.jank.FrameTracker.FrameMetricsWrapper;
+import com.android.internal.jank.FrameTracker.SurfaceControlWrapper;
import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper;
+import com.android.internal.jank.FrameTracker.ViewRootWrapper;
+import com.android.internal.jank.InteractionJankMonitor.Configuration;
import com.android.internal.jank.InteractionJankMonitor.Session;
import org.junit.Before;
@@ -92,12 +94,15 @@ public class InteractionJankMonitorTest {
verify(mWorker).start();
Session session = new Session(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX);
+ Configuration config = mock(Configuration.class);
+ when(config.isSurfaceOnly()).thenReturn(false);
FrameTracker tracker = spy(new FrameTracker(session, mWorker.getThreadHandler(),
new ThreadedRendererWrapper(mView.getThreadedRenderer()),
- new ViewRootWrapper(mView.getViewRootImpl()), new SurfaceControlWrapper(),
- mock(FrameTracker.ChoreographerWrapper.class),
- new FrameMetricsWrapper(), /*traceThresholdMissedFrames=*/ 1,
- /*traceThresholdFrameTimeMillis=*/ -1, null));
+ new ViewRootWrapper(mView.getViewRootImpl()),
+ new SurfaceControlWrapper(), mock(ChoreographerWrapper.class),
+ new FrameMetricsWrapper(),
+ /* traceThresholdMissedFrames= */ 1, /* traceThresholdFrameTimeMillis= */ -1,
+ /* FrameTrackerListener */ null, config));
doReturn(tracker).when(monitor).createFrameTracker(any(), any());
doNothing().when(tracker).triggerPerfetto();
doNothing().when(tracker).postTraceStartMarker();
@@ -138,28 +143,30 @@ public class InteractionJankMonitorTest {
public void testBeginCancel() {
InteractionJankMonitor monitor = spy(new InteractionJankMonitor(mWorker));
- ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
+ ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
Session session = new Session(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX);
+ Configuration config = mock(Configuration.class);
+ when(config.isSurfaceOnly()).thenReturn(false);
FrameTracker tracker = spy(new FrameTracker(session, mWorker.getThreadHandler(),
new ThreadedRendererWrapper(mView.getThreadedRenderer()),
- new ViewRootWrapper(mView.getViewRootImpl()), new SurfaceControlWrapper(),
- mock(FrameTracker.ChoreographerWrapper.class),
- new FrameMetricsWrapper(), /*traceThresholdMissedFrames=*/ 1,
- /*traceThresholdFrameTimeMillis=*/ -1, null));
+ new ViewRootWrapper(mView.getViewRootImpl()),
+ new SurfaceControlWrapper(), mock(FrameTracker.ChoreographerWrapper.class),
+ new FrameMetricsWrapper(),
+ /* traceThresholdMissedFrames= */ 1, /* traceThresholdFrameTimeMillis= */ -1,
+ /* FrameTrackerListener */ null, config));
doReturn(tracker).when(monitor).createFrameTracker(any(), any());
doNothing().when(tracker).triggerPerfetto();
doNothing().when(tracker).postTraceStartMarker();
assertThat(monitor.begin(mView, session.getCuj())).isTrue();
verify(tracker).begin();
- verify(mWorker.getThreadHandler(), atLeastOnce()).sendMessageAtTime(captor.capture(),
- anyLong());
- Runnable runnable = captor.getValue().getCallback();
+ verify(monitor).scheduleTimeoutAction(anyInt(), anyLong(), captor.capture());
+ Runnable runnable = captor.getValue();
assertThat(runnable).isNotNull();
mWorker.getThreadHandler().removeCallbacks(runnable);
runnable.run();
- verify(tracker).cancel(FrameTracker.REASON_CANCEL_NORMAL);
+ verify(tracker).cancel(FrameTracker.REASON_CANCEL_TIMEOUT);
}
@Test
diff --git a/core/tests/coretests/src/com/android/internal/os/ProcLocksReaderTest.java b/core/tests/coretests/src/com/android/internal/os/ProcLocksReaderTest.java
new file mode 100644
index 000000000000..d800c2c3c66e
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/ProcLocksReaderTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.os.FileUtils;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.nio.file.Files;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ProcLocksReaderTest {
+ private File mProcDirectory;
+
+ @Before
+ public void setUp() {
+ Context context = InstrumentationRegistry.getContext();
+ mProcDirectory = context.getDir("proc", Context.MODE_PRIVATE);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ FileUtils.deleteContents(mProcDirectory);
+ }
+
+ @Test
+ public void testRunSimpleLocks() throws Exception {
+ String simpleLocks =
+ "1: POSIX ADVISORY READ 18403 fd:09:9070 1073741826 1073742335\n" +
+ "2: POSIX ADVISORY WRITE 18292 fd:09:34062 0 EOF\n";
+ assertFalse(runHasFileLocks(simpleLocks, 18402));
+ assertFalse(runHasFileLocks(simpleLocks, 18404));
+ assertTrue(runHasFileLocks(simpleLocks, 18403));
+ assertTrue(runHasFileLocks(simpleLocks, 18292));
+ }
+
+ @Test
+ public void testRunBlockedLocks() throws Exception {
+ String blockedLocks =
+ "1: POSIX ADVISORY READ 18403 fd:09:9070 1073741826 1073742335\n" +
+ "2: POSIX ADVISORY WRITE 18292 fd:09:34062 0 EOF\n" +
+ "2: -> POSIX ADVISORY WRITE 18291 fd:09:34062 0 EOF\n" +
+ "2: -> POSIX ADVISORY WRITE 18293 fd:09:34062 0 EOF\n" +
+ "3: POSIX ADVISORY READ 3888 fd:09:13992 128 128\n" +
+ "4: POSIX ADVISORY READ 3888 fd:09:14230 1073741826 1073742335\n";
+ assertFalse(runHasFileLocks(blockedLocks, 18402));
+ assertFalse(runHasFileLocks(blockedLocks, 18404));
+ assertTrue(runHasFileLocks(blockedLocks, 18403));
+ assertTrue(runHasFileLocks(blockedLocks, 18292));
+
+ assertFalse(runHasFileLocks(blockedLocks, 18291));
+ assertFalse(runHasFileLocks(blockedLocks, 18293));
+ assertTrue(runHasFileLocks(blockedLocks, 3888));
+ }
+
+ private boolean runHasFileLocks(String fileContents, int pid) throws Exception {
+ File tempFile = File.createTempFile("locks", null, mProcDirectory);
+ Files.write(tempFile.toPath(), fileContents.getBytes());
+ boolean result = new ProcLocksReader(tempFile.toString()).hasFileLocks(pid);
+ Files.delete(tempFile.toPath());
+ return result;
+ }
+}
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index 269d8424a78f..516a5d288c0f 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -299,7 +299,7 @@ public class ActivityThreadClientTest {
null /* activityOptions */, true /* isForward */, null /* profilerInfo */,
mThread /* client */, null /* asssitToken */,
null /* fixedRotationAdjustments */, null /* shareableActivityToken */,
- false /* launchedFromBubble */);
+ false /* launchedFromBubble */, null /* taskfragmentToken */);
}
@Override
diff --git a/core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java b/core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java
index b6da1954ba79..0532628ba16d 100644
--- a/core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java
@@ -166,6 +166,46 @@ public class ProcFileReaderTest extends AndroidTestCase {
assertEquals(-1L, reader.nextOptionalLong(-1L));
}
+ public void testInvalidLongs() throws Exception {
+ final ProcFileReader reader = buildReader("12: 34\n56 78@#\n");
+
+ assertEquals(12L, reader.nextLong(true));
+ assertEquals(34L, reader.nextLong(true));
+ reader.finishLine();
+ assertTrue(reader.hasMoreData());
+
+ assertEquals(56L, reader.nextLong(true));
+ assertEquals(78L, reader.nextLong(true));
+ reader.finishLine();
+ assertFalse(reader.hasMoreData());
+ }
+
+ public void testConsecutiveDelimiters() throws Exception {
+ final ProcFileReader reader = buildReader("1 2 3 4 5\n");
+
+ assertEquals(1L, reader.nextLong());
+ assertEquals(2L, reader.nextLong());
+ assertEquals(3L, reader.nextLong());
+ assertEquals(4L, reader.nextLong());
+ assertEquals(5L, reader.nextLong());
+ reader.finishLine();
+ assertFalse(reader.hasMoreData());
+ }
+
+ public void testIgnore() throws Exception {
+ final ProcFileReader reader = buildReader("a b c\n");
+
+ assertEquals("a", reader.nextString());
+ assertTrue(reader.hasMoreData());
+
+ reader.nextIgnored();
+ assertTrue(reader.hasMoreData());
+
+ assertEquals("c", reader.nextString());
+ reader.finishLine();
+ assertFalse(reader.hasMoreData());
+ }
+
private static ProcFileReader buildReader(String string) throws IOException {
return buildReader(string, 2048);
}
diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java
index 6c1c2ee1ee57..36215ecc1403 100644
--- a/graphics/java/android/graphics/BLASTBufferQueue.java
+++ b/graphics/java/android/graphics/BLASTBufferQueue.java
@@ -33,7 +33,7 @@ public final class BLASTBufferQueue {
private static native Surface nativeGetSurface(long ptr, boolean includeSurfaceControlHandle);
private static native void nativeSetNextTransaction(long ptr, long transactionPtr);
private static native void nativeUpdate(long ptr, long surfaceControl, long width, long height,
- int format);
+ int format, long transactionPtr);
private static native void nativeFlushShadowQueue(long ptr);
private static native void nativeMergeWithNextTransaction(long ptr, long transactionPtr,
long frameNumber);
@@ -92,9 +92,15 @@ public final class BLASTBufferQueue {
* @param width The new width for the buffer.
* @param height The new height for the buffer.
* @param format The new format for the buffer.
+ * @param t Adds destination frame changes to the passed in transaction.
*/
+ public void update(SurfaceControl sc, int width, int height, @PixelFormat.Format int format,
+ SurfaceControl.Transaction t) {
+ nativeUpdate(mNativeObject, sc.mNativeObject, width, height, format, t.mNativeObject);
+ }
+
public void update(SurfaceControl sc, int width, int height, @PixelFormat.Format int format) {
- nativeUpdate(mNativeObject, sc.mNativeObject, width, height, format);
+ nativeUpdate(mNativeObject, sc.mNativeObject, width, height, format, 0);
}
/**
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 51bf6d539ce8..42e470b7f660 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -255,12 +255,6 @@ public class Paint {
| FILTER_BITMAP_FLAG;
/**
- * These flags are always set on a reset paint or a new paint instantiated using
- * {@link #Paint()}.
- */
- private static final int DEFAULT_PAINT_FLAGS = ANTI_ALIAS_FLAG | DITHER_FLAG;
-
- /**
* Font hinter option that disables font hinting.
*
* @see #setHinting(int)
@@ -577,12 +571,12 @@ public class Paint {
* On devices running {@link Build.VERSION_CODES#Q} and above,
* {@code FILTER_BITMAP_FLAG} is set by this constructor, and it can be
* cleared with {@link #setFlags} or {@link #setFilterBitmap}.
- * On devices running {@link Build.VERSION_CODES#S} and above, {@code ANTI_ALIAS_FLAG} and
- * {@code DITHER_FLAG} are set by this constructor, and they can be cleared with
- * {@link #setFlags} or {@link #setAntiAlias} and {@link #setDither}, respectively.</p>
+ * On devices running {@link Build.VERSION_CODES#S} and above, {@code ANTI_ALIAS_FLAG}
+ * is set by this constructor, and it can be cleared with {@link #setFlags} or
+ * {@link #setAntiAlias}.</p>
*/
public Paint() {
- this(DEFAULT_PAINT_FLAGS);
+ this(ANTI_ALIAS_FLAG);
}
/**
@@ -627,7 +621,7 @@ public class Paint {
/** Restores the paint to its default settings. */
public void reset() {
nReset(mNativePaint);
- setFlags(HIDDEN_DEFAULT_PAINT_FLAGS | DEFAULT_PAINT_FLAGS);
+ setFlags(HIDDEN_DEFAULT_PAINT_FLAGS | ANTI_ALIAS_FLAG);
// TODO: Turning off hinting has undesirable side effects, we need to
// revisit hinting once we add support for subpixel positioning
diff --git a/graphics/java/android/graphics/drawable/RippleAnimationSession.java b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
index 492520910afd..872331c82603 100644
--- a/graphics/java/android/graphics/drawable/RippleAnimationSession.java
+++ b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
@@ -67,7 +67,7 @@ public final class RippleAnimationSession {
@NonNull RippleAnimationSession enter(Canvas canvas) {
mStartTime = AnimationUtils.currentAnimationTimeMillis();
- if (isHwAccelerated(canvas)) {
+ if (useRTAnimations(canvas)) {
enterHardware((RecordingCanvas) canvas);
} else {
enterSoftware();
@@ -82,7 +82,7 @@ public final class RippleAnimationSession {
}
@NonNull RippleAnimationSession exit(Canvas canvas) {
- if (isHwAccelerated(canvas)) exitHardware((RecordingCanvas) canvas);
+ if (useRTAnimations(canvas)) exitHardware((RecordingCanvas) canvas);
else exitSoftware();
return this;
}
@@ -102,8 +102,12 @@ public final class RippleAnimationSession {
return this;
}
- private boolean isHwAccelerated(Canvas canvas) {
- return canvas.isHardwareAccelerated() && !mForceSoftware;
+ private boolean useRTAnimations(Canvas canvas) {
+ if (mForceSoftware) return false;
+ if (!canvas.isHardwareAccelerated()) return false;
+ RecordingCanvas hwCanvas = (RecordingCanvas) canvas;
+ if (hwCanvas.mNode == null || !hwCanvas.mNode.isAttached()) return false;
+ return true;
}
private void exitSoftware() {
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index d3cff5cb81ff..7354c90c5c98 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -49,7 +49,9 @@ import android.graphics.RecordingCanvas;
import android.graphics.Rect;
import android.graphics.Shader;
import android.os.Build;
+import android.os.Looper;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
@@ -113,6 +115,7 @@ import java.util.Arrays;
* @attr ref android.R.styleable#RippleDrawable_color
*/
public class RippleDrawable extends LayerDrawable {
+ private static final String TAG = "RippleDrawable";
/**
* Radius value that specifies the ripple radius should be computed based
* on the size of the ripple's container.
@@ -848,6 +851,10 @@ public class RippleDrawable extends LayerDrawable {
private void startBackgroundAnimation() {
mRunBackgroundAnimation = false;
+ if (Looper.myLooper() == null) {
+ Log.w(TAG, "Thread doesn't have a looper. Skipping animation.");
+ return;
+ }
mBackgroundAnimation = ValueAnimator.ofFloat(mBackgroundOpacity, mTargetBackgroundOpacity);
mBackgroundAnimation.setInterpolator(LINEAR_INTERPOLATOR);
mBackgroundAnimation.setDuration(BACKGROUND_OPACITY_DURATION);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
index 27bd53d6b98d..531df30a4e2c 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
@@ -116,6 +116,9 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
secondaryFragmentBounds, WINDOWING_MODE_MULTI_WINDOW, activityIntent,
activityOptions);
+ // Set adjacent to each other so that the containers below will be invisible.
+ wct.setAdjacentTaskFragments(launchingFragmentToken, secondaryFragmentToken);
+
applyTransaction(wct);
}
@@ -126,6 +129,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
*/
void expandTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken) {
resizeTaskFragment(wct, fragmentToken, new Rect());
+ wct.setAdjacentTaskFragments(fragmentToken, null);
}
/**
@@ -155,13 +159,22 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
* @param ownerToken The token of the activity that creates this task fragment. It does not
* have to be a child of this task fragment, but must belong to the same task.
*/
+ void createTaskFragment(WindowContainerTransaction wct, IBinder fragmentToken,
+ IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode) {
+ final TaskFragmentCreationParams fragmentOptions =
+ createFragmentOptions(fragmentToken, ownerToken, bounds, windowingMode);
+ wct.createTaskFragment(fragmentOptions);
+ }
+
+ /**
+ * @param ownerToken The token of the activity that creates this task fragment. It does not
+ * have to be a child of this task fragment, but must belong to the same task.
+ */
private void createTaskFragmentAndReparentActivity(
WindowContainerTransaction wct, IBinder fragmentToken, IBinder ownerToken,
@NonNull Rect bounds, @WindowingMode int windowingMode, Activity activity) {
- final TaskFragmentCreationParams fragmentOptions =
- createFragmentOptions(fragmentToken, ownerToken, bounds, windowingMode);
- wct.createTaskFragment(fragmentOptions)
- .reparentActivityToTaskFragment(fragmentToken, activity.getActivityToken());
+ createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode);
+ wct.reparentActivityToTaskFragment(fragmentToken, activity.getActivityToken());
}
/**
@@ -172,11 +185,8 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
WindowContainerTransaction wct, IBinder fragmentToken, IBinder ownerToken,
@NonNull Rect bounds, @WindowingMode int windowingMode, Intent activityIntent,
@Nullable Bundle activityOptions) {
- final TaskFragmentCreationParams fragmentOptions =
- createFragmentOptions(fragmentToken, ownerToken, bounds, windowingMode);
- wct.createTaskFragment(fragmentOptions)
- .startActivityInTaskFragment(fragmentToken, ownerToken, activityIntent,
- activityOptions);
+ createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode);
+ wct.startActivityInTaskFragment(fragmentToken, ownerToken, activityIntent, activityOptions);
}
TaskFragmentCreationParams createFragmentOptions(IBinder fragmentToken, IBinder ownerToken,
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
index 407c43d9226a..802976fbfc6d 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
@@ -20,9 +20,12 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityClient;
+import android.app.ActivityOptions;
import android.app.ActivityThread;
import android.app.Application.ActivityLifecycleCallbacks;
+import android.app.Instrumentation;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
@@ -61,9 +64,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
public SplitController() {
mPresenter = new SplitPresenter(new MainThreadExecutor(), this);
+ ActivityThread activityThread = ActivityThread.currentActivityThread();
// Register a callback to be notified about activities being created.
- ActivityThread.currentActivityThread().getApplication().registerActivityLifecycleCallbacks(
+ activityThread.getApplication().registerActivityLifecycleCallbacks(
new LifecycleCallbacks());
+ // Intercept activity starts to route activities to new containers if necessary.
+ Instrumentation instrumentation = activityThread.getInstrumentation();
+ instrumentation.addMonitor(new ActivityStartMonitor());
}
public void setSplitRules(@NonNull List<ExtensionSplitRule> splitRules) {
@@ -118,8 +125,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
}
container.setInfo(taskFragmentInfo);
- if (taskFragmentInfo.isEmpty()) {
- cleanupContainer(container, true /* shouldFinishDependent */);
+ // Check if there are no running activities - consider the container empty if there are no
+ // non-finishing activities left.
+ if (!taskFragmentInfo.hasRunningActivity()) {
+ mPresenter.cleanupContainer(container, true /* shouldFinishDependent */);
updateCallbackIfNecessary();
}
}
@@ -131,7 +140,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
return;
}
- cleanupContainer(container, true /* shouldFinishDependent */);
+ mPresenter.cleanupContainer(container, true /* shouldFinishDependent */);
updateCallbackIfNecessary();
}
@@ -155,7 +164,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
final List<ExtensionSplitRule> splitRules = getSplitRules();
final TaskFragmentContainer currentContainer = getContainerWithActivity(
- launchedActivity.getActivityToken());
+ launchedActivity.getActivityToken(), launchedActivity);
// Check if the activity is configured to always be expanded.
if (shouldExpand(componentName, splitRules)) {
@@ -247,9 +256,29 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
*/
@Nullable
TaskFragmentContainer getContainerWithActivity(@NonNull IBinder activityToken) {
+ return getContainerWithActivity(activityToken, null /* activityToAdd */);
+ }
+
+ /**
+ * This method can only be called from {@link #onActivityCreated(Activity)}, use
+ * {@link #getContainerWithActivity(IBinder) } otherwise.
+ *
+ * Returns a container that this activity is registered with. The activity could be created
+ * before the container appeared, adding the activity to the container if so.
+ */
+ @Nullable
+ private TaskFragmentContainer getContainerWithActivity(@NonNull IBinder activityToken,
+ Activity activityToAdd) {
+ final IBinder taskFragmentToken = ActivityThread.currentActivityThread().getActivityClient(
+ activityToken).mInitialTaskFragmentToken;
for (TaskFragmentContainer container : mContainers) {
if (container.hasActivity(activityToken)) {
return container;
+ } else if (container.getTaskFragmentToken().equals(taskFragmentToken)) {
+ if (activityToAdd != null) {
+ container.addPendingAppearedActivity(activityToAdd);
+ }
+ return container;
}
}
@@ -278,13 +307,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
mSplitContainers.add(splitContainer);
}
- void cleanupContainer(@NonNull TaskFragmentContainer container, boolean shouldFinishDependent) {
- if (container.isFinished()) {
- return;
- }
-
- container.finish(shouldFinishDependent);
-
+ /**
+ * Removes the container from bookkeeping records.
+ */
+ void removeContainer(@NonNull TaskFragmentContainer container) {
// Remove all split containers that included this one
mContainers.remove(container);
List<SplitContainer> containersToRemove = new ArrayList<>();
@@ -295,8 +321,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
}
}
mSplitContainers.removeAll(containersToRemove);
-
- mPresenter.deleteContainer(container);
}
/**
@@ -433,7 +457,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
return false;
}
- cleanupContainer(splitContainer.getSecondaryContainer(),
+ mPresenter.cleanupContainer(splitContainer.getSecondaryContainer(),
false /* shouldFinishDependent */);
return true;
}
@@ -644,4 +668,40 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
handler.post(r);
}
}
+
+ /**
+ * A monitor that intercepts all activity start requests originating in the client process and
+ * can amend them to target a specific task fragment to form a split.
+ */
+ private class ActivityStartMonitor extends Instrumentation.ActivityMonitor {
+
+ @Override
+ public Instrumentation.ActivityResult onStartActivity(Context who, Intent intent,
+ Bundle options) {
+ // TODO(b/190433398): Check if the activity is configured to always be expanded.
+
+ // Check if activity should be put in a split with the activity that launched it.
+ if (!(who instanceof Activity)) {
+ return super.onStartActivity(who, intent, options);
+ }
+ final Activity launchingActivity = (Activity) who;
+
+ final ExtensionSplitPairRule splitPairRule = getSplitRule(
+ launchingActivity.getComponentName(), intent.getComponent(), getSplitRules());
+ if (splitPairRule == null) {
+ return super.onStartActivity(who, intent, options);
+ }
+
+ // Create a new split with an empty side container
+ final TaskFragmentContainer secondaryContainer = mPresenter
+ .createNewSplitWithEmptySideContainer(launchingActivity, splitPairRule);
+
+ // Amend the request to let the WM know that the activity should be placed in the
+ // dedicated container.
+ options.putBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN,
+ secondaryContainer.getTaskFragmentToken());
+
+ return super.onStartActivity(who, intent, options);
+ }
+ }
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java
index 90af72b6a485..0f356291f50e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitPresenter.java
@@ -68,11 +68,13 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
}
/**
- * Deletes the provided container and updates the presentation if necessary.
+ * Deletes the specified container and all other associated and dependent containers in the same
+ * transaction.
*/
- void deleteContainer(TaskFragmentContainer container) {
+ void cleanupContainer(@NonNull TaskFragmentContainer container, boolean shouldFinishDependent) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
- deleteTaskFragment(wct, container.getTaskFragmentToken());
+
+ container.finish(shouldFinishDependent, this, wct, mController);
final TaskFragmentContainer newTopContainer = mController.getTopActiveContainer();
if (newTopContainer != null) {
@@ -83,6 +85,37 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
}
/**
+ * Creates a new split with the primary activity and an empty secondary container.
+ * @return The newly created secondary container.
+ */
+ TaskFragmentContainer createNewSplitWithEmptySideContainer(@NonNull Activity primaryActivity,
+ @NonNull ExtensionSplitPairRule rule) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+
+ final Rect parentBounds = getParentContainerBounds(primaryActivity);
+ final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
+ final TaskFragmentContainer primaryContainer = prepareContainerForActivity(wct,
+ primaryActivity, primaryRectBounds, null);
+
+ // Create new empty task fragment
+ TaskFragmentContainer secondaryContainer = mController.newContainer(null);
+ final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
+ createTaskFragment(wct, secondaryContainer.getTaskFragmentToken(),
+ primaryActivity.getActivityToken(), secondaryRectBounds,
+ WINDOWING_MODE_MULTI_WINDOW);
+ secondaryContainer.setLastRequestedBounds(secondaryRectBounds);
+
+ // Set adjacent to each other so that the containers below will be invisible.
+ wct.setAdjacentTaskFragments(
+ primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken());
+ applyTransaction(wct);
+
+ mController.registerSplit(primaryContainer, primaryActivity, secondaryContainer, rule);
+
+ return secondaryContainer;
+ }
+
+ /**
* Creates a new split container with the two provided activities.
* @param primaryActivity An activity that should be in the primary container. If it is not
* currently in an existing container, a new one will be created and the
@@ -99,54 +132,51 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
final Rect parentBounds = getParentContainerBounds(primaryActivity);
final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
- TaskFragmentContainer primaryContainer = mController.getContainerWithActivity(
- primaryActivity.getActivityToken());
- if (primaryContainer == null) {
- primaryContainer = mController.newContainer(primaryActivity);
+ final TaskFragmentContainer primaryContainer = prepareContainerForActivity(wct,
+ primaryActivity, primaryRectBounds, null);
- final TaskFragmentCreationParams fragmentOptions =
- createFragmentOptions(
- primaryContainer.getTaskFragmentToken(),
- primaryActivity.getActivityToken(),
- primaryRectBounds,
- WINDOWING_MODE_MULTI_WINDOW);
- wct.createTaskFragment(fragmentOptions);
+ final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
+ final TaskFragmentContainer secondaryContainer = prepareContainerForActivity(wct,
+ secondaryActivity, secondaryRectBounds, primaryContainer);
- wct.reparentActivityToTaskFragment(primaryContainer.getTaskFragmentToken(),
- primaryActivity.getActivityToken());
+ // Set adjacent to each other so that the containers below will be invisible.
+ wct.setAdjacentTaskFragments(
+ primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken());
+ applyTransaction(wct);
- primaryContainer.setLastRequestedBounds(primaryRectBounds);
- } else {
- resizeTaskFragmentIfRegistered(wct, primaryContainer, primaryRectBounds);
- }
+ mController.registerSplit(primaryContainer, primaryActivity, secondaryContainer, rule);
+ }
- final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
- TaskFragmentContainer secondaryContainer = mController.getContainerWithActivity(
- secondaryActivity.getActivityToken());
- if (secondaryContainer == null || secondaryContainer == primaryContainer) {
- secondaryContainer = mController.newContainer(secondaryActivity);
+ /**
+ * Creates a new container or resizes an existing container for activity to the provided bounds.
+ * @param activity The activity to be re-parented to the container if necessary.
+ * @param containerToAvoid Re-parent from this container if an activity is already in it.
+ */
+ private TaskFragmentContainer prepareContainerForActivity(
+ @NonNull WindowContainerTransaction wct, @NonNull Activity activity,
+ @NonNull Rect bounds, @Nullable TaskFragmentContainer containerToAvoid) {
+ TaskFragmentContainer container = mController.getContainerWithActivity(
+ activity.getActivityToken());
+ if (container == null || container == containerToAvoid) {
+ container = mController.newContainer(activity);
final TaskFragmentCreationParams fragmentOptions =
createFragmentOptions(
- secondaryContainer.getTaskFragmentToken(),
- secondaryActivity.getActivityToken(),
- secondaryRectBounds,
+ container.getTaskFragmentToken(),
+ activity.getActivityToken(),
+ bounds,
WINDOWING_MODE_MULTI_WINDOW);
wct.createTaskFragment(fragmentOptions);
- wct.reparentActivityToTaskFragment(secondaryContainer.getTaskFragmentToken(),
- secondaryActivity.getActivityToken());
+ wct.reparentActivityToTaskFragment(container.getTaskFragmentToken(),
+ activity.getActivityToken());
- secondaryContainer.setLastRequestedBounds(secondaryRectBounds);
+ container.setLastRequestedBounds(bounds);
} else {
- resizeTaskFragmentIfRegistered(wct, secondaryContainer, secondaryRectBounds);
+ resizeTaskFragmentIfRegistered(wct, container, bounds);
}
- // TODO(b/190433398): The primary container and the secondary container should also be set
- // as adjacent (WCT#setAdjacentRoots) to make activities behind invisible.
- applyTransaction(wct);
-
- mController.registerSplit(primaryContainer, primaryActivity, secondaryContainer, rule);
+ return container;
}
/**
@@ -184,9 +214,6 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
primaryContainer.setLastRequestedBounds(primaryRectBounds);
secondaryContainer.setLastRequestedBounds(secondaryRectBounds);
- // TODO(b/190433398): The primary container and the secondary container should also be set
- // as adjacent (WCT#setAdjacentRoots) to make activities behind invisible.
-
mController.registerSplit(primaryContainer, launchingActivity, secondaryContainer,
rule);
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java
index 368adeffce31..a4f5c75276f5 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java
@@ -24,6 +24,7 @@ import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.window.TaskFragmentInfo;
+import android.window.WindowContainerTransaction;
import java.util.ArrayList;
import java.util.List;
@@ -45,10 +46,10 @@ class TaskFragmentContainer {
private TaskFragmentInfo mInfo;
/**
- * Activity that is being reparented to this container, but haven't been added to {@link #mInfo}
- * yet.
+ * Activities that are being reparented or being started to this container, but haven't been
+ * added to {@link #mInfo} yet.
*/
- private Activity mReparentingActivity;
+ private final ArrayList<Activity> mPendingAppearedActivities = new ArrayList<>();
/** Containers that are dependent on this one and should be completely destroyed on exit. */
private final List<TaskFragmentContainer> mContainersToFinishOnExit =
@@ -71,7 +72,9 @@ class TaskFragmentContainer {
*/
TaskFragmentContainer(@Nullable Activity activity) {
mToken = new Binder("TaskFragmentContainer");
- mReparentingActivity = activity;
+ if (activity != null) {
+ addPendingAppearedActivity(activity);
+ }
}
/**
@@ -89,8 +92,8 @@ class TaskFragmentContainer {
// fragment info update with it placed in this container. We still want to apply rules
// in this intermediate state.
List<Activity> allActivities = new ArrayList<>();
- if (mReparentingActivity != null) {
- allActivities.add(mReparentingActivity);
+ if (!mPendingAppearedActivities.isEmpty()) {
+ allActivities.addAll(mPendingAppearedActivities);
}
// Add activities reported from the server.
if (mInfo == null) {
@@ -106,12 +109,20 @@ class TaskFragmentContainer {
return allActivities;
}
+ void addPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
+ mPendingAppearedActivities.add(pendingAppearedActivity);
+ }
+
boolean hasActivity(@NonNull IBinder token) {
if (mInfo != null && mInfo.getActivities().contains(token)) {
return true;
}
- return mReparentingActivity != null
- && mReparentingActivity.getActivityToken().equals(token);
+ for (Activity activity : mPendingAppearedActivities) {
+ if (activity.getActivityToken().equals(token)) {
+ return true;
+ }
+ }
+ return false;
}
@Nullable
@@ -121,14 +132,15 @@ class TaskFragmentContainer {
void setInfo(@Nullable TaskFragmentInfo info) {
mInfo = info;
- if (mInfo == null || mReparentingActivity == null) {
+ if (mInfo == null || mPendingAppearedActivities.isEmpty()) {
return;
}
// Cleanup activities that were being re-parented
- for (IBinder activityToken : mInfo.getActivities()) {
- if (mReparentingActivity.getActivityToken().equals(activityToken)) {
- mReparentingActivity = null;
- break;
+ List<IBinder> infoActivities = mInfo.getActivities();
+ for (int i = mPendingAppearedActivities.size() - 1; i >= 0; --i) {
+ final Activity activity = mPendingAppearedActivities.get(i);
+ if (infoActivities.contains(activity.getActivityToken())) {
+ mPendingAppearedActivities.remove(i);
}
}
}
@@ -147,7 +159,7 @@ class TaskFragmentContainer {
}
boolean isEmpty() {
- return mReparentingActivity == null && (mInfo == null || mInfo.isEmpty());
+ return mPendingAppearedActivities.isEmpty() && (mInfo == null || mInfo.isEmpty());
}
/**
@@ -168,7 +180,8 @@ class TaskFragmentContainer {
* Removes all activities that belong to this process and finishes other containers/activities
* configured to finish together.
*/
- void finish(boolean shouldFinishDependent) {
+ void finish(boolean shouldFinishDependent, @NonNull SplitPresenter presenter,
+ @NonNull WindowContainerTransaction wct, @NonNull SplitController controller) {
if (mIsFinished) {
return;
}
@@ -179,13 +192,19 @@ class TaskFragmentContainer {
activity.finish();
}
+ // Cleanup the visuals
+ presenter.deleteTaskFragment(wct, getTaskFragmentToken());
+ // Cleanup the records
+ controller.removeContainer(this);
+
if (!shouldFinishDependent) {
return;
}
// Finish dependent containers
for (TaskFragmentContainer container : mContainersToFinishOnExit) {
- container.finish(true /* shouldFinishDependent */);
+ container.finish(true /* shouldFinishDependent */, presenter,
+ wct, controller);
}
mContainersToFinishOnExit.clear();
@@ -196,10 +215,10 @@ class TaskFragmentContainer {
mActivitiesToFinishOnExit.clear();
// Finish activities that were being re-parented to this container.
- if (mReparentingActivity != null) {
- mReparentingActivity.finish();
- mReparentingActivity = null;
+ for (Activity activity : mPendingAppearedActivities) {
+ activity.finish();
}
+ mPendingAppearedActivities.clear();
}
boolean isFinished() {
diff --git a/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml b/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml
index 8710fb8ac69b..96d2d7c954d8 100644
--- a/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml
+++ b/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml
@@ -18,7 +18,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid
- android:color="@android:color/system_neutral1_900"
+ android:color="@android:color/system_neutral1_800"
/>
<corners android:radius="20dp" />
diff --git a/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml b/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml
index c09ae53746da..7658fca58822 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml
@@ -20,10 +20,10 @@
android:id="@+id/settings_button"
android:layout_gravity="start"
android:layout_width="wrap_content"
- android:layout_height="40dp"
- android:layout_marginTop="8dp"
- android:layout_marginLeft="16dp"
- android:layout_marginBottom="8dp"
+ android:layout_height="@dimen/bubble_manage_button_height"
+ android:layout_marginStart="@dimen/bubble_manage_button_margin"
+ android:layout_marginTop="@dimen/bubble_manage_button_margin"
+ android:layout_marginBottom="@dimen/bubble_manage_button_margin"
android:focusable="true"
android:text="@string/manage_bubbles_text"
android:textSize="@*android:dimen/text_size_body_2_material"
diff --git a/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml b/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml
index f4b3aca33dd7..298ad3025b00 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml
@@ -25,15 +25,15 @@
android:id="@+id/bubble_manage_menu_dismiss_container"
android:background="@drawable/bubble_manage_menu_row"
android:layout_width="match_parent"
- android:layout_height="48dp"
+ android:layout_height="@dimen/bubble_menu_item_height"
android:gravity="center_vertical"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
+ android:paddingStart="@dimen/bubble_menu_padding"
+ android:paddingEnd="@dimen/bubble_menu_padding"
android:orientation="horizontal">
<ImageView
- android:layout_width="24dp"
- android:layout_height="24dp"
+ android:layout_width="@dimen/bubble_menu_icon_size"
+ android:layout_height="@dimen/bubble_menu_icon_size"
android:src="@drawable/ic_remove_no_shadow"
android:tint="@color/bubbles_icon_tint"/>
@@ -50,15 +50,15 @@
android:id="@+id/bubble_manage_menu_dont_bubble_container"
android:background="@drawable/bubble_manage_menu_row"
android:layout_width="match_parent"
- android:layout_height="48dp"
+ android:layout_height="@dimen/bubble_menu_item_height"
android:gravity="center_vertical"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
+ android:paddingStart="@dimen/bubble_menu_padding"
+ android:paddingEnd="@dimen/bubble_menu_padding"
android:orientation="horizontal">
<ImageView
- android:layout_width="24dp"
- android:layout_height="24dp"
+ android:layout_width="@dimen/bubble_menu_icon_size"
+ android:layout_height="@dimen/bubble_menu_icon_size"
android:src="@drawable/bubble_ic_stop_bubble"
android:tint="@color/bubbles_icon_tint"/>
@@ -75,16 +75,16 @@
android:id="@+id/bubble_manage_menu_settings_container"
android:background="@drawable/bubble_manage_menu_row"
android:layout_width="match_parent"
- android:layout_height="48dp"
+ android:layout_height="@dimen/bubble_menu_item_height"
android:gravity="center_vertical"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
+ android:paddingStart="@dimen/bubble_menu_padding"
+ android:paddingEnd="@dimen/bubble_menu_padding"
android:orientation="horizontal">
<ImageView
android:id="@+id/bubble_manage_menu_settings_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
+ android:layout_width="@dimen/bubble_menu_icon_size"
+ android:layout_height="@dimen/bubble_menu_icon_size"
android:src="@drawable/ic_remove_no_shadow"/>
<TextView
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 624b8b37a1ee..c2b6ffbd1048 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -31,7 +31,7 @@
<string name="accessibility_action_pip_stash" msgid="4060775037619702641">"స్టాచ్"</string>
<string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ఆన్‌స్టాచ్"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"స్క్రీన్ విభజనతో యాప్‌ పని చేయకపోవచ్చు."</string>
- <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"అనువర్తనంలో స్క్రీన్ విభజనకు మద్దతు లేదు."</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"యాప్‌లో స్క్రీన్ విభజనకు మద్దతు లేదు."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ప్రత్యామ్నాయ డిస్‌ప్లేలో యాప్ పని చేయకపోవచ్చు."</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ప్రత్యామ్నాయ డిస్‌ప్లేల్లో ప్రారంభానికి యాప్ మద్దతు లేదు."</string>
<string name="accessibility_divider" msgid="703810061635792791">"విభజన స్క్రీన్ విభాగిని"</string>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index f28ee820eb35..7da31aa7d03a 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -100,6 +100,8 @@
<dimen name="bubble_flyout_space_from_bubble">8dp</dimen>
<!-- How much space to leave between the flyout text and the avatar displayed in the flyout. -->
<dimen name="bubble_flyout_avatar_message_space">6dp</dimen>
+ <!-- If the screen percentage is smaller than this, we'll use this value instead. -->
+ <dimen name="bubbles_flyout_min_width_large_screen">200dp</dimen>
<!-- Padding between status bar and bubbles when displayed in expanded state -->
<dimen name="bubble_padding_top">16dp</dimen>
<!-- Space between bubbles when expanded. -->
@@ -149,9 +151,17 @@
<!-- Extra padding around the dismiss target for bubbles -->
<dimen name="bubble_dismiss_slop">16dp</dimen>
<!-- Height of button allowing users to adjust settings for bubbles. -->
- <dimen name="bubble_manage_button_height">56dp</dimen>
+ <dimen name="bubble_manage_button_height">36dp</dimen>
+ <!-- Height of manage button including margins. -->
+ <dimen name="bubble_manage_button_total_height">68dp</dimen>
+ <!-- The margin around the outside of the manage button. -->
+ <dimen name="bubble_manage_button_margin">16dp</dimen>
<!-- Height of an item in the bubble manage menu. -->
<dimen name="bubble_menu_item_height">60dp</dimen>
+ <!-- Padding applied to the bubble manage menu. -->
+ <dimen name="bubble_menu_padding">16dp</dimen>
+ <!-- Size of the icons in the manage menu. -->
+ <dimen name="bubble_menu_icon_size">24dp</dimen>
<!-- Max width of the message bubble-->
<dimen name="bubble_message_max_width">144dp</dimen>
<!-- Min width of the message bubble -->
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
index d1fbf31e2b99..9bbede311d6d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
@@ -24,6 +24,7 @@ import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.draganddrop.DragAndDropController;
+import com.android.wm.shell.freeform.FreeformTaskListener;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -47,6 +48,7 @@ public class ShellInitImpl {
private final Optional<AppPairsController> mAppPairsOptional;
private final Optional<PipTouchHandler> mPipTouchHandlerOptional;
private final FullscreenTaskListener mFullscreenTaskListener;
+ private final Optional<FreeformTaskListener> mFreeformTaskListenerOptional;
private final ShellExecutor mMainExecutor;
private final Transitions mTransitions;
private final StartingWindowController mStartingWindow;
@@ -62,6 +64,7 @@ public class ShellInitImpl {
Optional<AppPairsController> appPairsOptional,
Optional<PipTouchHandler> pipTouchHandlerOptional,
FullscreenTaskListener fullscreenTaskListener,
+ Optional<Optional<FreeformTaskListener>> freeformTaskListenerOptional,
Transitions transitions,
StartingWindowController startingWindow,
ShellExecutor mainExecutor) {
@@ -74,6 +77,7 @@ public class ShellInitImpl {
mAppPairsOptional = appPairsOptional;
mFullscreenTaskListener = fullscreenTaskListener;
mPipTouchHandlerOptional = pipTouchHandlerOptional;
+ mFreeformTaskListenerOptional = freeformTaskListenerOptional.flatMap(f -> f);
mTransitions = transitions;
mMainExecutor = mainExecutor;
mStartingWindow = startingWindow;
@@ -108,6 +112,11 @@ public class ShellInitImpl {
// controller instead of the feature interface, can just initialize the touch handler if
// needed
mPipTouchHandlerOptional.ifPresent((handler) -> handler.init());
+
+ // Initialize optional freeform
+ mFreeformTaskListenerOptional.ifPresent(f ->
+ mShellTaskOrganizer.addListenerForType(
+ f, ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM));
}
@ExternalThread
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index ba0ab6db1003..ab8a21c58e9c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -71,12 +71,14 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
public static final int TASK_LISTENER_TYPE_FULLSCREEN = -2;
public static final int TASK_LISTENER_TYPE_MULTI_WINDOW = -3;
public static final int TASK_LISTENER_TYPE_PIP = -4;
+ public static final int TASK_LISTENER_TYPE_FREEFORM = -5;
@IntDef(prefix = {"TASK_LISTENER_TYPE_"}, value = {
TASK_LISTENER_TYPE_UNDEFINED,
TASK_LISTENER_TYPE_FULLSCREEN,
TASK_LISTENER_TYPE_MULTI_WINDOW,
TASK_LISTENER_TYPE_PIP,
+ TASK_LISTENER_TYPE_FREEFORM,
})
public @interface TaskListenerType {}
@@ -572,6 +574,7 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
case WINDOWING_MODE_PINNED:
return TASK_LISTENER_TYPE_PIP;
case WINDOWING_MODE_FREEFORM:
+ return TASK_LISTENER_TYPE_FREEFORM;
case WINDOWING_MODE_UNDEFINED:
default:
return TASK_LISTENER_TYPE_UNDEFINED;
@@ -586,6 +589,8 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
return "TASK_LISTENER_TYPE_MULTI_WINDOW";
case TASK_LISTENER_TYPE_PIP:
return "TASK_LISTENER_TYPE_PIP";
+ case TASK_LISTENER_TYPE_FREEFORM:
+ return "TASK_LISTENER_TYPE_FREEFORM";
case TASK_LISTENER_TYPE_UNDEFINED:
return "TASK_LISTENER_TYPE_UNDEFINED";
default:
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
index 8aca01d2467b..2aead9392e59 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
@@ -62,4 +62,10 @@ public class Interpolators {
*/
public static final Interpolator PANEL_CLOSE_ACCELERATED =
new PathInterpolator(0.3f, 0, 0.5f, 1);
+
+ public static final PathInterpolator SLOWDOWN_INTERPOLATOR =
+ new PathInterpolator(0.5f, 1f, 0.5f, 1f);
+
+ public static final PathInterpolator DIM_INTERPOLATOR =
+ new PathInterpolator(.23f, .87f, .52f, -0.11f);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
index 94a87583da89..8405385e174e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
@@ -215,7 +215,7 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou
if (mSplitLayout != null) {
if (mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)) {
- onBoundsChanged(mSplitLayout);
+ onLayoutChanged(mSplitLayout);
}
// updateConfiguration re-inits the dividerbar, so show it now
mSyncQueue.runInSync(t -> t.show(mSplitLayout.getDividerLeash()));
@@ -299,17 +299,24 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou
}
@Override
- public void onBoundsChanging(SplitLayout layout) {
+ public void onLayoutChanging(SplitLayout layout) {
mSyncQueue.runInSync(t ->
layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2));
}
@Override
- public void onBoundsChanged(SplitLayout layout) {
+ public void onLayoutChanged(SplitLayout layout) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
layout.applyTaskChanges(wct, mTaskInfo1, mTaskInfo2);
mSyncQueue.queue(wct);
mSyncQueue.runInSync(t ->
layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2));
}
+
+ @Override
+ public void onLayoutShifted(int offsetX, int offsetY, SplitLayout layout) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ layout.applyLayoutShifted(wct, offsetX, offsetY, mTaskInfo1, mTaskInfo2);
+ mController.getTaskOrganizer().applyTransaction(wct);
+ }
}
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 a02fa9b18e49..252b588ec63f 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
@@ -735,6 +735,10 @@ public class BubbleExpandedView extends LinearLayout {
mManageButton.getBoundsOnScreen(rect);
}
+ public int getManageButtonMargin() {
+ return ((LinearLayout.LayoutParams) mManageButton.getLayoutParams()).getMarginStart();
+ }
+
/**
* Cleans up anything related to the task and {@code TaskView}. If this view should be reused
* after this method is called, then
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
index 35a4f33ecf72..9374da4c4fab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
@@ -56,9 +56,6 @@ import com.android.wm.shell.common.TriangleShape;
* transform into the 'new' dot, which is used during flyout dismiss animations/gestures.
*/
public class BubbleFlyoutView extends FrameLayout {
- /** Max width of the flyout, in terms of percent of the screen width. */
- private static final float FLYOUT_MAX_WIDTH_PERCENT = .6f;
-
/** Translation Y of fade animation. */
private static final float FLYOUT_FADE_Y = 40f;
@@ -68,6 +65,8 @@ public class BubbleFlyoutView extends FrameLayout {
// Whether the flyout view should show a pointer to the bubble.
private static final boolean SHOW_POINTER = false;
+ private BubblePositioner mPositioner;
+
private final int mFlyoutPadding;
private final int mFlyoutSpaceFromBubble;
private final int mPointerSize;
@@ -156,10 +155,11 @@ public class BubbleFlyoutView extends FrameLayout {
/** Callback to run when the flyout is hidden. */
@Nullable private Runnable mOnHide;
- public BubbleFlyoutView(Context context) {
+ public BubbleFlyoutView(Context context, BubblePositioner positioner) {
super(context);
- LayoutInflater.from(context).inflate(R.layout.bubble_flyout, this, true);
+ mPositioner = positioner;
+ LayoutInflater.from(context).inflate(R.layout.bubble_flyout, this, true);
mFlyoutTextContainer = findViewById(R.id.bubble_flyout_text_container);
mSenderText = findViewById(R.id.bubble_flyout_name);
mSenderAvatar = findViewById(R.id.bubble_flyout_avatar);
@@ -230,11 +230,11 @@ public class BubbleFlyoutView extends FrameLayout {
/*
* Fade animation for consecutive flyouts.
*/
- void animateUpdate(Bubble.FlyoutMessage flyoutMessage, float parentWidth, PointF stackPos,
+ void animateUpdate(Bubble.FlyoutMessage flyoutMessage, PointF stackPos,
boolean hideDot, Runnable onHide) {
mOnHide = onHide;
final Runnable afterFadeOut = () -> {
- updateFlyoutMessage(flyoutMessage, parentWidth);
+ updateFlyoutMessage(flyoutMessage);
// Wait for TextViews to layout with updated height.
post(() -> {
fade(true /* in */, stackPos, hideDot, () -> {} /* after */);
@@ -266,7 +266,7 @@ public class BubbleFlyoutView extends FrameLayout {
.withEndAction(afterFade);
}
- private void updateFlyoutMessage(Bubble.FlyoutMessage flyoutMessage, float parentWidth) {
+ private void updateFlyoutMessage(Bubble.FlyoutMessage flyoutMessage) {
final Drawable senderAvatar = flyoutMessage.senderAvatar;
if (senderAvatar != null && flyoutMessage.isGroupChat) {
mSenderAvatar.setVisibility(VISIBLE);
@@ -278,8 +278,7 @@ public class BubbleFlyoutView extends FrameLayout {
mSenderText.setTranslationX(0);
}
- final int maxTextViewWidth =
- (int) (parentWidth * FLYOUT_MAX_WIDTH_PERCENT) - mFlyoutPadding * 2;
+ final int maxTextViewWidth = (int) mPositioner.getMaxFlyoutSize() - mFlyoutPadding * 2;
// Name visibility
if (!TextUtils.isEmpty(flyoutMessage.senderName)) {
@@ -328,22 +327,20 @@ public class BubbleFlyoutView extends FrameLayout {
void setupFlyoutStartingAsDot(
Bubble.FlyoutMessage flyoutMessage,
PointF stackPos,
- float parentWidth,
boolean arrowPointingLeft,
int dotColor,
@Nullable Runnable onLayoutComplete,
@Nullable Runnable onHide,
float[] dotCenter,
- boolean hideDot,
- BubblePositioner positioner) {
+ boolean hideDot) {
- mBubbleSize = positioner.getBubbleSize();
+ mBubbleSize = mPositioner.getBubbleSize();
mOriginalDotSize = SIZE_PERCENTAGE * mBubbleSize;
mNewDotRadius = (DOT_SCALE * mOriginalDotSize) / 2f;
mNewDotSize = mNewDotRadius * 2f;
- updateFlyoutMessage(flyoutMessage, parentWidth);
+ updateFlyoutMessage(flyoutMessage);
mArrowPointingLeft = arrowPointingLeft;
mDotColor = dotColor;
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 0a856a8231a0..df804ec174d3 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
@@ -61,10 +61,16 @@ public class BubblePositioner {
public static final int NUM_VISIBLE_WHEN_RESTING = 2;
/** Indicates a bubble's height should be the maximum available space. **/
public static final int MAX_HEIGHT = -1;
+ /** The max percent of screen width to use for the flyout on large screens. */
+ public static final float FLYOUT_MAX_WIDTH_PERCENT_LARGE_SCREEN = 0.3f;
+ /** The max percent of screen width to use for the flyout on phone. */
+ public static final float FLYOUT_MAX_WIDTH_PERCENT = 0.6f;
+
private Context mContext;
private WindowManager mWindowManager;
private Rect mPositionRect;
+ private Rect mScreenRect;
private @Surface.Rotation int mRotation = Surface.ROTATION_0;
private Insets mInsets;
private int mDefaultMaxBubbles;
@@ -77,10 +83,10 @@ public class BubblePositioner {
private int mPointerMargin;
private int mPointerWidth;
private int mPointerHeight;
- private int mPointerOverlap;
private int mManageButtonHeight;
private int mExpandedViewMinHeight;
private int mOverflowHeight;
+ private int mMinimumFlyoutWidthLargeScreen;
private PointF mPinLocation;
private PointF mRestingStackPosition;
@@ -149,6 +155,7 @@ public class BubblePositioner {
mRotation = rotation;
mInsets = insets;
+ mScreenRect = new Rect(bounds);
mPositionRect = new Rect(bounds);
mPositionRect.left += mInsets.left;
mPositionRect.top += mInsets.top;
@@ -166,10 +173,11 @@ public class BubblePositioner {
mPointerWidth = res.getDimensionPixelSize(R.dimen.bubble_pointer_width);
mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin);
- mPointerOverlap = res.getDimensionPixelSize(R.dimen.bubble_pointer_overlap);
- mManageButtonHeight = res.getDimensionPixelSize(R.dimen.bubble_manage_button_height);
+ mManageButtonHeight = res.getDimensionPixelSize(R.dimen.bubble_manage_button_total_height);
mExpandedViewMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height);
mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height);
+ mMinimumFlyoutWidthLargeScreen = res.getDimensionPixelSize(
+ R.dimen.bubbles_flyout_min_width_large_screen);
mMaxBubbles = calculateMaxBubbles();
@@ -426,6 +434,17 @@ public class BubblePositioner {
}
/**
+ * @return the width of the bubble flyout (message originating from the bubble).
+ */
+ public float getMaxFlyoutSize() {
+ if (isLargeScreen()) {
+ return Math.max(mScreenRect.width() * FLYOUT_MAX_WIDTH_PERCENT_LARGE_SCREEN,
+ mMinimumFlyoutWidthLargeScreen);
+ }
+ return mScreenRect.width() * FLYOUT_MAX_WIDTH_PERCENT;
+ }
+
+ /**
* Sets the stack's most recent position along the edge of the screen. This is saved when the
* last bubble is removed, so that the stack can be restored in its previous position.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index c35a74c9af25..8f2df4ab3972 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -108,9 +108,6 @@ public class BubbleStackView extends FrameLayout
*/
private static final float FLYOUT_OVERSCROLL_ATTENUATION_FACTOR = 8f;
- /** Duration of the flyout alpha animations. */
- private static final int FLYOUT_ALPHA_ANIMATION_DURATION = 100;
-
private static final int FADE_IN_DURATION = 320;
/** Percent to darken the bubbles when they're in the dismiss target. */
@@ -124,6 +121,8 @@ public class BubbleStackView extends FrameLayout
private static final int EXPANDED_VIEW_ALPHA_ANIMATION_DURATION = 150;
+ private static final int MANAGE_MENU_SCRIM_ANIM_DURATION = 150;
+
private static final float SCRIM_ALPHA = 0.6f;
/**
@@ -200,6 +199,7 @@ public class BubbleStackView extends FrameLayout
private ExpandedAnimationController mExpandedAnimationController;
private View mScrim;
+ private View mManageMenuScrim;
private FrameLayout mExpandedViewContainer;
/** Matrix used to scale the expanded view container with a given pivot point. */
@@ -869,6 +869,14 @@ public class BubbleStackView extends FrameLayout
addView(mScrim);
mScrim.setAlpha(0f);
+ mManageMenuScrim = new View(getContext());
+ mManageMenuScrim.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+ mManageMenuScrim.setBackgroundDrawable(new ColorDrawable(
+ getResources().getColor(android.R.color.system_neutral1_1000)));
+ addView(mManageMenuScrim, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ mManageMenuScrim.setAlpha(0f);
+ mManageMenuScrim.setVisibility(INVISIBLE);
+
mOrientationChangedListener =
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
mPositioner.update();
@@ -1178,7 +1186,7 @@ public class BubbleStackView extends FrameLayout
if (mFlyout != null) {
removeView(mFlyout);
}
- mFlyout = new BubbleFlyoutView(getContext());
+ mFlyout = new BubbleFlyoutView(getContext(), mPositioner);
mFlyout.setVisibility(GONE);
mFlyout.setOnClickListener(mFlyoutClickListener);
mFlyout.setOnTouchListener(mFlyoutTouchListener);
@@ -1227,6 +1235,8 @@ public class BubbleStackView extends FrameLayout
updateExpandedViewTheme();
mScrim.setBackgroundDrawable(new ColorDrawable(
getResources().getColor(android.R.color.system_neutral1_1000)));
+ mManageMenuScrim.setBackgroundDrawable(new ColorDrawable(
+ getResources().getColor(android.R.color.system_neutral1_1000)));
}
/**
@@ -2413,20 +2423,19 @@ public class BubbleStackView extends FrameLayout
if (mFlyout.getVisibility() == View.VISIBLE) {
- mFlyout.animateUpdate(bubble.getFlyoutMessage(), getWidth(),
+ mFlyout.animateUpdate(bubble.getFlyoutMessage(),
mStackAnimationController.getStackPosition(), !bubble.showDot(),
mAfterFlyoutHidden /* onHide */);
} else {
mFlyout.setVisibility(INVISIBLE);
mFlyout.setupFlyoutStartingAsDot(bubble.getFlyoutMessage(),
- mStackAnimationController.getStackPosition(), getWidth(),
+ mStackAnimationController.getStackPosition(),
mStackAnimationController.isStackOnLeftSide(),
bubble.getIconView().getDotColor() /* dotColor */,
expandFlyoutAfterDelay /* onLayoutComplete */,
mAfterFlyoutHidden /* onHide */,
bubble.getIconView().getDotCenter(),
- !bubble.showDot(),
- mPositioner);
+ !bubble.showDot());
}
mFlyout.bringToFront();
});
@@ -2511,6 +2520,24 @@ public class BubbleStackView extends FrameLayout
return;
}
+ if (show) {
+ mManageMenuScrim.setVisibility(VISIBLE);
+ mManageMenuScrim.setTranslationZ(mManageMenu.getElevation() - 1f);
+ }
+ Runnable endAction = () -> {
+ if (!show) {
+ mManageMenuScrim.setVisibility(INVISIBLE);
+ mManageMenuScrim.setTranslationZ(0f);
+ }
+ };
+
+ mManageMenuScrim.animate()
+ .setDuration(MANAGE_MENU_SCRIM_ANIM_DURATION)
+ .setInterpolator(show ? ALPHA_IN : ALPHA_OUT)
+ .alpha(show ? SCRIM_ALPHA : 0f)
+ .withEndAction(endAction)
+ .start();
+
// If available, update the manage menu's settings option with the expanded bubble's app
// name and icon.
if (show && mBubbleData.hasBubbleInStackWithKey(mExpandedBubble.getKey())) {
@@ -2520,7 +2547,6 @@ public class BubbleStackView extends FrameLayout
R.string.bubbles_app_settings, bubble.getAppName()));
}
- mExpandedBubble.getExpandedView().getManageButtonBoundsOnScreen(mTempRect);
if (mExpandedBubble.getExpandedView().getTaskView() != null) {
mExpandedBubble.getExpandedView().getTaskView().setObscuredTouchRect(mShowingManage
? new Rect(0, 0, getWidth(), getHeight())
@@ -2532,7 +2558,11 @@ public class BubbleStackView extends FrameLayout
// When the menu is open, it should be at these coordinates. The menu pops out to the right
// in LTR and to the left in RTL.
- final float targetX = isLtr ? mTempRect.left : mTempRect.right - mManageMenu.getWidth();
+ mExpandedBubble.getExpandedView().getManageButtonBoundsOnScreen(mTempRect);
+ final float margin = mExpandedBubble.getExpandedView().getManageButtonMargin();
+ final float targetX = isLtr
+ ? mTempRect.left - margin
+ : mTempRect.right + margin - mManageMenu.getWidth();
final float targetY = mTempRect.bottom - mManageMenu.getHeight();
final float xOffsetForAnimation = (isLtr ? 1 : -1) * mManageMenu.getWidth() / 4f;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
index b7235a31af03..b90283feb184 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
@@ -82,6 +82,9 @@ public class DisplayLayout {
private boolean mHasNavigationBar = false;
private boolean mHasStatusBar = false;
private int mNavBarFrameHeight = 0;
+ private boolean mAllowSeamlessRotationDespiteNavBarMoving = false;
+ private boolean mNavigationBarCanMove = false;
+ private boolean mReverseDefaultRotation = false;
@Override
public boolean equals(Object o) {
@@ -98,6 +101,10 @@ public class DisplayLayout {
&& Objects.equals(mStableInsets, other.mStableInsets)
&& mHasNavigationBar == other.mHasNavigationBar
&& mHasStatusBar == other.mHasStatusBar
+ && mAllowSeamlessRotationDespiteNavBarMoving
+ == other.mAllowSeamlessRotationDespiteNavBarMoving
+ && mNavigationBarCanMove == other.mNavigationBarCanMove
+ && mReverseDefaultRotation == other.mReverseDefaultRotation
&& mNavBarFrameHeight == other.mNavBarFrameHeight;
}
@@ -105,7 +112,8 @@ public class DisplayLayout {
public int hashCode() {
return Objects.hash(mUiMode, mWidth, mHeight, mCutout, mRotation, mDensityDpi,
mNonDecorInsets, mStableInsets, mHasNavigationBar, mHasStatusBar,
- mNavBarFrameHeight);
+ mNavBarFrameHeight, mAllowSeamlessRotationDespiteNavBarMoving,
+ mNavigationBarCanMove, mReverseDefaultRotation);
}
/**
@@ -150,6 +158,9 @@ public class DisplayLayout {
mDensityDpi = dl.mDensityDpi;
mHasNavigationBar = dl.mHasNavigationBar;
mHasStatusBar = dl.mHasStatusBar;
+ mAllowSeamlessRotationDespiteNavBarMoving = dl.mAllowSeamlessRotationDespiteNavBarMoving;
+ mNavigationBarCanMove = dl.mNavigationBarCanMove;
+ mReverseDefaultRotation = dl.mReverseDefaultRotation;
mNavBarFrameHeight = dl.mNavBarFrameHeight;
mNonDecorInsets.set(dl.mNonDecorInsets);
mStableInsets.set(dl.mStableInsets);
@@ -165,6 +176,10 @@ public class DisplayLayout {
mDensityDpi = info.logicalDensityDpi;
mHasNavigationBar = hasNavigationBar;
mHasStatusBar = hasStatusBar;
+ mAllowSeamlessRotationDespiteNavBarMoving = res.getBoolean(
+ R.bool.config_allowSeamlessRotationDespiteNavBarMoving);
+ mNavigationBarCanMove = res.getBoolean(R.bool.config_navBarCanMove);
+ mReverseDefaultRotation = res.getBoolean(R.bool.config_reverseDefaultRotation);
recalcInsets(res);
}
@@ -249,6 +264,28 @@ public class DisplayLayout {
return mNavBarFrameHeight;
}
+ /** @return whether we can seamlessly rotate even if nav-bar can change sides. */
+ public boolean allowSeamlessRotationDespiteNavBarMoving() {
+ return mAllowSeamlessRotationDespiteNavBarMoving;
+ }
+
+ /** @return whether the navigation bar will change sides during rotation. */
+ public boolean navigationBarCanMove() {
+ return mNavigationBarCanMove;
+ }
+
+ /** @return the rotation that would make the physical display "upside down". */
+ public int getUpsideDownRotation() {
+ boolean displayHardwareIsLandscape = mWidth > mHeight;
+ if ((mRotation % 2) != 0) {
+ displayHardwareIsLandscape = !displayHardwareIsLandscape;
+ }
+ if (displayHardwareIsLandscape) {
+ return mReverseDefaultRotation ? Surface.ROTATION_270 : Surface.ROTATION_90;
+ }
+ return Surface.ROTATION_180;
+ }
+
/** Gets the orientation of this layout */
public int getOrientation() {
return (mWidth > mHeight) ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 8adfac01b462..bb40f679b272 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -16,11 +16,18 @@
package com.android.wm.shell.common.split;
+import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
+import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
+import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
import static android.view.WindowManager.DOCKED_TOP;
import static com.android.internal.policy.DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_END;
import static com.android.internal.policy.DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START;
+import static com.android.wm.shell.animation.Interpolators.DIM_INTERPOLATOR;
+import static com.android.wm.shell.animation.Interpolators.SLOWDOWN_INTERPOLATOR;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -30,6 +37,7 @@ import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.Point;
import android.graphics.Rect;
import android.view.SurfaceControl;
import android.view.WindowInsets;
@@ -39,6 +47,7 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.Nullable;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.animation.Interpolators;
@@ -78,6 +87,7 @@ public final class SplitLayout {
private final int mDividerInsets;
private final int mDividerSize;
+ private final Rect mTempRect = new Rect();
private final Rect mRootBounds = new Rect();
private final Rect mDividerBounds = new Rect();
private final Rect mBounds1 = new Rect();
@@ -86,6 +96,7 @@ public final class SplitLayout {
private final SplitWindowManager mSplitWindowManager;
private final DisplayImeController mDisplayImeController;
private final ImePositionProcessor mImePositionProcessor;
+ private final DismissingParallaxPolicy mDismissingParallaxPolicy;
private final ShellTaskOrganizer mTaskOrganizer;
private Context mContext;
@@ -108,6 +119,7 @@ public final class SplitLayout {
windowName, mContext, configuration, parentContainerCallbacks);
mTaskOrganizer = taskOrganizer;
mImePositionProcessor = new ImePositionProcessor(mContext.getDisplayId());
+ mDismissingParallaxPolicy = new DismissingParallaxPolicy();
final Resources resources = context.getResources();
mDividerWindowWidth = resources.getDimensionPixelSize(
@@ -185,7 +197,8 @@ public final class SplitLayout {
mDividerBounds.set(mRootBounds);
mBounds1.set(mRootBounds);
mBounds2.set(mRootBounds);
- if (isLandscape(mRootBounds)) {
+ final boolean isLandscape = isLandscape(mRootBounds);
+ if (isLandscape) {
position += mRootBounds.left;
mDividerBounds.left = position - mDividerInsets;
mDividerBounds.right = mDividerBounds.left + mDividerWindowWidth;
@@ -198,6 +211,7 @@ public final class SplitLayout {
mBounds1.bottom = position;
mBounds2.top = mBounds1.bottom + mDividerSize;
}
+ mDismissingParallaxPolicy.applyDividerPosition(position, isLandscape);
}
/** Inflates {@link DividerView} on the root surface. */
@@ -224,19 +238,20 @@ public final class SplitLayout {
void updateDivideBounds(int position) {
updateBounds(position);
mSplitWindowManager.setResizingSplits(true);
- mSplitLayoutHandler.onBoundsChanging(this);
+ mSplitLayoutHandler.onLayoutChanging(this);
}
void setDividePosition(int position) {
mDividePosition = position;
updateBounds(mDividePosition);
- mSplitLayoutHandler.onBoundsChanged(this);
+ mSplitLayoutHandler.onLayoutChanged(this);
mSplitWindowManager.setResizingSplits(false);
}
/** Resets divider position. */
public void resetDividerPosition() {
mDividePosition = mDividerSnapAlgorithm.getMiddleTarget().position;
+ mSplitWindowManager.setResizingSplits(false);
updateBounds(mDividePosition);
}
@@ -247,15 +262,15 @@ public final class SplitLayout {
public void snapToTarget(int currentPosition, DividerSnapAlgorithm.SnapTarget snapTarget) {
switch (snapTarget.flag) {
case FLAG_DISMISS_START:
- mSplitLayoutHandler.onSnappedToDismiss(false /* bottomOrRight */);
- mSplitWindowManager.setResizingSplits(false);
+ flingDividePosition(currentPosition, snapTarget.position,
+ () -> mSplitLayoutHandler.onSnappedToDismiss(false /* bottomOrRight */));
break;
case FLAG_DISMISS_END:
- mSplitLayoutHandler.onSnappedToDismiss(true /* bottomOrRight */);
- mSplitWindowManager.setResizingSplits(false);
+ flingDividePosition(currentPosition, snapTarget.position,
+ () -> mSplitLayoutHandler.onSnappedToDismiss(true /* bottomOrRight */));
break;
default:
- flingDividePosition(currentPosition, snapTarget.position);
+ flingDividePosition(currentPosition, snapTarget.position, null);
break;
}
}
@@ -285,7 +300,8 @@ public final class SplitLayout {
isLandscape ? DOCKED_LEFT : DOCKED_TOP /* dockSide */);
}
- private void flingDividePosition(int from, int to) {
+ @VisibleForTesting
+ void flingDividePosition(int from, int to, @Nullable Runnable flingFinishedCallback) {
if (from == to) {
// No animation run, it should stop resizing here.
mSplitWindowManager.setResizingSplits(false);
@@ -301,6 +317,9 @@ public final class SplitLayout {
@Override
public void onAnimationEnd(Animator animation) {
setDividePosition(to);
+ if (flingFinishedCallback != null) {
+ flingFinishedCallback.run();
+ }
}
@Override
@@ -326,30 +345,73 @@ public final class SplitLayout {
/** Apply recorded surface layout to the {@link SurfaceControl.Transaction}. */
public void applySurfaceChanges(SurfaceControl.Transaction t, SurfaceControl leash1,
SurfaceControl leash2, SurfaceControl dimLayer1, SurfaceControl dimLayer2) {
- final Rect dividerBounds = mImePositionProcessor.adjustForIme(mDividerBounds);
- final Rect bounds1 = mImePositionProcessor.adjustForIme(mBounds1);
- final Rect bounds2 = mImePositionProcessor.adjustForIme(mBounds2);
final SurfaceControl dividerLeash = getDividerLeash();
if (dividerLeash != null) {
- t.setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
- // Resets layer of divider bar to make sure it is always on top.
- .setLayer(dividerLeash, Integer.MAX_VALUE);
+ t.setPosition(dividerLeash, mDividerBounds.left, mDividerBounds.top);
+ // Resets layer of divider bar to make sure it is always on top.
+ t.setLayer(dividerLeash, Integer.MAX_VALUE);
}
+ t.setPosition(leash1, mBounds1.left, mBounds1.top)
+ .setWindowCrop(leash1, mBounds1.width(), mBounds1.height());
+ t.setPosition(leash2, mBounds2.left, mBounds2.top)
+ .setWindowCrop(leash2, mBounds2.width(), mBounds2.height());
- t.setPosition(leash1, bounds1.left, bounds1.top)
- .setWindowCrop(leash1, bounds1.width(), bounds1.height());
-
- t.setPosition(leash2, bounds2.left, bounds2.top)
- .setWindowCrop(leash2, bounds2.width(), bounds2.height());
+ if (mImePositionProcessor.adjustSurfaceLayoutForIme(
+ t, dividerLeash, leash1, leash2, dimLayer1, dimLayer2)) {
+ return;
+ }
- mImePositionProcessor.applySurfaceDimValues(t, dimLayer1, dimLayer2);
+ mDismissingParallaxPolicy.adjustDismissingSurface(t, leash1, leash2, dimLayer1, dimLayer2);
}
/** Apply recorded task layout to the {@link WindowContainerTransaction}. */
public void applyTaskChanges(WindowContainerTransaction wct,
ActivityManager.RunningTaskInfo task1, ActivityManager.RunningTaskInfo task2) {
- wct.setBounds(task1.token, mImePositionProcessor.adjustForIme(mBounds1))
- .setBounds(task2.token, mImePositionProcessor.adjustForIme(mBounds2));
+ if (mImePositionProcessor.applyTaskLayoutForIme(wct, task1.token, task2.token)) {
+ return;
+ }
+
+ wct.setBounds(task1.token, mBounds1)
+ .setBounds(task2.token, mBounds2);
+ }
+
+ /**
+ * Shift configuration bounds to prevent client apps get configuration changed or relaunch. And
+ * restore shifted configuration bounds if it's no longer shifted.
+ */
+ public void applyLayoutShifted(WindowContainerTransaction wct, int offsetX, int offsetY,
+ ActivityManager.RunningTaskInfo taskInfo1, ActivityManager.RunningTaskInfo taskInfo2) {
+ if (offsetX == 0 && offsetY == 0) {
+ wct.setBounds(taskInfo1.token, mBounds1);
+ wct.setAppBounds(taskInfo1.token, null);
+ wct.setScreenSizeDp(taskInfo1.token,
+ SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
+
+ wct.setBounds(taskInfo2.token, mBounds2);
+ wct.setAppBounds(taskInfo2.token, null);
+ wct.setScreenSizeDp(taskInfo2.token,
+ SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
+ } else {
+ mTempRect.set(taskInfo1.configuration.windowConfiguration.getBounds());
+ mTempRect.offset(offsetX, offsetY);
+ wct.setBounds(taskInfo1.token, mTempRect);
+ mTempRect.set(taskInfo1.configuration.windowConfiguration.getAppBounds());
+ mTempRect.offset(offsetX, offsetY);
+ wct.setAppBounds(taskInfo1.token, mTempRect);
+ wct.setScreenSizeDp(taskInfo1.token,
+ taskInfo1.configuration.screenWidthDp,
+ taskInfo1.configuration.screenHeightDp);
+
+ mTempRect.set(taskInfo2.configuration.windowConfiguration.getBounds());
+ mTempRect.offset(offsetX, offsetY);
+ wct.setBounds(taskInfo2.token, mTempRect);
+ mTempRect.set(taskInfo2.configuration.windowConfiguration.getAppBounds());
+ mTempRect.offset(offsetX, offsetY);
+ wct.setAppBounds(taskInfo2.token, mTempRect);
+ wct.setScreenSizeDp(taskInfo2.token,
+ taskInfo2.configuration.screenWidthDp,
+ taskInfo2.configuration.screenHeightDp);
+ }
}
/** Handles layout change event. */
@@ -359,10 +421,18 @@ public final class SplitLayout {
void onSnappedToDismiss(boolean snappedToEnd);
/** Calls when the bounds is changing due to animation or dragging divider bar. */
- void onBoundsChanging(SplitLayout layout);
+ void onLayoutChanging(SplitLayout layout);
/** Calls when the target bounds changed. */
- void onBoundsChanged(SplitLayout layout);
+ void onLayoutChanged(SplitLayout layout);
+
+ /**
+ * Notifies when the layout shifted. So the layout handler can shift configuration
+ * bounds correspondingly to make sure client apps won't get configuration changed or
+ * relaunch. If the layout is no longer shifted, layout handler should restore shifted
+ * configuration bounds.
+ */
+ void onLayoutShifted(int offsetX, int offsetY, SplitLayout layout);
/** Calls when user double tapped on the divider bar. */
default void onDoubleTappedDivider() {
@@ -373,6 +443,106 @@ public final class SplitLayout {
int getSplitItemPosition(WindowContainerToken token);
}
+ /**
+ * Calculates and applies proper dismissing parallax offset and dimming value to hint users
+ * dismissing gesture.
+ */
+ private class DismissingParallaxPolicy {
+ // The current dismissing side.
+ int mDismissingSide = DOCKED_INVALID;
+
+ // The parallax offset to hint the dismissing side and progress.
+ final Point mDismissingParallaxOffset = new Point();
+
+ // The dimming value to hint the dismissing side and progress.
+ float mDismissingDimValue = 0.0f;
+
+ /**
+ * Applies a parallax to the task to hint dismissing progress.
+ *
+ * @param position the split position to apply dismissing parallax effect
+ * @param isLandscape indicates whether it's splitting horizontally or vertically
+ */
+ void applyDividerPosition(int position, boolean isLandscape) {
+ mDismissingSide = DOCKED_INVALID;
+ mDismissingParallaxOffset.set(0, 0);
+ mDismissingDimValue = 0;
+
+ int totalDismissingDistance = 0;
+ if (position <= mDividerSnapAlgorithm.getFirstSplitTarget().position) {
+ mDismissingSide = isLandscape ? DOCKED_LEFT : DOCKED_TOP;
+ totalDismissingDistance = mDividerSnapAlgorithm.getDismissStartTarget().position
+ - mDividerSnapAlgorithm.getFirstSplitTarget().position;
+ } else if (position >= mDividerSnapAlgorithm.getLastSplitTarget().position) {
+ mDismissingSide = isLandscape ? DOCKED_RIGHT : DOCKED_BOTTOM;
+ totalDismissingDistance = mDividerSnapAlgorithm.getLastSplitTarget().position
+ - mDividerSnapAlgorithm.getDismissEndTarget().position;
+ }
+
+ if (mDismissingSide != DOCKED_INVALID) {
+ float fraction = Math.max(0,
+ Math.min(mDividerSnapAlgorithm.calculateDismissingFraction(position), 1f));
+ mDismissingDimValue = DIM_INTERPOLATOR.getInterpolation(fraction);
+ fraction = calculateParallaxDismissingFraction(fraction, mDismissingSide);
+ if (isLandscape) {
+ mDismissingParallaxOffset.x = (int) (fraction * totalDismissingDistance);
+ } else {
+ mDismissingParallaxOffset.y = (int) (fraction * totalDismissingDistance);
+ }
+ }
+ }
+
+ /**
+ * @return for a specified {@code fraction}, this returns an adjusted value that simulates a
+ * slowing down parallax effect
+ */
+ private float calculateParallaxDismissingFraction(float fraction, int dockSide) {
+ float result = SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;
+
+ // Less parallax at the top, just because.
+ if (dockSide == WindowManager.DOCKED_TOP) {
+ result /= 2f;
+ }
+ return result;
+ }
+
+ /** Applies parallax offset and dimming value to the root surface at the dismissing side. */
+ boolean adjustDismissingSurface(SurfaceControl.Transaction t,
+ SurfaceControl leash1, SurfaceControl leash2,
+ SurfaceControl dimLayer1, SurfaceControl dimLayer2) {
+ SurfaceControl targetLeash, targetDimLayer;
+ switch (mDismissingSide) {
+ case DOCKED_TOP:
+ case DOCKED_LEFT:
+ targetLeash = leash1;
+ targetDimLayer = dimLayer1;
+ mTempRect.set(mBounds1);
+ break;
+ case DOCKED_BOTTOM:
+ case DOCKED_RIGHT:
+ targetLeash = leash2;
+ targetDimLayer = dimLayer2;
+ mTempRect.set(mBounds2);
+ break;
+ case DOCKED_INVALID:
+ default:
+ t.setAlpha(dimLayer1, 0).hide(dimLayer1);
+ t.setAlpha(dimLayer2, 0).hide(dimLayer2);
+ return false;
+ }
+
+ t.setPosition(targetLeash,
+ mTempRect.left + mDismissingParallaxOffset.x,
+ mTempRect.top + mDismissingParallaxOffset.y);
+ // Transform the screen-based split bounds to surface-based crop bounds.
+ mTempRect.offsetTo(-mDismissingParallaxOffset.x, -mDismissingParallaxOffset.y);
+ t.setWindowCrop(targetLeash, mTempRect);
+ t.setAlpha(targetDimLayer, mDismissingDimValue)
+ .setVisibility(targetDimLayer, mDismissingDimValue > 0.001f);
+ return true;
+ }
+ }
+
/** Records IME top offset changes and updates SplitLayout correspondingly. */
private class ImePositionProcessor implements DisplayImeController.ImePositionProcessor {
/**
@@ -427,6 +597,18 @@ public final class SplitLayout {
&& !isFloating && !isLandscape(mRootBounds) && showing;
mTargetYOffset = needOffset ? getTargetYOffset() : 0;
+ if (mTargetYOffset != mLastYOffset) {
+ // Freeze the configuration size with offset to prevent app get a configuration
+ // changed or relaunch. This is required to make sure client apps will calculate
+ // insets properly after layout shifted.
+ if (mTargetYOffset == 0) {
+ mSplitLayoutHandler.onLayoutShifted(0, 0, SplitLayout.this);
+ } else {
+ mSplitLayoutHandler.onLayoutShifted(0, mTargetYOffset - mLastYOffset,
+ SplitLayout.this);
+ }
+ }
+
// Make {@link DividerView} non-interactive while IME showing in split mode. Listen to
// ImePositionProcessor#onImeVisibilityChanged directly in DividerView is not enough
// because DividerView won't receive onImeVisibilityChanged callback after it being
@@ -441,7 +623,7 @@ public final class SplitLayout {
public void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t) {
if (displayId != mDisplayId) return;
onProgress(getProgress(imeTop));
- mSplitLayoutHandler.onBoundsChanging(SplitLayout.this);
+ mSplitLayoutHandler.onLayoutChanging(SplitLayout.this);
}
@Override
@@ -449,7 +631,7 @@ public final class SplitLayout {
SurfaceControl.Transaction t) {
if (displayId != mDisplayId || cancel) return;
onProgress(1.0f);
- mSplitLayoutHandler.onBoundsChanging(SplitLayout.this);
+ mSplitLayoutHandler.onLayoutChanging(SplitLayout.this);
}
@Override
@@ -459,7 +641,7 @@ public final class SplitLayout {
if (!controlling && mImeShown) {
reset();
mSplitWindowManager.setInteractive(true);
- mSplitLayoutHandler.onBoundsChanging(SplitLayout.this);
+ mSplitLayoutHandler.onLayoutChanging(SplitLayout.this);
}
}
@@ -491,24 +673,61 @@ public final class SplitLayout {
return start + (end - start) * progress;
}
- private void reset() {
+ void reset() {
mImeShown = false;
mYOffsetForIme = mLastYOffset = mTargetYOffset = 0;
mDimValue1 = mLastDim1 = mTargetDim1 = 0.0f;
mDimValue2 = mLastDim2 = mTargetDim2 = 0.0f;
}
- /* Adjust bounds with IME offset. */
- private Rect adjustForIme(Rect bounds) {
- final Rect temp = new Rect(bounds);
- if (mYOffsetForIme != 0) temp.offset(0, mYOffsetForIme);
- return temp;
+ /**
+ * Applies adjusted task layout for showing IME.
+ *
+ * @return {@code false} if there's no need to adjust, otherwise {@code true}
+ */
+ boolean applyTaskLayoutForIme(WindowContainerTransaction wct,
+ WindowContainerToken token1, WindowContainerToken token2) {
+ if (mYOffsetForIme == 0) return false;
+
+ mTempRect.set(mBounds1);
+ mTempRect.offset(0, mYOffsetForIme);
+ wct.setBounds(token1, mTempRect);
+
+ mTempRect.set(mBounds2);
+ mTempRect.offset(0, mYOffsetForIme);
+ wct.setBounds(token2, mTempRect);
+
+ return true;
}
- private void applySurfaceDimValues(SurfaceControl.Transaction t, SurfaceControl dimLayer1,
- SurfaceControl dimLayer2) {
+ /**
+ * Adjusts surface layout while showing IME.
+ *
+ * @return {@code false} if there's no need to adjust, otherwise {@code true}
+ */
+ boolean adjustSurfaceLayoutForIme(SurfaceControl.Transaction t,
+ SurfaceControl dividerLeash, SurfaceControl leash1, SurfaceControl leash2,
+ SurfaceControl dimLayer1, SurfaceControl dimLayer2) {
+ if (mYOffsetForIme == 0) return false;
+
+ if (dividerLeash != null) {
+ mTempRect.set(mDividerBounds);
+ mTempRect.offset(0, mYOffsetForIme);
+ t.setPosition(dividerLeash, mTempRect.left, mTempRect.top);
+ }
+
+ mTempRect.set(mBounds1);
+ mTempRect.offset(0, mYOffsetForIme);
+ t.setPosition(leash1, mTempRect.left, mTempRect.top);
+
+ mTempRect.set(mBounds2);
+ mTempRect.offset(0, mYOffsetForIme);
+ t.setPosition(leash2, mTempRect.left, mTempRect.top);
+
t.setAlpha(dimLayer1, mDimValue1).setVisibility(dimLayer1, mDimValue1 > 0.001f);
t.setAlpha(dimLayer2, mDimValue2).setVisibility(dimLayer2, mDimValue2 > 0.001f);
+
+ return true;
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
new file mode 100644
index 000000000000..5fb3297aa6d3
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.freeform;
+
+import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
+import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
+
+import android.app.ActivityManager.RunningTaskInfo;
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.provider.Settings;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.SurfaceControl;
+
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
+
+import java.io.PrintWriter;
+
+/**
+ * {@link ShellTaskOrganizer.TaskListener} for {@link
+ * ShellTaskOrganizer#TASK_LISTENER_TYPE_FREEFORM}.
+ */
+public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener {
+ private static final String TAG = "FreeformTaskListener";
+
+ private final SyncTransactionQueue mSyncQueue;
+
+ private final SparseArray<State> mTasks = new SparseArray<>();
+
+ private static class State {
+ RunningTaskInfo mTaskInfo;
+ SurfaceControl mLeash;
+ }
+
+ public FreeformTaskListener(SyncTransactionQueue syncQueue) {
+ mSyncQueue = syncQueue;
+ }
+
+ @Override
+ public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
+ if (mTasks.get(taskInfo.taskId) != null) {
+ throw new RuntimeException("Task appeared more than once: #" + taskInfo.taskId);
+ }
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Appeared: #%d",
+ taskInfo.taskId);
+ final State state = new State();
+ state.mTaskInfo = taskInfo;
+ state.mLeash = leash;
+ mTasks.put(taskInfo.taskId, state);
+
+ final Rect taskBounds = taskInfo.configuration.windowConfiguration.getBounds();
+ mSyncQueue.runInSync(t -> {
+ Point taskPosition = taskInfo.positionInParent;
+ t.setPosition(leash, taskPosition.x, taskPosition.y)
+ .setWindowCrop(leash, taskBounds.width(), taskBounds.height())
+ .show(leash);
+ });
+ }
+
+ @Override
+ public void onTaskVanished(RunningTaskInfo taskInfo) {
+ State state = mTasks.get(taskInfo.taskId);
+ if (state == null) {
+ Slog.e(TAG, "Task already vanished: #" + taskInfo.taskId);
+ return;
+ }
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Vanished: #%d",
+ taskInfo.taskId);
+ mTasks.remove(taskInfo.taskId);
+ }
+
+ @Override
+ public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
+ State state = mTasks.get(taskInfo.taskId);
+ if (state == null) {
+ throw new RuntimeException(
+ "Task info changed before appearing: #" + taskInfo.taskId);
+ }
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Info Changed: #%d",
+ taskInfo.taskId);
+ state.mTaskInfo = taskInfo;
+
+ final Rect taskBounds = taskInfo.configuration.windowConfiguration.getBounds();
+ final SurfaceControl leash = state.mLeash;
+ mSyncQueue.runInSync(t -> {
+ Point taskPosition = taskInfo.positionInParent;
+ t.setPosition(leash, taskPosition.x, taskPosition.y)
+ .setWindowCrop(leash, taskBounds.width(), taskBounds.height())
+ .show(leash);
+ });
+ }
+
+ @Override
+ public void dump(PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ pw.println(prefix + this);
+ pw.println(innerPrefix + mTasks.size() + " tasks");
+ }
+
+ @Override
+ public String toString() {
+ return TAG;
+ }
+
+ /**
+ * Checks if freeform support is enabled in system.
+ *
+ * @param context context used to check settings and package manager.
+ * @return {@code true} if freeform is enabled, {@code false} if not.
+ */
+ public static boolean isFreeformEnabled(Context context) {
+ return context.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)
+ || Settings.Global.getInt(context.getContentResolver(),
+ DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
+ }
+
+ /**
+ * Creates {@link FreeformTaskListener} if freeform is enabled.
+ */
+ public static FreeformTaskListener create(Context context,
+ SyncTransactionQueue syncQueue) {
+ if (!isFreeformEnabled(context)) {
+ return null;
+ }
+
+ return new FreeformTaskListener(syncQueue);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
index 9bed40d67335..067f80800ed5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
@@ -20,6 +20,8 @@ import static android.view.PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW;
import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
import static android.view.WindowManager.DOCKED_RIGHT;
+import static com.android.wm.shell.animation.Interpolators.DIM_INTERPOLATOR;
+import static com.android.wm.shell.animation.Interpolators.SLOWDOWN_INTERPOLATOR;
import static com.android.wm.shell.common.split.DividerView.TOUCH_ANIMATION_DURATION;
import static com.android.wm.shell.common.split.DividerView.TOUCH_RELEASE_ANIMATION_DURATION;
@@ -100,10 +102,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private static final float MINIMIZE_DOCK_SCALE = 0f;
private static final float ADJUSTED_FOR_IME_SCALE = 0.5f;
- private static final PathInterpolator SLOWDOWN_INTERPOLATOR =
- new PathInterpolator(0.5f, 1f, 0.5f, 1f);
- private static final PathInterpolator DIM_INTERPOLATOR =
- new PathInterpolator(.23f, .87f, .52f, -0.11f);
private static final Interpolator IME_ADJUST_INTERPOLATOR =
new PathInterpolator(0.2f, 0f, 0.1f, 1f);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
index 97461e607e66..d0491e95ec01 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedBackgroundPanelOrganizer.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.view.ContextThemeWrapper;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.animation.LinearInterpolator;
@@ -31,7 +32,6 @@ import android.window.DisplayAreaOrganizer;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-import androidx.appcompat.view.ContextThemeWrapper;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
index 21bc889a7d83..ff333c8c659d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
@@ -130,7 +130,7 @@ public final class OneHandedSettingsUtil {
*/
public boolean getSettingsTapsAppToExit(ContentResolver resolver, int userId) {
return Settings.Secure.getIntForUser(resolver,
- Settings.Secure.TAPS_APP_TO_EXIT, 0, userId) == 1;
+ Settings.Secure.TAPS_APP_TO_EXIT, 1, userId) == 1;
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
index f58c6b173af9..81dd60d715e9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
@@ -32,6 +32,7 @@ import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.SurfaceControl;
@@ -44,7 +45,6 @@ import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
-import androidx.appcompat.view.ContextThemeWrapper;
import com.android.internal.annotations.VisibleForTesting;
import com.android.wm.shell.R;
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 d77619a396d7..1d238a116059 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
@@ -137,11 +137,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
public void onPipAnimationStart(TaskInfo taskInfo,
PipAnimationController.PipTransitionAnimator animator) {
final int direction = animator.getTransitionDirection();
- if (direction == TRANSITION_DIRECTION_TO_PIP) {
- // TODO (b//169221267): Add jank listener for transactions without buffer updates.
- //InteractionJankMonitor.getInstance().begin(
- // InteractionJankMonitor.CUJ_LAUNCHER_APP_CLOSE_TO_PIP, 2000);
- }
sendOnPipTransitionStarted(direction);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index ae17a93ef1dc..ea587c69c0c0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -19,6 +19,7 @@ package com.android.wm.shell.pip;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.util.RotationUtils.deltaRotation;
+import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_PIP;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
@@ -126,6 +127,12 @@ public class PipTransition extends PipTransitionController {
return true;
}
+ // We only support TRANSIT_PIP type (from RootWindowContainer) or TRANSIT_OPEN (from apps
+ // that enter PiP instantly on opening, mostly from CTS/Flicker tests)
+ if (info.getType() != TRANSIT_PIP && info.getType() != TRANSIT_OPEN) {
+ return false;
+ }
+
// Search for an Enter PiP transition (along with a show wallpaper one)
TransitionInfo.Change enterPip = null;
TransitionInfo.Change wallpaper = null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index dedc56678ef1..dbf603ca72d9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -19,7 +19,6 @@ package com.android.wm.shell.pip;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK;
-import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
import android.app.PictureInPictureParams;
import android.app.TaskInfo;
@@ -57,12 +56,6 @@ public abstract class PipTransitionController implements Transitions.TransitionH
public void onPipAnimationStart(TaskInfo taskInfo,
PipAnimationController.PipTransitionAnimator animator) {
final int direction = animator.getTransitionDirection();
- if (direction == TRANSITION_DIRECTION_TO_PIP) {
- // TODO (b//169221267): Add jank listener for transactions without buffer
- // updates.
- //InteractionJankMonitor.getInstance().begin(
- // InteractionJankMonitor.CUJ_LAUNCHER_APP_CLOSE_TO_PIP, 2000);
- }
sendOnPipTransitionStarted(direction);
}
@@ -76,12 +69,6 @@ public abstract class PipTransitionController implements Transitions.TransitionH
}
onFinishResize(taskInfo, animator.getDestinationBounds(), direction, tx);
sendOnPipTransitionFinished(direction);
- if (direction == TRANSITION_DIRECTION_TO_PIP) {
- // TODO (b//169221267): Add jank listener for transactions without buffer
- // updates.
- //InteractionJankMonitor.getInstance().end(
- // InteractionJankMonitor.CUJ_LAUNCHER_APP_CLOSE_TO_PIP);
- }
}
@Override
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 62b50c55e77c..92c0099c6557 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
@@ -21,7 +21,15 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static android.view.WindowManager.INPUT_CONSUMER_PIP;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_PIP_TRANSITION;
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_SNAP_AFTER_RESIZE;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_USER_RESIZE;
import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
import android.app.ActivityManager;
@@ -52,6 +60,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.jank.InteractionJankMonitor;
import com.android.wm.shell.R;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayChangeController;
@@ -567,8 +576,37 @@ public class PipController implements PipTransitionController.PipTransitionCallb
mPipTaskOrganizer.stopSwipePipToHome(componentName, destinationBounds, overlay);
}
+ private String getTransitionTag(int direction) {
+ switch (direction) {
+ case TRANSITION_DIRECTION_TO_PIP:
+ return "TRANSITION_TO_PIP";
+ case TRANSITION_DIRECTION_LEAVE_PIP:
+ return "TRANSITION_LEAVE_PIP";
+ case TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN:
+ return "TRANSITION_LEAVE_PIP_TO_SPLIT_SCREEN";
+ case TRANSITION_DIRECTION_REMOVE_STACK:
+ return "TRANSITION_REMOVE_STACK";
+ case TRANSITION_DIRECTION_SNAP_AFTER_RESIZE:
+ return "TRANSITION_SNAP_AFTER_RESIZE";
+ case TRANSITION_DIRECTION_USER_RESIZE:
+ return "TRANSITION_USER_RESIZE";
+ case TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND:
+ return "TRANSITION_EXPAND_OR_UNEXPAND";
+ default:
+ return "TRANSITION_LEAVE_UNKNOWN";
+ }
+ }
+
@Override
public void onPipTransitionStarted(int direction, Rect pipBounds) {
+ // Begin InteractionJankMonitor with PIP transition CUJs
+ final InteractionJankMonitor.Configuration.Builder builder =
+ InteractionJankMonitor.Configuration.Builder.withSurface(
+ CUJ_PIP_TRANSITION, mContext, mPipTaskOrganizer.getSurfaceControl())
+ .setTag(getTransitionTag(direction))
+ .setTimeout(2000);
+ InteractionJankMonitor.getInstance().begin(builder);
+
if (isOutPipDirection(direction)) {
// Exiting PIP, save the reentry state to restore to when re-entering.
saveReentryState(pipBounds);
@@ -607,6 +645,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb
}
private void onPipTransitionFinishedOrCanceled(int direction) {
+ // End InteractionJankMonitor with PIP transition by CUJs
+ InteractionJankMonitor.getInstance().end(CUJ_PIP_TRANSITION);
+
// Re-enable touches after the animation completes
mTouchHandler.setTouchEnabled(true);
mTouchHandler.onPinnedStackAnimationEnded(direction);
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 962b5d5ce9be..29e99175bed0 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
@@ -425,7 +425,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (mSideStageListener.mVisible && updateBounds) {
if (wct == null) {
// onBoundsChanged builds/applies a wct with the contents of updateWindowBounds.
- onBoundsChanged(mSplitLayout);
+ onLayoutChanged(mSplitLayout);
} else {
updateWindowBounds(mSplitLayout, wct);
}
@@ -743,12 +743,12 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
@Override
- public void onBoundsChanging(SplitLayout layout) {
+ public void onLayoutChanging(SplitLayout layout) {
mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t));
}
@Override
- public void onBoundsChanged(SplitLayout layout) {
+ public void onLayoutChanged(SplitLayout layout) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
updateWindowBounds(layout, wct);
mSyncQueue.queue(wct);
@@ -792,6 +792,18 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
@Override
+ public void onLayoutShifted(int offsetX, int offsetY, SplitLayout layout) {
+ final StageTaskListener topLeftStage =
+ mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
+ final StageTaskListener bottomRightStage =
+ mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ layout.applyLayoutShifted(wct, offsetX, offsetY, topLeftStage.mRootTaskInfo,
+ bottomRightStage.mRootTaskInfo);
+ mTaskOrganizer.applyTransaction(wct);
+ }
+
+ @Override
public void onDisplayAreaAppeared(DisplayAreaInfo displayAreaInfo) {
mDisplayAreaInfo = displayAreaInfo;
if (mSplitLayout == null) {
@@ -813,7 +825,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (mSplitLayout != null
&& mSplitLayout.updateConfiguration(mDisplayAreaInfo.configuration)
&& mMainStage.isActive()) {
- onBoundsChanged(mSplitLayout);
+ onLayoutChanged(mSplitLayout);
mSyncQueue.runInSync(t -> applyDividerVisibility(t));
}
}
@@ -1113,7 +1125,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
null /* contentInsets */, Integer.MAX_VALUE /* prefixOrderIndex */,
new android.graphics.Point(0, 0) /* position */, bounds, bounds,
new WindowConfiguration(), true, null /* startLeash */, null /* startBounds */,
- null /* taskInfo */, TYPE_DOCK_DIVIDER);
+ null /* taskInfo */, false /* allowEnterPip */, TYPE_DOCK_DIVIDER);
}
@Override
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 01134a7c74f7..b584038bf0e5 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
@@ -23,6 +23,10 @@ import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
import static android.app.ActivityOptions.ANIM_SCALE_UP;
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
@@ -31,8 +35,10 @@ import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_RELAUNCH;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.TransitionInfo.FLAG_IS_VOICE_INTERACTION;
+import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
@@ -68,9 +74,12 @@ import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.AttributeCache;
import com.android.internal.policy.TransitionAnimation;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -97,6 +106,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
SystemProperties.getBoolean(DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY, true);
private final TransactionPool mTransactionPool;
+ private final DisplayController mDisplayController;
private final Context mContext;
private final ShellExecutor mMainExecutor;
private final ShellExecutor mAnimExecutor;
@@ -114,8 +124,10 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
private ScreenRotationAnimation mRotationAnimation;
- DefaultTransitionHandler(@NonNull TransactionPool transactionPool, Context context,
+ DefaultTransitionHandler(@NonNull DisplayController displayController,
+ @NonNull TransactionPool transactionPool, Context context,
@NonNull ShellExecutor mainExecutor, @NonNull ShellExecutor animExecutor) {
+ mDisplayController = displayController;
mTransactionPool = transactionPool;
mContext = context;
mMainExecutor = mainExecutor;
@@ -126,6 +138,110 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
AttributeCache.init(context);
}
+ @VisibleForTesting
+ static boolean isRotationSeamless(@NonNull TransitionInfo info,
+ DisplayController displayController) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+ "Display is rotating, check if it should be seamless.");
+ boolean checkedDisplayLayout = false;
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+
+ // Only look at changing things. showing/hiding don't need to rotate.
+ if (change.getMode() != TRANSIT_CHANGE) continue;
+
+ // This container isn't rotating, so we can ignore it.
+ if (change.getEndRotation() == change.getStartRotation()) continue;
+
+ if ((change.getFlags() & FLAG_IS_DISPLAY) != 0) {
+ // In the presence of System Alert windows we can not seamlessly rotate.
+ if ((change.getFlags() & FLAG_DISPLAY_HAS_ALERT_WINDOWS) != 0) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+ " display has system alert windows, so not seamless.");
+ return false;
+ }
+ } else if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
+ if (change.getRotationAnimation() != ROTATION_ANIMATION_SEAMLESS) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+ " wallpaper is participating but isn't seamless.");
+ return false;
+ }
+ } else if (change.getTaskInfo() != null) {
+ // We only enable seamless rotation if all the visible task windows requested it.
+ if (change.getRotationAnimation() != ROTATION_ANIMATION_SEAMLESS) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+ " task %s isn't requesting seamless, so not seamless.",
+ change.getTaskInfo().taskId);
+ return false;
+ }
+
+ // This is the only way to get display-id currently, so we will check display
+ // capabilities here
+ if (!checkedDisplayLayout) {
+ // only need to check display once.
+ checkedDisplayLayout = true;
+ final DisplayLayout displayLayout = displayController.getDisplayLayout(
+ change.getTaskInfo().displayId);
+ // For the upside down rotation we don't rotate seamlessly as the navigation
+ // bar moves position. Note most apps (using orientation:sensor or user as
+ // opposed to fullSensor) will not enter the reverse portrait orientation, so
+ // actually the orientation won't change at all.
+ int upsideDownRotation = displayLayout.getUpsideDownRotation();
+ if (change.getStartRotation() == upsideDownRotation
+ || change.getEndRotation() == upsideDownRotation) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+ " rotation involves upside-down portrait, so not seamless.");
+ return false;
+ }
+
+ // If the navigation bar can't change sides, then it will jump when we change
+ // orientations and we don't rotate seamlessly - unless that is allowed, eg.
+ // with gesture navigation where the navbar is low-profile enough that this
+ // isn't very noticeable.
+ if (!displayLayout.allowSeamlessRotationDespiteNavBarMoving()
+ && (!(displayLayout.navigationBarCanMove()
+ && (change.getStartAbsBounds().width()
+ != change.getStartAbsBounds().height())))) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+ " nav bar changes sides, so not seamless.");
+ return false;
+ }
+ }
+ }
+ }
+
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Rotation IS seamless.");
+ return true;
+ }
+
+ /**
+ * Gets the rotation animation for the topmost task. Assumes that seamless is checked
+ * elsewhere, so it will default SEAMLESS to ROTATE.
+ */
+ private int getRotationAnimation(@NonNull TransitionInfo info) {
+ // Traverse in top-to-bottom order so that the first task is top-most
+ for (int i = 0; i < info.getChanges().size(); ++i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+
+ // Only look at changing things. showing/hiding don't need to rotate.
+ if (change.getMode() != TRANSIT_CHANGE) continue;
+
+ // This container isn't rotating, so we can ignore it.
+ if (change.getEndRotation() == change.getStartRotation()) continue;
+
+ if (change.getTaskInfo() != null) {
+ final int anim = change.getRotationAnimation();
+ if (anim == ROTATION_ANIMATION_UNSPECIFIED
+ // Fallback animation for seamless should also be default.
+ || anim == ROTATION_ANIMATION_SEAMLESS) {
+ return ROTATION_ANIMATION_ROTATE;
+ }
+ return anim;
+ }
+ }
+ return ROTATION_ANIMATION_ROTATE;
+ }
+
@Override
public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@@ -168,11 +284,15 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
if (info.getType() == TRANSIT_CHANGE && change.getMode() == TRANSIT_CHANGE
&& (change.getEndRotation() != change.getStartRotation())
&& (change.getFlags() & FLAG_IS_DISPLAY) != 0) {
- mRotationAnimation = new ScreenRotationAnimation(mContext, mSurfaceSession,
- mTransactionPool, startTransaction, change, info.getRootLeash());
- mRotationAnimation.startAnimation(animations, onAnimFinish,
- mTransitionAnimationScaleSetting, mMainExecutor, mAnimExecutor);
- continue;
+ boolean isSeamless = isRotationSeamless(info, mDisplayController);
+ final int anim = getRotationAnimation(info);
+ if (!(isSeamless || anim == ROTATION_ANIMATION_JUMPCUT)) {
+ mRotationAnimation = new ScreenRotationAnimation(mContext, mSurfaceSession,
+ mTransactionPool, startTransaction, change, info.getRootLeash());
+ mRotationAnimation.startAnimation(animations, onAnimFinish,
+ mTransitionAnimationScaleSetting, mMainExecutor, mAnimExecutor);
+ continue;
+ }
}
if (change.getMode() == TRANSIT_CHANGE) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 01ef2a6d5111..09dfabf9bfdf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -54,6 +54,7 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
@@ -113,15 +114,16 @@ public class Transitions implements RemoteCallable<Transitions> {
private final ArrayList<ActiveTransition> mActiveTransitions = new ArrayList<>();
public Transitions(@NonNull WindowOrganizer organizer, @NonNull TransactionPool pool,
- @NonNull Context context, @NonNull ShellExecutor mainExecutor,
- @NonNull ShellExecutor animExecutor) {
+ @NonNull DisplayController displayController, @NonNull Context context,
+ @NonNull ShellExecutor mainExecutor, @NonNull ShellExecutor animExecutor) {
mOrganizer = organizer;
mContext = context;
mMainExecutor = mainExecutor;
mAnimExecutor = animExecutor;
mPlayerImpl = new TransitionPlayerImpl();
// The very last handler (0 in the list) should be the default one.
- mHandlers.add(new DefaultTransitionHandler(pool, context, mainExecutor, animExecutor));
+ mHandlers.add(new DefaultTransitionHandler(displayController, pool, context, mainExecutor,
+ animExecutor));
// Next lowest priority is remote transitions.
mRemoteTransitionHandler = new RemoteTransitionHandler(mainExecutor);
mHandlers.add(mRemoteTransitionHandler);
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
index 9dd25fe0e6fe..3ca5b9c38aff 100644
--- a/libs/WindowManager/Shell/tests/flicker/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -25,11 +25,17 @@ package {
android_test {
name: "WMShellFlickerTests",
- srcs: ["src/**/*.java", "src/**/*.kt"],
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
manifest: "AndroidManifest.xml",
test_config: "AndroidTest.xml",
platform_apis: true,
certificate: "platform",
+ optimize: {
+ enabled: false,
+ },
test_suites: ["device-tests"],
libs: ["android.test.runner"],
static_libs: [
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
index c5b5b91d570b..b36468b7e9a5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
@@ -16,97 +16,100 @@
package com.android.wm.shell.flicker
+import android.content.ComponentName
import android.graphics.Region
import android.view.Surface
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.traces.layers.getVisibleBounds
-fun FlickerTestParameter.appPairsDividerIsVisible() {
+fun FlickerTestParameter.appPairsDividerIsVisibleAtEnd() {
assertLayersEnd {
- this.isVisible(APP_PAIR_SPLIT_DIVIDER)
+ this.isVisible(APP_PAIR_SPLIT_DIVIDER_COMPONENT)
}
}
-fun FlickerTestParameter.appPairsDividerIsInvisible() {
+fun FlickerTestParameter.appPairsDividerIsInvisibleAtEnd() {
assertLayersEnd {
- this.notContains(APP_PAIR_SPLIT_DIVIDER)
+ this.notContains(APP_PAIR_SPLIT_DIVIDER_COMPONENT)
}
}
fun FlickerTestParameter.appPairsDividerBecomesVisible() {
assertLayers {
- this.isInvisible(DOCKED_STACK_DIVIDER)
+ this.isInvisible(DOCKED_STACK_DIVIDER_COMPONENT)
.then()
- .isVisible(DOCKED_STACK_DIVIDER)
+ .isVisible(DOCKED_STACK_DIVIDER_COMPONENT)
}
}
-fun FlickerTestParameter.dockedStackDividerIsVisible() {
+fun FlickerTestParameter.dockedStackDividerIsVisibleAtEnd() {
assertLayersEnd {
- this.isVisible(DOCKED_STACK_DIVIDER)
+ this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT)
}
}
fun FlickerTestParameter.dockedStackDividerBecomesVisible() {
assertLayers {
- this.isInvisible(DOCKED_STACK_DIVIDER)
+ this.isInvisible(DOCKED_STACK_DIVIDER_COMPONENT)
.then()
- .isVisible(DOCKED_STACK_DIVIDER)
+ .isVisible(DOCKED_STACK_DIVIDER_COMPONENT)
}
}
fun FlickerTestParameter.dockedStackDividerBecomesInvisible() {
assertLayers {
- this.isVisible(DOCKED_STACK_DIVIDER)
+ this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT)
.then()
- .isInvisible(DOCKED_STACK_DIVIDER)
+ .isInvisible(DOCKED_STACK_DIVIDER_COMPONENT)
}
}
-fun FlickerTestParameter.dockedStackDividerIsInvisible() {
+fun FlickerTestParameter.dockedStackDividerNotExistsAtEnd() {
assertLayersEnd {
- this.notContains(DOCKED_STACK_DIVIDER)
+ this.notContains(DOCKED_STACK_DIVIDER_COMPONENT)
}
}
-fun FlickerTestParameter.appPairsPrimaryBoundsIsVisible(rotation: Int, primaryLayerName: String) {
+fun FlickerTestParameter.appPairsPrimaryBoundsIsVisibleAtEnd(
+ rotation: Int,
+ primaryComponent: ComponentName
+) {
assertLayersEnd {
- val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
- visibleRegion(primaryLayerName)
+ val dividerRegion = layer(APP_PAIR_SPLIT_DIVIDER_COMPONENT).visibleRegion.region
+ visibleRegion(primaryComponent)
.coversExactly(getPrimaryRegion(dividerRegion, rotation))
}
}
-fun FlickerTestParameter.dockedStackPrimaryBoundsIsVisible(
+fun FlickerTestParameter.dockedStackPrimaryBoundsIsVisibleAtEnd(
rotation: Int,
- primaryLayerName: String
+ primaryComponent: ComponentName
) {
assertLayersEnd {
- val dividerRegion = entry.getVisibleBounds(DOCKED_STACK_DIVIDER)
- visibleRegion(primaryLayerName)
+ val dividerRegion = layer(DOCKED_STACK_DIVIDER_COMPONENT).visibleRegion.region
+ visibleRegion(primaryComponent)
.coversExactly(getPrimaryRegion(dividerRegion, rotation))
}
}
-fun FlickerTestParameter.appPairsSecondaryBoundsIsVisible(
+fun FlickerTestParameter.appPairsSecondaryBoundsIsVisibleAtEnd(
rotation: Int,
- secondaryLayerName: String
+ secondaryComponent: ComponentName
) {
assertLayersEnd {
- val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
- visibleRegion(secondaryLayerName)
+ val dividerRegion = layer(APP_PAIR_SPLIT_DIVIDER_COMPONENT).visibleRegion.region
+ visibleRegion(secondaryComponent)
.coversExactly(getSecondaryRegion(dividerRegion, rotation))
}
}
-fun FlickerTestParameter.dockedStackSecondaryBoundsIsVisible(
+fun FlickerTestParameter.dockedStackSecondaryBoundsIsVisibleAtEnd(
rotation: Int,
- secondaryLayerName: String
+ secondaryComponent: ComponentName
) {
assertLayersEnd {
- val dividerRegion = entry.getVisibleBounds(DOCKED_STACK_DIVIDER)
- visibleRegion(secondaryLayerName)
+ val dividerRegion = layer(DOCKED_STACK_DIVIDER_COMPONENT).visibleRegion.region
+ visibleRegion(secondaryComponent)
.coversExactly(getSecondaryRegion(dividerRegion, rotation))
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
index 03b93c74233c..ff1a6e6d9d90 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
@@ -14,9 +14,11 @@
* limitations under the License.
*/
+@file:JvmName("CommonConstants")
package com.android.wm.shell.flicker
-const val IME_WINDOW_NAME = "InputMethod"
+import android.content.ComponentName
+
const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui"
-const val APP_PAIR_SPLIT_DIVIDER = "AppPairSplitDivider"
-const val DOCKED_STACK_DIVIDER = "DockedStackDivider" \ No newline at end of file
+val APP_PAIR_SPLIT_DIVIDER_COMPONENT = ComponentName("", "AppPairSplitDivider#")
+val DOCKED_STACK_DIVIDER_COMPONENT = ComponentName("", "DockedStackDivider#") \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
index ef9f7421fd60..19374ed04be5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.apppairs
-import android.os.SystemClock
import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
@@ -25,7 +24,7 @@ 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.wm.shell.flicker.appPairsDividerIsInvisible
+import com.android.wm.shell.flicker.appPairsDividerIsInvisibleAtEnd
import com.android.wm.shell.flicker.helpers.AppPairsHelper
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
@@ -61,7 +60,7 @@ class AppPairsTestCannotPairNonResizeableApps(
// TODO pair apps through normal UX flow
executeShellCommand(
composePairsCommand(primaryTaskId, nonResizeableTaskId, pair = true))
- SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
+ nonResizeableApp?.run { wmHelper.waitForFullScreenApp(nonResizeableApp.component) }
}
}
@@ -85,15 +84,13 @@ class AppPairsTestCannotPairNonResizeableApps(
@Test
override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
- @FlakyTest
+ @Presubmit
@Test
- override fun navBarLayerIsAlwaysVisible() {
- super.navBarLayerIsAlwaysVisible()
- }
+ override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
@Presubmit
@Test
- fun appPairsDividerIsInvisible() = testSpec.appPairsDividerIsInvisible()
+ fun appPairsDividerIsInvisibleAtEnd() = testSpec.appPairsDividerIsInvisibleAtEnd()
@Presubmit
@Test
@@ -103,8 +100,8 @@ class AppPairsTestCannotPairNonResizeableApps(
"Non resizeable app not initialized"
}
testSpec.assertWmEnd {
- isVisible(nonResizeableApp.defaultWindowName)
- isInvisible(primaryApp.defaultWindowName)
+ isVisible(nonResizeableApp.component)
+ isInvisible(primaryApp.component)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
index db63c4c43523..46ee89295a4e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.apppairs
-import android.os.SystemClock
import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
@@ -25,10 +24,10 @@ 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.flicker.traces.layers.getVisibleBounds
-import com.android.wm.shell.flicker.APP_PAIR_SPLIT_DIVIDER
-import com.android.wm.shell.flicker.appPairsDividerIsVisible
+import com.android.wm.shell.flicker.APP_PAIR_SPLIT_DIVIDER_COMPONENT
+import com.android.wm.shell.flicker.appPairsDividerIsVisibleAtEnd
import com.android.wm.shell.flicker.helpers.AppPairsHelper
+import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -54,10 +53,14 @@ class AppPairsTestPairPrimaryAndSecondaryApps(
// TODO pair apps through normal UX flow
executeShellCommand(
composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
- SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
+ waitAppsShown(primaryApp, secondaryApp)
}
}
+ @Presubmit
+ @Test
+ override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
+
@FlakyTest
@Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
@@ -68,14 +71,14 @@ class AppPairsTestPairPrimaryAndSecondaryApps(
@Presubmit
@Test
- fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible()
+ fun appPairsDividerIsVisibleAtEnd() = testSpec.appPairsDividerIsVisibleAtEnd()
@Presubmit
@Test
fun bothAppWindowsVisible() {
testSpec.assertWmEnd {
- isVisible(primaryApp.defaultWindowName)
- isVisible(secondaryApp.defaultWindowName)
+ isVisible(primaryApp.component)
+ isVisible(secondaryApp.component)
}
}
@@ -83,10 +86,10 @@ class AppPairsTestPairPrimaryAndSecondaryApps(
@Test
fun appsEndingBounds() {
testSpec.assertLayersEnd {
- val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
- visibleRegion(primaryApp.defaultWindowName)
+ val dividerRegion = layer(APP_PAIR_SPLIT_DIVIDER_COMPONENT).visibleRegion.region
+ visibleRegion(primaryApp.component)
.coversExactly(appPairsHelper.getPrimaryBounds(dividerRegion))
- visibleRegion(secondaryApp.defaultWindowName)
+ visibleRegion(secondaryApp.component)
.coversExactly(appPairsHelper.getSecondaryBounds(dividerRegion))
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
index c8d34237231c..f7ced71afe8a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.apppairs
-import android.os.SystemClock
import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
@@ -25,7 +24,7 @@ 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.wm.shell.flicker.appPairsDividerIsVisible
+import com.android.wm.shell.flicker.appPairsDividerIsVisibleAtEnd
import com.android.wm.shell.flicker.helpers.AppPairsHelper
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
@@ -61,7 +60,7 @@ class AppPairsTestSupportPairNonResizeableApps(
// TODO pair apps through normal UX flow
executeShellCommand(
composePairsCommand(primaryTaskId, nonResizeableTaskId, pair = true))
- SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
+ nonResizeableApp?.run { wmHelper.waitForFullScreenApp(nonResizeableApp.component) }
}
}
@@ -77,6 +76,10 @@ class AppPairsTestSupportPairNonResizeableApps(
resetMultiWindowConfig(instrumentation)
}
+ @Presubmit
+ @Test
+ override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
+
@FlakyTest
@Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
@@ -87,7 +90,7 @@ class AppPairsTestSupportPairNonResizeableApps(
@Presubmit
@Test
- fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible()
+ fun appPairsDividerIsVisibleAtEnd() = testSpec.appPairsDividerIsVisibleAtEnd()
@Presubmit
@Test
@@ -97,8 +100,8 @@ class AppPairsTestSupportPairNonResizeableApps(
"Non resizeable app not initialized"
}
testSpec.assertWmEnd {
- isVisible(nonResizeableApp.defaultWindowName)
- isVisible(primaryApp.defaultWindowName)
+ isVisible(nonResizeableApp.component)
+ isVisible(primaryApp.component)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
index 83df83600d11..3debdd3276e4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
@@ -25,10 +25,10 @@ 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.flicker.traces.layers.getVisibleBounds
-import com.android.wm.shell.flicker.APP_PAIR_SPLIT_DIVIDER
-import com.android.wm.shell.flicker.appPairsDividerIsInvisible
+import com.android.wm.shell.flicker.APP_PAIR_SPLIT_DIVIDER_COMPONENT
+import com.android.wm.shell.flicker.appPairsDividerIsInvisibleAtEnd
import com.android.wm.shell.flicker.helpers.AppPairsHelper
+import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -51,9 +51,11 @@ class AppPairsTestUnpairPrimaryAndSecondaryApps(
get() = {
super.transition(this, it)
setup {
- executeShellCommand(
- composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
- SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
+ eachRun {
+ executeShellCommand(
+ composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
+ waitAppsShown(primaryApp, secondaryApp)
+ }
}
transitions {
// TODO pair apps through normal UX flow
@@ -73,14 +75,14 @@ class AppPairsTestUnpairPrimaryAndSecondaryApps(
@Presubmit
@Test
- fun appPairsDividerIsInvisible() = testSpec.appPairsDividerIsInvisible()
+ fun appPairsDividerIsInvisibleAtEnd() = testSpec.appPairsDividerIsInvisibleAtEnd()
@Presubmit
@Test
fun bothAppWindowsInvisible() {
testSpec.assertWmEnd {
- isInvisible(primaryApp.defaultWindowName)
- isInvisible(secondaryApp.defaultWindowName)
+ isInvisible(primaryApp.component)
+ isInvisible(secondaryApp.component)
}
}
@@ -88,10 +90,10 @@ class AppPairsTestUnpairPrimaryAndSecondaryApps(
@Test
fun appsStartingBounds() {
testSpec.assertLayersStart {
- val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
- visibleRegion(primaryApp.defaultWindowName)
+ val dividerRegion = layer(APP_PAIR_SPLIT_DIVIDER_COMPONENT).visibleRegion.region
+ visibleRegion(primaryApp.component)
.coversExactly(appPairsHelper.getPrimaryBounds(dividerRegion))
- visibleRegion(secondaryApp.defaultWindowName)
+ visibleRegion(secondaryApp.component)
.coversExactly(appPairsHelper.getSecondaryBounds(dividerRegion))
}
}
@@ -100,16 +102,14 @@ class AppPairsTestUnpairPrimaryAndSecondaryApps(
@Test
fun appsEndingBounds() {
testSpec.assertLayersEnd {
- notContains(primaryApp.defaultWindowName)
- notContains(secondaryApp.defaultWindowName)
+ notContains(primaryApp.component)
+ notContains(secondaryApp.component)
}
}
- @FlakyTest
+ @Presubmit
@Test
- override fun navBarLayerIsAlwaysVisible() {
- super.navBarLayerIsAlwaysVisible()
- }
+ override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
index 1935bb97849c..cdf89a57fde8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
@@ -30,14 +30,14 @@ import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.isRotated
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.wm.shell.flicker.helpers.AppPairsHelper
import com.android.wm.shell.flicker.helpers.BaseAppHelper
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.getDevEnableNonResizableMultiWindow
@@ -154,26 +154,26 @@ abstract class AppPairsTransition(protected val testSpec: FlickerTestParameter)
@FlakyTest(bugId = 186510496)
@Test
- open fun navBarLayerIsAlwaysVisible() {
- testSpec.navBarLayerIsAlwaysVisible()
+ open fun navBarLayerIsVisible() {
+ testSpec.navBarLayerIsVisible()
}
@Presubmit
@Test
- open fun statusBarLayerIsAlwaysVisible() {
- testSpec.statusBarLayerIsAlwaysVisible()
+ open fun statusBarLayerIsVisible() {
+ testSpec.statusBarLayerIsVisible()
}
@Presubmit
@Test
- open fun navBarWindowIsAlwaysVisible() {
- testSpec.navBarWindowIsAlwaysVisible()
+ open fun navBarWindowIsVisible() {
+ testSpec.navBarWindowIsVisible()
}
@Presubmit
@Test
- open fun statusBarWindowIsAlwaysVisible() {
- testSpec.statusBarWindowIsAlwaysVisible()
+ open fun statusBarWindowIsVisible() {
+ testSpec.statusBarWindowIsVisible()
}
@Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
index c875c0006703..3e782e608c86 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.apppairs
-import android.os.SystemClock
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
@@ -28,10 +27,10 @@ import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.wm.shell.flicker.appPairsDividerIsVisible
-import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisible
-import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisible
-import com.android.wm.shell.flicker.helpers.AppPairsHelper
+import com.android.wm.shell.flicker.appPairsDividerIsVisibleAtEnd
+import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisibleAtEnd
+import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisibleAtEnd
+import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -57,41 +56,43 @@ class RotateTwoLaunchedAppsInAppPairsMode(
transitions {
executeShellCommand(composePairsCommand(
primaryTaskId, secondaryTaskId, true /* pair */))
- SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
+ waitAppsShown(primaryApp, secondaryApp)
setRotation(testSpec.config.endRotation)
}
}
- @FlakyTest
+ @Presubmit
@Test
- override fun statusBarLayerIsAlwaysVisible() {
- super.statusBarLayerIsAlwaysVisible()
- }
+ override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
+
+ @Presubmit
+ @Test
+ override fun statusBarLayerIsVisible() = super.statusBarLayerIsVisible()
@Presubmit
@Test
fun bothAppWindowsVisible() {
testSpec.assertWmEnd {
- isVisible(primaryApp.defaultWindowName)
- .isVisible(secondaryApp.defaultWindowName)
+ isVisible(primaryApp.component)
+ .isVisible(secondaryApp.component)
}
}
@Presubmit
@Test
- fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible()
+ fun appPairsDividerIsVisibleAtEnd() = testSpec.appPairsDividerIsVisibleAtEnd()
- @FlakyTest(bugId = 172776659)
+ @Presubmit
@Test
- fun appPairsPrimaryBoundsIsVisible() =
- testSpec.appPairsPrimaryBoundsIsVisible(testSpec.config.endRotation,
- primaryApp.defaultWindowName)
+ fun appPairsPrimaryBoundsIsVisibleAtEnd() =
+ testSpec.appPairsPrimaryBoundsIsVisibleAtEnd(testSpec.config.endRotation,
+ primaryApp.component)
- @FlakyTest(bugId = 172776659)
+ @FlakyTest
@Test
- fun appPairsSecondaryBoundsIsVisible() =
- testSpec.appPairsSecondaryBoundsIsVisible(testSpec.config.endRotation,
- secondaryApp.defaultWindowName)
+ fun appPairsSecondaryBoundsIsVisibleAtEnd() =
+ testSpec.appPairsSecondaryBoundsIsVisibleAtEnd(testSpec.config.endRotation,
+ secondaryApp.component)
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
index c3360ca0f7d3..ee28c7aa6beb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.apppairs
-import android.os.SystemClock
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
@@ -28,12 +27,10 @@ import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.appPairsDividerIsVisible
-import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisible
-import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisible
-import com.android.wm.shell.flicker.helpers.AppPairsHelper
+import com.android.wm.shell.flicker.appPairsDividerIsVisibleAtEnd
+import com.android.wm.shell.flicker.appPairsPrimaryBoundsIsVisibleAtEnd
+import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisibleAtEnd
+import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -60,48 +57,50 @@ class RotateTwoLaunchedAppsRotateAndEnterAppPairsMode(
this.setRotation(testSpec.config.endRotation)
executeShellCommand(
composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
- SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
+ waitAppsShown(primaryApp, secondaryApp)
}
}
@Presubmit
@Test
- fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible()
+ fun appPairsDividerIsVisibleAtEnd() = testSpec.appPairsDividerIsVisibleAtEnd()
@Presubmit
@Test
- override fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ override fun navBarWindowIsVisible() = super.navBarWindowIsVisible()
@Presubmit
@Test
- override fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
- @FlakyTest
+ @Presubmit
@Test
- override fun statusBarLayerIsAlwaysVisible() {
- super.statusBarLayerIsAlwaysVisible()
- }
+ override fun statusBarWindowIsVisible() = super.statusBarWindowIsVisible()
+
+ @Presubmit
+ @Test
+ override fun statusBarLayerIsVisible() = super.statusBarLayerIsVisible()
@Presubmit
@Test
fun bothAppWindowsVisible() {
testSpec.assertWmEnd {
- isVisible(primaryApp.defaultWindowName)
- isVisible(secondaryApp.defaultWindowName)
+ isVisible(primaryApp.component)
+ isVisible(secondaryApp.component)
}
}
@FlakyTest(bugId = 172776659)
@Test
- fun appPairsPrimaryBoundsIsVisible() =
- testSpec.appPairsPrimaryBoundsIsVisible(testSpec.config.endRotation,
- primaryApp.defaultWindowName)
+ fun appPairsPrimaryBoundsIsVisibleAtEnd() =
+ testSpec.appPairsPrimaryBoundsIsVisibleAtEnd(testSpec.config.endRotation,
+ primaryApp.component)
@FlakyTest(bugId = 172776659)
@Test
- fun appPairsSecondaryBoundsIsVisible() =
- testSpec.appPairsSecondaryBoundsIsVisible(testSpec.config.endRotation,
- secondaryApp.defaultWindowName)
+ fun appPairsSecondaryBoundsIsVisibleAtEnd() =
+ testSpec.appPairsSecondaryBoundsIsVisibleAtEnd(testSpec.config.endRotation,
+ secondaryApp.component)
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
index 277aca8fc01d..b95193a17265 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
@@ -40,8 +40,8 @@ abstract class RotateTwoLaunchedAppsTransition(
test {
device.wakeUpAndGoToHomeScreen()
this.setRotation(Surface.ROTATION_0)
- primaryApp.launchViaIntent()
- secondaryApp.launchViaIntent()
+ primaryApp.launchViaIntent(wmHelper)
+ secondaryApp.launchViaIntent(wmHelper)
updateTasksId()
}
}
@@ -64,8 +64,8 @@ abstract class RotateTwoLaunchedAppsTransition(
@FlakyTest
@Test
- override fun navBarLayerIsAlwaysVisible() {
- super.navBarLayerIsAlwaysVisible()
+ override fun navBarLayerIsVisible() {
+ super.navBarLayerIsVisible()
}
@FlakyTest
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
index 5b8cfb81016a..5a438af0b1f1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
@@ -19,6 +19,7 @@ package com.android.wm.shell.flicker.helpers
import android.app.Instrumentation
import android.content.ComponentName
import android.graphics.Region
+import com.android.server.wm.flicker.Flicker
import com.android.server.wm.flicker.helpers.WindowUtils
class AppPairsHelper(
@@ -43,5 +44,17 @@ class AppPairsHelper(
companion object {
const val TEST_REPETITIONS = 1
const val TIMEOUT_MS = 3_000L
+
+ fun Flicker.waitAppsShown(app1: SplitScreenHelper?, app2: SplitScreenHelper?) {
+ wmHelper.waitFor("primaryAndSecondaryAppsVisible") { dump ->
+ val primaryAppVisible = app1?.let {
+ dump.wmState.isWindowSurfaceShown(app1.defaultWindowName)
+ } ?: false
+ val secondaryAppVisible = app2?.let {
+ dump.wmState.isWindowSurfaceShown(app2.defaultWindowName)
+ } ?: false
+ primaryAppVisible && secondaryAppVisible
+ }
+ }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
index cac46fe676b3..086e8b792e0e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
@@ -61,7 +61,7 @@ open class ImeAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
if (wmHelper == null) {
device.waitForIdle()
} else {
- require(wmHelper.waitImeWindowShown()) { "IME did not appear" }
+ require(wmHelper.waitImeShown()) { "IME did not appear" }
}
}
@@ -78,7 +78,7 @@ open class ImeAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
if (wmHelper == null) {
uiDevice.waitForIdle()
} else {
- require(wmHelper.waitImeWindowGone()) { "IME did did not close" }
+ require(wmHelper.waitImeGone()) { "IME did did not close" }
}
} else {
// While pressing the back button should close the IME on TV as well, it may also lead
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 f4dd7decb1b7..d4b4e5daf7cb 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
@@ -62,7 +62,7 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
stringExtras: Map<String, String>
) {
super.launchViaIntent(wmHelper, expectedWindowName, action, stringExtras)
- wmHelper.waitFor { it.wmState.hasPipWindow() }
+ wmHelper.waitFor("hasPipWindow") { it.wmState.hasPipWindow() }
}
private fun focusOnObject(selector: BySelector): Boolean {
@@ -84,7 +84,7 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
clickObject(ENTER_PIP_BUTTON_ID)
// Wait on WMHelper or simply wait for 3 seconds
- wmHelper?.waitFor { it.wmState.hasPipWindow() } ?: SystemClock.sleep(3_000)
+ wmHelper?.waitFor("hasPipWindow") { it.wmState.hasPipWindow() } ?: SystemClock.sleep(3_000)
}
fun clickStartMediaSessionButton() {
@@ -137,7 +137,7 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
}
// Wait for animation to complete.
- wmHelper.waitFor { !it.wmState.hasPipWindow() }
+ wmHelper.waitFor("!hasPipWindow") { !it.wmState.hasPipWindow() }
wmHelper.waitForHomeActivityVisible()
}
@@ -167,7 +167,7 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
val windowRect = windowRegion.bounds
uiDevice.click(windowRect.centerX(), windowRect.centerY())
uiDevice.click(windowRect.centerX(), windowRect.centerY())
- wmHelper.waitFor { !it.wmState.hasPipWindow() }
+ wmHelper.waitFor("!hasPipWindow") { !it.wmState.hasPipWindow() }
wmHelper.waitForAppTransitionIdle()
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
index 4f12f2bb9f5f..508e93988aa6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
@@ -16,22 +16,24 @@
package com.android.wm.shell.flicker.legacysplitscreen
+import android.content.ComponentName
import android.platform.test.annotations.Presubmit
import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
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.FlickerTestParameterFactory
-import com.android.server.wm.flicker.HOME_WINDOW_TITLE
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible
-import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
+import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -60,16 +62,16 @@ class EnterSplitScreenDockActivity(
}
}
- override val ignoredWindows: List<String>
- get() = listOf(LAUNCHER_PACKAGE_NAME, LIVE_WALLPAPER_PACKAGE_NAME,
- splitScreenApp.defaultWindowName, WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME, *HOME_WINDOW_TITLE)
+ override val ignoredWindows: List<ComponentName>
+ get() = listOf(LAUNCHER_COMPONENT, LIVE_WALLPAPER_COMPONENT,
+ splitScreenApp.component, WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT,
+ WindowManagerStateHelper.SNAPSHOT_COMPONENT, LAUNCHER_COMPONENT)
@Presubmit
@Test
- fun dockedStackPrimaryBoundsIsVisible() =
- testSpec.dockedStackPrimaryBoundsIsVisible(testSpec.config.startRotation,
- splitScreenApp.defaultWindowName)
+ fun dockedStackPrimaryBoundsIsVisibleAtEnd() =
+ testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.config.startRotation,
+ splitScreenApp.component)
@Presubmit
@Test
@@ -77,27 +79,39 @@ class EnterSplitScreenDockActivity(
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
@Presubmit
@Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
@Presubmit
@Test
fun appWindowIsVisible() {
testSpec.assertWmEnd {
- isVisible(splitScreenApp.defaultWindowName)
+ isVisible(splitScreenApp.component)
}
}
+ @FlakyTest
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ @Presubmit
+ @Test
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0) // bugId = 179116910
+ supportedRotations = listOf(Surface.ROTATION_0), // bugId = 179116910
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)
)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt
index f91f634a00e5..12f3909b6c34 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenFromDetachedRecentTask.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.legacysplitscreen
+import android.content.ComponentName
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
@@ -25,7 +26,7 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
-import com.android.wm.shell.flicker.dockedStackDividerIsVisible
+import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -61,24 +62,34 @@ class EnterSplitScreenFromDetachedRecentTask(
}
}
- override val ignoredWindows: List<String>
- get() = listOf(LAUNCHER_PACKAGE_NAME,
- WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME,
- splitScreenApp.defaultWindowName)
+ override val ignoredWindows: List<ComponentName>
+ get() = listOf(LAUNCHER_COMPONENT,
+ WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT,
+ WindowManagerStateHelper.SNAPSHOT_COMPONENT,
+ splitScreenApp.component)
@Presubmit
@Test
- fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible()
+ fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
@Presubmit
@Test
fun appWindowIsVisible() {
testSpec.assertWmEnd {
- isVisible(splitScreenApp.defaultWindowName)
+ isVisible(splitScreenApp.component)
}
}
+ @Presubmit
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ @Presubmit
+ @Test
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
index 85ded8a45233..ac85c4857c76 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.legacysplitscreen
+import android.content.ComponentName
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
@@ -23,17 +24,16 @@ 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.Group1
-import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible
-import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
-import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisible
+import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd
+import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -62,22 +62,22 @@ class EnterSplitScreenLaunchToSide(
}
}
- override val ignoredWindows: List<String>
- get() = listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName,
- secondaryApp.defaultWindowName, WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
+ override val ignoredWindows: List<ComponentName>
+ get() = listOf(LAUNCHER_COMPONENT, splitScreenApp.component,
+ secondaryApp.component, WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT,
+ WindowManagerStateHelper.SNAPSHOT_COMPONENT)
@Presubmit
@Test
- fun dockedStackPrimaryBoundsIsVisible() =
- testSpec.dockedStackPrimaryBoundsIsVisible(testSpec.config.startRotation,
- splitScreenApp.defaultWindowName)
+ fun dockedStackPrimaryBoundsIsVisibleAtEnd() =
+ testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.config.startRotation,
+ splitScreenApp.component)
@Presubmit
@Test
- fun dockedStackSecondaryBoundsIsVisible() =
- testSpec.dockedStackSecondaryBoundsIsVisible(testSpec.config.startRotation,
- secondaryApp.defaultWindowName)
+ fun dockedStackSecondaryBoundsIsVisibleAtEnd() =
+ testSpec.dockedStackSecondaryBoundsIsVisibleAtEnd(testSpec.config.startRotation,
+ secondaryApp.component)
@Presubmit
@Test
@@ -85,15 +85,35 @@ class EnterSplitScreenLaunchToSide(
@Presubmit
@Test
- fun appWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp.defaultWindowName)
+ fun appWindowBecomesVisible() {
+ testSpec.assertWm {
+ // when the app is launched, first the activity becomes visible, then the
+ // SnapshotStartingWindow appears and then the app window becomes visible.
+ // Because we log WM once per frame, sometimes the activity and the window
+ // become visible in the same entry, sometimes not, thus it is not possible to
+ // assert the visibility of the activity here
+ this.isAppWindowInvisible(secondaryApp.component, ignoreActivity = true)
+ .then()
+ // during re-parenting, the window may disappear and reappear from the
+ // trace, this occurs because we log only 1x per frame
+ .notContains(secondaryApp.component, isOptional = true)
+ .then()
+ .isAppWindowVisible(secondaryApp.component)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
@Presubmit
@Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
index e958bf39930e..964af2341439 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.legacysplitscreen
+import android.content.ComponentName
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
@@ -26,7 +27,7 @@ import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.canSplitScreen
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
-import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
+import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
@@ -70,12 +71,12 @@ class EnterSplitScreenNotSupportNonResizable(
}
}
- override val ignoredWindows: List<String>
- get() = listOf(LAUNCHER_PACKAGE_NAME,
- WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME,
- nonResizeableApp.defaultWindowName,
- splitScreenApp.defaultWindowName)
+ override val ignoredWindows: List<ComponentName>
+ get() = listOf(LAUNCHER_COMPONENT,
+ WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT,
+ WindowManagerStateHelper.SNAPSHOT_COMPONENT,
+ nonResizeableApp.component,
+ splitScreenApp.component)
@Before
override fun setup() {
@@ -91,7 +92,12 @@ class EnterSplitScreenNotSupportNonResizable(
@Presubmit
@Test
- fun dockedStackDividerIsInvisible() = testSpec.dockedStackDividerIsInvisible()
+ fun dockedStackDividerNotExistsAtEnd() = testSpec.dockedStackDividerNotExistsAtEnd()
+
+ @Presubmit
+ @Test
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt
index d3acc82121b0..1b8afa668802 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.legacysplitscreen
+import android.content.ComponentName
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
@@ -26,7 +27,7 @@ import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
-import com.android.wm.shell.flicker.dockedStackDividerIsVisible
+import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
@@ -67,12 +68,12 @@ class EnterSplitScreenSupportNonResizable(
}
}
- override val ignoredWindows: List<String>
- get() = listOf(LAUNCHER_PACKAGE_NAME,
- WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME,
- nonResizeableApp.defaultWindowName,
- splitScreenApp.defaultWindowName)
+ override val ignoredWindows: List<ComponentName>
+ get() = listOf(LAUNCHER_COMPONENT,
+ WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT,
+ WindowManagerStateHelper.SNAPSHOT_COMPONENT,
+ nonResizeableApp.component,
+ splitScreenApp.component)
@Before
override fun setup() {
@@ -88,16 +89,21 @@ class EnterSplitScreenSupportNonResizable(
@Presubmit
@Test
- fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible()
+ fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
@Presubmit
@Test
fun appWindowIsVisible() {
testSpec.assertWmEnd {
- isVisible(nonResizeableApp.defaultWindowName)
+ isVisible(nonResizeableApp.component)
}
}
+ @Presubmit
+ @Test
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
index bad46836dcb7..247965f8071d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
@@ -16,7 +16,8 @@
package com.android.wm.shell.flicker.legacysplitscreen
-import android.platform.test.annotations.Presubmit
+import android.content.ComponentName
+import android.platform.test.annotations.Postsubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
@@ -24,15 +25,13 @@ 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.appWindowBecomesInVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.exitSplitScreenFromBottom
import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.layerBecomesInvisible
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
-import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER
+import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -67,31 +66,52 @@ class ExitLegacySplitScreenFromBottom(
}
}
transitions {
- device.exitSplitScreenFromBottom()
+ device.exitSplitScreenFromBottom(wmHelper)
}
}
- override val ignoredWindows: List<String>
- get() = listOf(LAUNCHER_PACKAGE_NAME, WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- splitScreenApp.defaultWindowName, secondaryApp.defaultWindowName,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
+ override val ignoredWindows: List<ComponentName>
+ get() = listOf(LAUNCHER_COMPONENT, WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT,
+ splitScreenApp.component, secondaryApp.component,
+ WindowManagerStateHelper.SNAPSHOT_COMPONENT)
- @Presubmit
+ @Postsubmit
@Test
- fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(DOCKED_STACK_DIVIDER)
+ fun layerBecomesInvisible() {
+ testSpec.assertLayers {
+ this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT)
+ .then()
+ .isInvisible(DOCKED_STACK_DIVIDER_COMPONENT)
+ }
+ }
@FlakyTest
@Test
- fun appWindowBecomesInVisible() =
- testSpec.appWindowBecomesInVisible(secondaryApp.defaultWindowName)
+ fun appWindowBecomesInVisible() {
+ testSpec.assertWm {
+ this.isAppWindowVisible(secondaryApp.component)
+ .then()
+ .isAppWindowInvisible(secondaryApp.component)
+ }
+ }
+
+ @Postsubmit
+ @Test
+ fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
- @Presubmit
+ @Postsubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
- @Presubmit
+ @FlakyTest
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ @FlakyTest
@Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
index 76dcd8b89242..af99fc4af1a0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
@@ -16,6 +16,8 @@
package com.android.wm.shell.flicker.legacysplitscreen
+import android.content.ComponentName
+import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
@@ -24,15 +26,13 @@ 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.appWindowBecomesInVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.layerBecomesInvisible
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
-import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
+import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -71,31 +71,52 @@ class ExitPrimarySplitScreenShowSecondaryFullscreen(
}
}
- override val ignoredWindows: List<String>
- get() = listOf(LAUNCHER_PACKAGE_NAME, WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- splitScreenApp.defaultWindowName, secondaryApp.defaultWindowName,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
+ override val ignoredWindows: List<ComponentName>
+ get() = listOf(LAUNCHER_COMPONENT, WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT,
+ splitScreenApp.component, secondaryApp.component,
+ WindowManagerStateHelper.SNAPSHOT_COMPONENT)
- @FlakyTest(bugId = 175687842)
+ @Presubmit
@Test
- fun dockedStackDividerIsInvisible() = testSpec.dockedStackDividerIsInvisible()
+ fun dockedStackDividerNotExistsAtEnd() = testSpec.dockedStackDividerNotExistsAtEnd()
@FlakyTest
@Test
- fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
+ fun layerBecomesInvisible() {
+ testSpec.assertLayers {
+ this.isVisible(splitScreenApp.component)
+ .then()
+ .isInvisible(splitScreenApp.component)
+ }
+ }
@FlakyTest
@Test
- fun appWindowBecomesInVisible() =
- testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
+ fun appWindowBecomesInVisible() {
+ testSpec.assertWm {
+ this.isAppWindowVisible(splitScreenApp.component)
+ .then()
+ .isAppWindowInvisible(splitScreenApp.component)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
@Presubmit
@Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ @Postsubmit
+ @Test
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt
index d0a64b3774c7..95e4085db4eb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.legacysplitscreen
+import android.content.ComponentName
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
@@ -23,15 +24,11 @@ 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.appWindowBecomesInVisible
-import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.layerBecomesInvisible
-import com.android.server.wm.flicker.layerBecomesVisible
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
-import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER
-import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
+import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT
+import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
@@ -72,11 +69,11 @@ class LegacySplitScreenFromIntentNotSupportNonResizable(
}
}
- override val ignoredWindows: List<String>
- get() = listOf(DOCKED_STACK_DIVIDER, LAUNCHER_PACKAGE_NAME, LETTERBOX_NAME,
- nonResizeableApp.defaultWindowName, splitScreenApp.defaultWindowName,
- WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
+ override val ignoredWindows: List<ComponentName>
+ get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT,
+ nonResizeableApp.component, splitScreenApp.component,
+ WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT,
+ WindowManagerStateHelper.SNAPSHOT_COMPONENT)
@Before
override fun setup() {
@@ -92,44 +89,110 @@ class LegacySplitScreenFromIntentNotSupportNonResizable(
@Presubmit
@Test
- fun resizableAppLayerBecomesInvisible() =
- testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
+ fun resizableAppLayerBecomesInvisible() {
+ testSpec.assertLayers {
+ this.isVisible(splitScreenApp.component)
+ .then()
+ .isInvisible(splitScreenApp.component)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun nonResizableAppLayerBecomesVisible() {
+ testSpec.assertLayers {
+ this.notContains(nonResizeableApp.component)
+ .then()
+ .isInvisible(nonResizeableApp.component)
+ .then()
+ .isVisible(nonResizeableApp.component)
+ }
+ }
+ /**
+ * Assets that [splitScreenApp] exists at the start of the trace and, once it becomes
+ * invisible, it remains invisible until the end of the trace.
+ */
@Presubmit
@Test
- fun nonResizableAppLayerBecomesVisible() =
- testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
+ fun resizableAppWindowBecomesInvisible() {
+ testSpec.assertWm {
+ // when the activity gets PAUSED the window may still be marked as visible
+ // it will be updated in the next log entry. This occurs because we record 1x
+ // per frame, thus ignore activity check here
+ this.isAppWindowVisible(splitScreenApp.component, ignoreActivity = true)
+ .then()
+ // immediately after the window (after onResume and before perform relayout)
+ // the activity is invisible. This may or not be logged, since we record 1x
+ // per frame, thus ignore activity check here
+ .isAppWindowInvisible(splitScreenApp.component, ignoreActivity = true)
+ }
+ }
+ /**
+ * Assets that [nonResizeableApp] doesn't exist at the start of the trace, then
+ * [nonResizeableApp] is created (visible or not) and, once [nonResizeableApp] becomes
+ * visible, it remains visible until the end of the trace.
+ */
@Presubmit
@Test
- fun resizableAppWindowBecomesInvisible() =
- testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
+ fun nonResizableAppWindowBecomesVisible() {
+ testSpec.assertWm {
+ this.notContains(nonResizeableApp.component)
+ .then()
+ // we log once per frame, upon logging, window may be visible or not depending
+ // on what was processed until that moment. Both behaviors are correct
+ .isAppWindowInvisible(nonResizeableApp.component,
+ ignoreActivity = true, isOptional = true)
+ .then()
+ // immediately after the window (after onResume and before perform relayout)
+ // the activity is invisible. This may or not be logged, since we record 1x
+ // per frame, thus ignore activity check here
+ .isAppWindowVisible(nonResizeableApp.component, ignoreActivity = true)
+ }
+ }
+ /**
+ * Asserts that both the app window and the activity are visible at the end of the trace
+ */
@Presubmit
@Test
- fun nonResizableAppWindowBecomesVisible() =
- testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
+ fun nonResizableAppWindowBecomesVisibleAtEnd() {
+ testSpec.assertWmEnd {
+ this.isVisible(nonResizeableApp.component)
+ }
+ }
@Presubmit
@Test
- fun dockedStackDividerIsInvisibleAtEnd() = testSpec.dockedStackDividerIsInvisible()
+ fun dockedStackDividerNotExistsAtEnd() = testSpec.dockedStackDividerNotExistsAtEnd()
@Presubmit
@Test
fun onlyNonResizableAppWindowIsVisibleAtEnd() {
testSpec.assertWmEnd {
- isInvisible(splitScreenApp.defaultWindowName)
- isVisible(nonResizeableApp.defaultWindowName)
+ isInvisible(splitScreenApp.component)
+ isVisible(nonResizeableApp.component)
}
}
+ @Presubmit
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ @Presubmit
+ @Test
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- repetitions = SplitScreenHelper.TEST_REPETITIONS,
- supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
+ repetitions = SplitScreenHelper.TEST_REPETITIONS,
+ supportedRotations = listOf(Surface.ROTATION_0)) // b/178685668
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt
index c26c05fa8db6..65346aa8ea5d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.legacysplitscreen
+import android.content.ComponentName
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
@@ -23,13 +24,11 @@ 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.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.layerBecomesVisible
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
-import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER
-import com.android.wm.shell.flicker.dockedStackDividerIsVisible
+import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT
+import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
@@ -70,11 +69,11 @@ class LegacySplitScreenFromIntentSupportNonResizable(
}
}
- override val ignoredWindows: List<String>
- get() = listOf(DOCKED_STACK_DIVIDER, LAUNCHER_PACKAGE_NAME, LETTERBOX_NAME,
- nonResizeableApp.defaultWindowName, splitScreenApp.defaultWindowName,
- WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
+ override val ignoredWindows: List<ComponentName>
+ get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT,
+ nonResizeableApp.component, splitScreenApp.component,
+ WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT,
+ WindowManagerStateHelper.SNAPSHOT_COMPONENT)
@Before
override fun setup() {
@@ -90,27 +89,60 @@ class LegacySplitScreenFromIntentSupportNonResizable(
@Presubmit
@Test
- fun nonResizableAppLayerBecomesVisible() =
- testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
+ fun nonResizableAppLayerBecomesVisible() {
+ testSpec.assertLayers {
+ this.isInvisible(nonResizeableApp.component)
+ .then()
+ .isVisible(nonResizeableApp.component)
+ }
+ }
+ /**
+ * Assets that [nonResizeableApp] doesn't exist at the start of the trace, then
+ * [nonResizeableApp] is created (visible or not) and, once [nonResizeableApp] becomes
+ * visible, it remains visible until the end of the trace.
+ */
@Presubmit
@Test
- fun nonResizableAppWindowBecomesVisible() =
- testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
+ fun nonResizableAppWindowBecomesVisible() {
+ testSpec.assertWm {
+ this.notContains(nonResizeableApp.component)
+ .then()
+ // we log once per frame, upon logging, window may be visible or not depending
+ // on what was processed until that moment. Both behaviors are correct
+ .isAppWindowInvisible(nonResizeableApp.component,
+ ignoreActivity = true, isOptional = true)
+ .then()
+ // immediately after the window (after onResume and before perform relayout)
+ // the activity is invisible. This may or not be logged, since we record 1x
+ // per frame, thus ignore activity check here
+ .isAppWindowVisible(nonResizeableApp.component, ignoreActivity = true)
+ }
+ }
@Presubmit
@Test
- fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisible()
+ fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
@Presubmit
@Test
fun bothAppsWindowsAreVisibleAtEnd() {
testSpec.assertWmEnd {
- isVisible(splitScreenApp.defaultWindowName)
- isVisible(nonResizeableApp.defaultWindowName)
+ isVisible(splitScreenApp.component)
+ isVisible(nonResizeableApp.component)
}
}
+ @Presubmit
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ @Presubmit
+ @Test
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt
index fb1758975442..547341a14cdd 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt
@@ -16,6 +16,8 @@
package com.android.wm.shell.flicker.legacysplitscreen
+import android.content.ComponentName
+import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
@@ -23,16 +25,12 @@ 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.appWindowBecomesInVisible
-import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.layerBecomesInvisible
-import com.android.server.wm.flicker.layerBecomesVisible
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
-import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER
-import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
+import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT
+import com.android.wm.shell.flicker.dockedStackDividerNotExistsAtEnd
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
@@ -73,11 +71,11 @@ class LegacySplitScreenFromRecentNotSupportNonResizable(
}
}
- override val ignoredWindows: List<String>
- get() = listOf(DOCKED_STACK_DIVIDER, LAUNCHER_PACKAGE_NAME, LETTERBOX_NAME, TOAST_NAME,
- splitScreenApp.defaultWindowName, nonResizeableApp.defaultWindowName,
- WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
+ override val ignoredWindows: List<ComponentName>
+ get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT,
+ TOAST_COMPONENT, splitScreenApp.component, nonResizeableApp.component,
+ WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT,
+ WindowManagerStateHelper.SNAPSHOT_COMPONENT)
@Before
override fun setup() {
@@ -93,37 +91,73 @@ class LegacySplitScreenFromRecentNotSupportNonResizable(
@Presubmit
@Test
- fun resizableAppLayerBecomesInvisible() =
- testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
+ fun resizableAppLayerBecomesInvisible() {
+ testSpec.assertLayers {
+ this.isVisible(splitScreenApp.component)
+ .then()
+ .isInvisible(splitScreenApp.component)
+ }
+ }
@Presubmit
@Test
- fun nonResizableAppLayerBecomesVisible() =
- testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
+ fun nonResizableAppLayerBecomesVisible() {
+ testSpec.assertLayers {
+ this.isInvisible(nonResizeableApp.component)
+ .then()
+ .isVisible(nonResizeableApp.component)
+ }
+ }
@Presubmit
@Test
- fun resizableAppWindowBecomesInvisible() =
- testSpec.appWindowBecomesInVisible(splitScreenApp.defaultWindowName)
+ fun resizableAppWindowBecomesInvisible() {
+ testSpec.assertWm {
+ // when the activity gets PAUSED the window may still be marked as visible
+ // it will be updated in the next log entry. This occurs because we record 1x
+ // per frame, thus ignore activity check here
+ this.isAppWindowVisible(splitScreenApp.component, ignoreActivity = true)
+ .then()
+ // immediately after the window (after onResume and before perform relayout)
+ // the activity is invisible. This may or not be logged, since we record 1x
+ // per frame, thus ignore activity check here
+ .isAppWindowInvisible(splitScreenApp.component, ignoreActivity = true)
+ }
+ }
- @Presubmit
+ @Postsubmit
@Test
- fun nonResizableAppWindowBecomesVisible() =
- testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
+ fun nonResizableAppWindowBecomesVisible() {
+ testSpec.assertWm {
+ this.isAppWindowInvisible(nonResizeableApp.component)
+ .then()
+ .isAppWindowVisible(nonResizeableApp.component)
+ }
+ }
@Presubmit
@Test
- fun dockedStackDividerIsInvisibleAtEnd() = testSpec.dockedStackDividerIsInvisible()
+ fun dockedStackDividerNotExistsAtEnd() = testSpec.dockedStackDividerNotExistsAtEnd()
@Presubmit
@Test
fun onlyNonResizableAppWindowIsVisibleAtEnd() {
testSpec.assertWmEnd {
- isInvisible(splitScreenApp.defaultWindowName)
- isVisible(nonResizeableApp.defaultWindowName)
+ isInvisible(splitScreenApp.component)
+ isVisible(nonResizeableApp.component)
}
}
+ @Presubmit
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ @Presubmit
+ @Test
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt
index a9c28efcdf44..3f86658297fe 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.legacysplitscreen
+import android.content.ComponentName
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
@@ -23,14 +24,12 @@ 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.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.layerBecomesVisible
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
-import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER
-import com.android.wm.shell.flicker.dockedStackDividerIsVisible
+import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT
+import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSupportsNonResizableMultiWindow
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
@@ -71,11 +70,11 @@ class LegacySplitScreenFromRecentSupportNonResizable(
}
}
- override val ignoredWindows: List<String>
- get() = listOf(DOCKED_STACK_DIVIDER, LAUNCHER_PACKAGE_NAME, LETTERBOX_NAME, TOAST_NAME,
- splitScreenApp.defaultWindowName, nonResizeableApp.defaultWindowName,
- WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
+ override val ignoredWindows: List<ComponentName>
+ get() = listOf(DOCKED_STACK_DIVIDER_COMPONENT, LAUNCHER_COMPONENT, LETTERBOX_COMPONENT,
+ TOAST_COMPONENT, splitScreenApp.component, nonResizeableApp.component,
+ WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT,
+ WindowManagerStateHelper.SNAPSHOT_COMPONENT)
@Before
override fun setup() {
@@ -91,27 +90,60 @@ class LegacySplitScreenFromRecentSupportNonResizable(
@Presubmit
@Test
- fun nonResizableAppLayerBecomesVisible() =
- testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
+ fun nonResizableAppLayerBecomesVisible() {
+ testSpec.assertLayers {
+ this.isInvisible(nonResizeableApp.component)
+ .then()
+ .isVisible(nonResizeableApp.component)
+ }
+ }
@Presubmit
@Test
- fun nonResizableAppWindowBecomesVisible() =
- testSpec.appWindowBecomesVisible(nonResizeableApp.defaultWindowName)
+ fun nonResizableAppWindowBecomesVisible() {
+ testSpec.assertWm {
+ // when the app is launched, first the activity becomes visible, then the
+ // SnapshotStartingWindow appears and then the app window becomes visible.
+ // Because we log WM once per frame, sometimes the activity and the window
+ // become visible in the same entry, sometimes not, thus it is not possible to
+ // assert the visibility of the activity here
+ this.isAppWindowInvisible(nonResizeableApp.component, ignoreActivity = true)
+ .then()
+ // during re-parenting, the window may disappear and reappear from the
+ // trace, this occurs because we log only 1x per frame
+ .notContains(nonResizeableApp.component, isOptional = true)
+ .then()
+ // if the window reappears after re-parenting it will most likely not
+ // be visible in the first log entry (because we log only 1x per frame)
+ .isAppWindowInvisible(nonResizeableApp.component, isOptional = true)
+ .then()
+ .isAppWindowVisible(nonResizeableApp.component)
+ }
+ }
@Presubmit
@Test
- fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisible()
+ fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
@Presubmit
@Test
fun bothAppsWindowsAreVisibleAtEnd() {
testSpec.assertWmEnd {
- isVisible(splitScreenApp.defaultWindowName)
- isVisible(nonResizeableApp.defaultWindowName)
+ isVisible(splitScreenApp.component)
+ isVisible(nonResizeableApp.component)
}
}
+ @Presubmit
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ @Presubmit
+ @Test
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
index a4d2ab51e358..7b4b71b41967 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
@@ -16,10 +16,10 @@
package com.android.wm.shell.flicker.legacysplitscreen
+import android.content.ComponentName
+import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
-import android.support.test.launcherhelper.LauncherStrategyFactory
import android.view.Surface
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -27,20 +27,18 @@ 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.endRotation
-import com.android.server.wm.flicker.focusDoesNotChange
+import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.helpers.exitSplitScreen
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.layerBecomesInvisible
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import com.android.wm.shell.flicker.dockedStackDividerBecomesInvisible
import com.android.wm.shell.flicker.helpers.SimpleAppHelper
@@ -62,8 +60,6 @@ import org.junit.runners.Parameterized
class LegacySplitScreenToLauncher(
testSpec: FlickerTestParameter
) : LegacySplitScreenTransition(testSpec) {
- private val launcherPackageName = LauncherStrategyFactory.getInstance(instrumentation)
- .launcherStrategy.supportedLauncherPackage
private val testApp = SimpleAppHelper(instrumentation)
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
@@ -90,25 +86,25 @@ class LegacySplitScreenToLauncher(
}
}
- override val ignoredWindows: List<String>
- get() = listOf(launcherPackageName, WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
+ override val ignoredWindows: List<ComponentName>
+ get() = listOf(LAUNCHER_COMPONENT, WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT,
+ WindowManagerStateHelper.SNAPSHOT_COMPONENT)
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
@Presubmit
@Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
@Presubmit
@Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+ fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
@Presubmit
@Test
- fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.endRotation)
+ fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.endRotation)
@Presubmit
@Test
@@ -122,19 +118,39 @@ class LegacySplitScreenToLauncher(
@Presubmit
@Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+ fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
- @Presubmit
+ @Postsubmit
@Test
fun dockedStackDividerBecomesInvisible() = testSpec.dockedStackDividerBecomesInvisible()
+ @Postsubmit
+ @Test
+ fun layerBecomesInvisible() {
+ testSpec.assertLayers {
+ this.isVisible(testApp.component)
+ .then()
+ .isInvisible(testApp.component)
+ }
+ }
+
+ @Postsubmit
+ @Test
+ fun focusDoesNotChange() {
+ testSpec.assertEventLog {
+ this.focusDoesNotChange()
+ }
+ }
+
@Presubmit
@Test
- fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(testApp.getPackage())
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
- @FlakyTest(bugId = 151179149)
+ @Presubmit
@Test
- fun focusDoesNotChange() = testSpec.focusDoesNotChange()
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
index 16dfd853209f..666d259f2b40 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
@@ -17,6 +17,7 @@
package com.android.wm.shell.flicker.legacysplitscreen
import android.app.Instrumentation
+import android.content.ComponentName
import android.content.Context
import android.support.test.launcherhelper.LauncherStrategyFactory
import android.view.Surface
@@ -48,8 +49,9 @@ abstract class LegacySplitScreenTransition(protected val testSpec: FlickerTestPa
protected val splitScreenApp = SplitScreenHelper.getPrimary(instrumentation)
protected val secondaryApp = SplitScreenHelper.getSecondary(instrumentation)
protected val nonResizeableApp = SplitScreenHelper.getNonResizeable(instrumentation)
- protected val LAUNCHER_PACKAGE_NAME = LauncherStrategyFactory.getInstance(instrumentation)
- .launcherStrategy.supportedLauncherPackage
+ protected val LAUNCHER_COMPONENT = ComponentName("",
+ LauncherStrategyFactory.getInstance(instrumentation)
+ .launcherStrategy.supportedLauncherPackage)
private var prevDevEnableNonResizableMultiWindow = 0
@Before
@@ -74,8 +76,9 @@ abstract class LegacySplitScreenTransition(protected val testSpec: FlickerTestPa
*
* b/182720234
*/
- open val ignoredWindows: List<String> = listOf(WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
+ open val ignoredWindows: List<ComponentName> = listOf(
+ WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT,
+ WindowManagerStateHelper.SNAPSHOT_COMPONENT)
protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = { configuration ->
@@ -142,9 +145,9 @@ abstract class LegacySplitScreenTransition(protected val testSpec: FlickerTestPa
}
companion object {
- internal const val LIVE_WALLPAPER_PACKAGE_NAME =
- "com.breel.wallpapers18.soundviz.wallpaper.variations.SoundVizWallpaperV2"
- internal const val LETTERBOX_NAME = "Letterbox"
- internal const val TOAST_NAME = "Toast"
+ internal val LIVE_WALLPAPER_COMPONENT = ComponentName("",
+ "com.breel.wallpapers18.soundviz.wallpaper.variations.SoundVizWallpaperV2")
+ internal val LETTERBOX_COMPONENT = ComponentName("", "Letterbox")
+ internal val TOAST_COMPONENT = ComponentName("", "Toast")
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
index 05eb5f49a641..ec0c73a58846 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.legacysplitscreen
+import android.content.ComponentName
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
@@ -24,14 +25,11 @@ 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.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.focusChanges
+import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.layerBecomesVisible
-import com.android.server.wm.flicker.noUncoveredRegions
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import com.android.wm.shell.flicker.appPairsDividerBecomesVisible
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
@@ -62,22 +60,28 @@ class OpenAppToLegacySplitScreen(
}
}
- override val ignoredWindows: List<String>
- get() = listOf(LAUNCHER_PACKAGE_NAME, splitScreenApp.defaultWindowName,
- WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
+ override val ignoredWindows: List<ComponentName>
+ get() = listOf(LAUNCHER_COMPONENT, splitScreenApp.component,
+ WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT,
+ WindowManagerStateHelper.SNAPSHOT_COMPONENT)
@FlakyTest
@Test
- fun appWindowBecomesVisible() = testSpec.appWindowBecomesVisible(splitScreenApp.getPackage())
+ fun appWindowBecomesVisible() {
+ testSpec.assertWm {
+ this.isAppWindowInvisible(splitScreenApp.component)
+ .then()
+ .isAppWindowVisible(splitScreenApp.component)
+ }
+ }
- @FlakyTest
+ @Presubmit
@Test
- fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
+ fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation)
@Presubmit
@Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+ fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
@Presubmit
@Test
@@ -85,12 +89,27 @@ class OpenAppToLegacySplitScreen(
@FlakyTest
@Test
- fun layerBecomesVisible() = testSpec.layerBecomesVisible(splitScreenApp.getPackage())
+ fun layerBecomesVisible() {
+ testSpec.assertLayers {
+ this.isInvisible(splitScreenApp.component)
+ .then()
+ .isVisible(splitScreenApp.component)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun focusChanges() {
+ testSpec.assertEventLog {
+ this.focusChanges(splitScreenApp.`package`,
+ "recents_animation_input_consumer", "NexusLauncherActivity")
+ }
+ }
- @FlakyTest(bugId = 151179149)
+ @Presubmit
@Test
- fun focusChanges() = testSpec.focusChanges(splitScreenApp.`package`,
- "recents_animation_input_consumer", "NexusLauncherActivity")
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
index 3e83b6382939..d7f71a83ba7e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
@@ -28,23 +28,23 @@ 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.endRotation
+import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.helpers.ImeAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.resizeSplitScreen
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.traces.layers.getVisibleBounds
-import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER
+import com.android.server.wm.flicker.statusBarWindowIsVisible
+import com.android.wm.shell.flicker.DOCKED_STACK_DIVIDER_COMPONENT
import com.android.wm.shell.flicker.helpers.SimpleAppHelper
+import com.android.wm.shell.flicker.testapp.Components
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -101,16 +101,16 @@ class ResizeLegacySplitScreen(
}
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
@Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
@FlakyTest(bugId = 156223549)
@Test
fun topAppWindowIsAlwaysVisible() {
testSpec.assertWm {
- this.showsAppWindow(sSimpleActivity)
+ this.isAppWindowVisible(Components.SimpleActivity.COMPONENT)
}
}
@@ -118,18 +118,18 @@ class ResizeLegacySplitScreen(
@Test
fun bottomAppWindowIsAlwaysVisible() {
testSpec.assertWm {
- this.showsAppWindow(sImeActivity)
+ this.isAppWindowVisible(Components.ImeActivity.COMPONENT)
}
}
@Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+ fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
@Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+ fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
@Test
- fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.endRotation)
+ fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.endRotation)
@Test
fun navBarLayerRotatesAndScales() =
@@ -142,21 +142,21 @@ class ResizeLegacySplitScreen(
@Test
fun topAppLayerIsAlwaysVisible() {
testSpec.assertLayers {
- this.isVisible(sSimpleActivity)
+ this.isVisible(Components.SimpleActivity.COMPONENT)
}
}
@Test
fun bottomAppLayerIsAlwaysVisible() {
testSpec.assertLayers {
- this.isVisible(sImeActivity)
+ this.isVisible(Components.ImeActivity.COMPONENT)
}
}
@Test
fun dividerLayerIsAlwaysVisible() {
testSpec.assertLayers {
- this.isVisible(DOCKED_STACK_DIVIDER)
+ this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT)
}
}
@@ -166,7 +166,7 @@ class ResizeLegacySplitScreen(
testSpec.assertLayersStart {
val displayBounds = WindowUtils.displayBounds
val dividerBounds =
- entry.getVisibleBounds(DOCKED_STACK_DIVIDER).bounds
+ layer(DOCKED_STACK_DIVIDER_COMPONENT).visibleRegion.region.bounds
val topAppBounds = Region(0, 0, dividerBounds.right,
dividerBounds.top + WindowUtils.dockedStackDividerInset)
@@ -174,8 +174,8 @@ class ResizeLegacySplitScreen(
dividerBounds.bottom - WindowUtils.dockedStackDividerInset,
displayBounds.right,
displayBounds.bottom - WindowUtils.navigationBarHeight)
- visibleRegion("SimpleActivity").coversExactly(topAppBounds)
- visibleRegion("ImeActivity").coversExactly(bottomAppBounds)
+ visibleRegion(Components.SimpleActivity.COMPONENT).coversExactly(topAppBounds)
+ visibleRegion(Components.ImeActivity.COMPONENT).coversExactly(bottomAppBounds)
}
}
@@ -185,7 +185,7 @@ class ResizeLegacySplitScreen(
testSpec.assertLayersStart {
val displayBounds = WindowUtils.displayBounds
val dividerBounds =
- entry.getVisibleBounds(DOCKED_STACK_DIVIDER).bounds
+ layer(DOCKED_STACK_DIVIDER_COMPONENT).visibleRegion.region.bounds
val topAppBounds = Region(0, 0, dividerBounds.right,
dividerBounds.top + WindowUtils.dockedStackDividerInset)
@@ -194,8 +194,8 @@ class ResizeLegacySplitScreen(
displayBounds.right,
displayBounds.bottom - WindowUtils.navigationBarHeight)
- visibleRegion(sSimpleActivity).coversExactly(topAppBounds)
- visibleRegion(sImeActivity).coversExactly(bottomAppBounds)
+ visibleRegion(Components.SimpleActivity.COMPONENT).coversExactly(topAppBounds)
+ visibleRegion(Components.ImeActivity.COMPONENT).coversExactly(bottomAppBounds)
}
}
@@ -207,8 +207,6 @@ class ResizeLegacySplitScreen(
}
companion object {
- private const val sSimpleActivity = "SimpleActivity"
- private const val sImeActivity = "ImeActivity"
private val startRatio = Rational(1, 3)
private val stopRatio = Rational(2, 3)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
index 58482eaae3f5..8a2b55b6fce0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
@@ -24,18 +24,17 @@ 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.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.dockedStackDividerIsVisible
-import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
+import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
+import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -66,21 +65,21 @@ class RotateOneLaunchedAppAndEnterSplitScreen(
@Presubmit
@Test
- fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible()
+ fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
@Presubmit
@Test
- fun dockedStackPrimaryBoundsIsVisible() =
- testSpec.dockedStackPrimaryBoundsIsVisible(testSpec.config.startRotation,
- splitScreenApp.defaultWindowName)
+ fun dockedStackPrimaryBoundsIsVisibleAtEnd() =
+ testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.config.startRotation,
+ splitScreenApp.component)
- @FlakyTest(bugId = 169271943)
+ @Presubmit
@Test
fun navBarLayerRotatesAndScales() =
testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation,
testSpec.config.endRotation)
- @FlakyTest(bugId = 169271943)
+ @Presubmit
@Test
fun statusBarLayerRotatesScales() =
testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation,
@@ -88,16 +87,26 @@ class RotateOneLaunchedAppAndEnterSplitScreen(
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
@Presubmit
@Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
@FlakyTest
@Test
- fun appWindowBecomesVisible() =
- testSpec.appWindowBecomesVisible(splitScreenApp.defaultWindowName)
+ fun appWindowBecomesVisible() {
+ testSpec.assertWm {
+ this.isAppWindowInvisible(splitScreenApp.component)
+ .then()
+ .isAppWindowVisible(splitScreenApp.component)
+ }
+ }
+
+ @Presubmit
+ @Test
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
index 06828d6adb26..b3251573c942 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
@@ -24,18 +24,17 @@ 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.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.dockedStackDividerIsVisible
-import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
+import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
+import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -66,35 +65,45 @@ class RotateOneLaunchedAppInSplitScreenMode(
@Presubmit
@Test
- fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible()
+ fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
@Presubmit
@Test
- fun dockedStackPrimaryBoundsIsVisible() = testSpec.dockedStackPrimaryBoundsIsVisible(
- testSpec.config.startRotation, splitScreenApp.defaultWindowName)
+ fun dockedStackPrimaryBoundsIsVisibleAtEnd() = testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(
+ testSpec.config.startRotation, splitScreenApp.component)
- @FlakyTest(bugId = 169271943)
+ @Presubmit
@Test
fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales(
testSpec.config.startRotation, testSpec.config.endRotation)
- @FlakyTest(bugId = 169271943)
+ @Presubmit
@Test
fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales(
testSpec.config.startRotation, testSpec.config.endRotation)
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
@Presubmit
@Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
@FlakyTest
@Test
- fun appWindowBecomesVisible() =
- testSpec.appWindowBecomesVisible(splitScreenApp.defaultWindowName)
+ fun appWindowBecomesVisible() {
+ testSpec.assertWm {
+ this.isAppWindowInvisible(splitScreenApp.component)
+ .then()
+ .isAppWindowVisible(splitScreenApp.component)
+ }
+ }
+
+ @Presubmit
+ @Test
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
index f8e32bf171d8..2be693631b26 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
@@ -18,26 +18,24 @@ package com.android.wm.shell.flicker.legacysplitscreen
import android.platform.test.annotations.Presubmit
import android.view.Surface
-import androidx.test.filters.FlakyTest
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.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group2
-import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.dockedStackDividerIsVisible
-import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
-import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
+import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
+import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd
+import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -69,42 +67,66 @@ class RotateTwoLaunchedAppAndEnterSplitScreen(
@Presubmit
@Test
- fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible()
+ fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
@Presubmit
@Test
- fun dockedStackPrimaryBoundsIsVisible() =
- testSpec.dockedStackPrimaryBoundsIsVisible(testSpec.config.startRotation,
- splitScreenApp.defaultWindowName)
+ fun dockedStackPrimaryBoundsIsVisibleAtEnd() =
+ testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.config.startRotation,
+ splitScreenApp.component)
@Presubmit
@Test
- fun dockedStackSecondaryBoundsIsVisible() =
- testSpec.dockedStackSecondaryBoundsIsVisible(testSpec.config.startRotation,
- secondaryApp.defaultWindowName)
+ fun dockedStackSecondaryBoundsIsVisibleAtEnd() =
+ testSpec.dockedStackSecondaryBoundsIsVisibleAtEnd(testSpec.config.startRotation,
+ secondaryApp.component)
- @FlakyTest(bugId = 169271943)
+ @Presubmit
@Test
fun navBarLayerRotatesAndScales() =
testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation,
testSpec.config.endRotation)
- @FlakyTest(bugId = 169271943)
+ @Presubmit
@Test
fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales(
testSpec.config.startRotation, testSpec.config.endRotation)
@Presubmit
@Test
- fun appWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp.defaultWindowName)
+ fun appWindowBecomesVisible() {
+ testSpec.assertWm {
+ // when the app is launched, first the activity becomes visible, then the
+ // SnapshotStartingWindow appears and then the app window becomes visible.
+ // Because we log WM once per frame, sometimes the activity and the window
+ // become visible in the same entry, sometimes not, thus it is not possible to
+ // assert the visibility of the activity here
+ this.isAppWindowInvisible(secondaryApp.component, ignoreActivity = true)
+ .then()
+ // during re-parenting, the window may disappear and reappear from the
+ // trace, this occurs because we log only 1x per frame
+ .notContains(secondaryApp.component, isOptional = true)
+ .then()
+ // if the window reappears after re-parenting it will most likely not
+ // be visible in the first log entry (because we log only 1x per frame)
+ .isAppWindowInvisible(secondaryApp.component, isOptional = true)
+ .then()
+ .isAppWindowVisible(secondaryApp.component)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
@Presubmit
@Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
index cb246ca0b694..5782f145c00f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
@@ -24,20 +24,19 @@ 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.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.dockedStackDividerIsVisible
-import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
-import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
+import com.android.wm.shell.flicker.dockedStackDividerIsVisibleAtEnd
+import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisibleAtEnd
+import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -74,27 +73,27 @@ class RotateTwoLaunchedAppInSplitScreenMode(
@Presubmit
@Test
- fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible()
+ fun dockedStackDividerIsVisibleAtEnd() = testSpec.dockedStackDividerIsVisibleAtEnd()
@Presubmit
@Test
- fun dockedStackPrimaryBoundsIsVisible() =
- testSpec.dockedStackPrimaryBoundsIsVisible(testSpec.config.startRotation,
- splitScreenApp.defaultWindowName)
+ fun dockedStackPrimaryBoundsIsVisibleAtEnd() =
+ testSpec.dockedStackPrimaryBoundsIsVisibleAtEnd(testSpec.config.startRotation,
+ splitScreenApp.component)
@Presubmit
@Test
- fun dockedStackSecondaryBoundsIsVisible() =
- testSpec.dockedStackSecondaryBoundsIsVisible(testSpec.config.startRotation,
- secondaryApp.defaultWindowName)
+ fun dockedStackSecondaryBoundsIsVisibleAtEnd() =
+ testSpec.dockedStackSecondaryBoundsIsVisibleAtEnd(testSpec.config.startRotation,
+ secondaryApp.component)
- @FlakyTest(bugId = 169271943)
+ @Presubmit
@Test
fun navBarLayerRotatesAndScales() =
testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation,
testSpec.config.endRotation)
- @FlakyTest(bugId = 169271943)
+ @Presubmit
@Test
fun statusBarLayerRotatesScales() =
testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation,
@@ -102,16 +101,31 @@ class RotateTwoLaunchedAppInSplitScreenMode(
@FlakyTest
@Test
- fun appWindowBecomesVisible() =
- testSpec.appWindowBecomesVisible(secondaryApp.defaultWindowName)
+ fun appWindowBecomesVisible() {
+ testSpec.assertWm {
+ this.isAppWindowInvisible(secondaryApp.component)
+ .then()
+ .isAppWindowVisible(secondaryApp.component)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
@Presubmit
@Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/CommonAssertions.kt
index 2a660747bc1d..443204c245db 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/CommonAssertions.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,4 +16,4 @@
package com.android.wm.shell.flicker.pip
-internal const val PIP_WINDOW_TITLE = "PipMenuActivity"
+internal const val PIP_WINDOW_COMPONENT = "PipMenuActivity"
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
index 00e50e7fe3b5..39e89fbd9b71 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
@@ -62,18 +63,21 @@ class EnterExitPipTest(
@Test
fun pipAppRemainInsideVisibleBounds() {
testSpec.assertWm {
- coversAtMost(displayBounds, pipApp.defaultWindowName)
+ coversAtMost(displayBounds, pipApp.component)
}
}
- @Presubmit
+ @Postsubmit
@Test
fun showBothAppWindowsThenHidePip() {
testSpec.assertWm {
- showsAppWindow(testApp.defaultWindowName)
- .showsAppWindowOnTop(pipApp.defaultWindowName)
+ // when the activity is STOPPING, sometimes it becomes invisible in an entry before
+ // the window, sometimes in the same entry. This occurs because we log 1x per frame
+ // thus we ignore activity here
+ isAppWindowVisible(testApp.component, ignoreActivity = true)
+ .isAppWindowOnTop(pipApp.component)
.then()
- .hidesAppWindow(testApp.defaultWindowName)
+ .isAppWindowInvisible(testApp.component)
}
}
@@ -81,10 +85,10 @@ class EnterExitPipTest(
@Test
fun showBothAppLayersThenHidePip() {
testSpec.assertLayers {
- isVisible(testApp.defaultWindowName)
- .isVisible(pipApp.defaultWindowName)
+ isVisible(testApp.component)
+ .isVisible(pipApp.component)
.then()
- .isInvisible(testApp.defaultWindowName)
+ .isInvisible(testApp.component)
}
}
@@ -92,8 +96,8 @@ class EnterExitPipTest(
@Test
fun testAppCoversFullScreenWithPipOnDisplay() {
testSpec.assertLayersStart {
- visibleRegion(testApp.defaultWindowName).coversExactly(displayBounds)
- visibleRegion(pipApp.defaultWindowName).coversAtMost(displayBounds)
+ visibleRegion(testApp.component).coversExactly(displayBounds)
+ visibleRegion(pipApp.component).coversAtMost(displayBounds)
}
}
@@ -101,7 +105,7 @@ class EnterExitPipTest(
@Test
fun pipAppCoversFullScreen() {
testSpec.assertLayersEnd {
- visibleRegion(pipApp.defaultWindowName).coversExactly(displayBounds)
+ visibleRegion(pipApp.component).coversExactly(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 b6af26060050..0f0a4abe30ef 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
@@ -44,30 +44,24 @@ class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = buildTransition(eachRun = true, stringExtras = emptyMap()) {
transitions {
- pipApp.clickEnterPipButton()
+ pipApp.clickEnterPipButton(wmHelper)
pipApp.expandPipWindow(wmHelper)
}
}
- @FlakyTest
- @Test
- override fun noUncoveredRegions() {
- super.noUncoveredRegions()
- }
-
@Presubmit
@Test
fun pipAppWindowAlwaysVisible() {
testSpec.assertWm {
- this.showsAppWindow(pipApp.defaultWindowName)
+ this.isAppWindowVisible(pipApp.component)
}
}
- @FlakyTest
+ @Presubmit
@Test
- fun pipLayerBecomesVisible() {
+ fun pipAppLayerAlwaysVisible() {
testSpec.assertLayers {
- this.isVisible(pipApp.windowName)
+ this.isVisible(pipApp.component)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index 3a1456e53f87..67ad322f19f6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -92,15 +92,13 @@ class EnterPipToOtherOrientationTest(
@FlakyTest
@Test
- override fun noUncoveredRegions() {
- super.noUncoveredRegions()
- }
+ override fun entireScreenCovered() = super.entireScreenCovered()
@Presubmit
@Test
fun pipAppWindowIsAlwaysOnTop() {
testSpec.assertWm {
- showsAppWindowOnTop(pipApp.defaultWindowName)
+ isAppWindowOnTop(pipApp.component)
}
}
@@ -108,7 +106,7 @@ class EnterPipToOtherOrientationTest(
@Test
fun pipAppHidesTestApp() {
testSpec.assertWmStart {
- isInvisible(testApp.defaultWindowName)
+ isInvisible(testApp.component)
}
}
@@ -116,7 +114,7 @@ class EnterPipToOtherOrientationTest(
@Test
fun testAppWindowIsVisible() {
testSpec.assertWmEnd {
- isVisible(testApp.defaultWindowName)
+ isVisible(testApp.component)
}
}
@@ -124,8 +122,8 @@ class EnterPipToOtherOrientationTest(
@Test
fun pipAppLayerHidesTestApp() {
testSpec.assertLayersStart {
- visibleRegion(pipApp.defaultWindowName).coversExactly(startingBounds)
- isInvisible(testApp.defaultWindowName)
+ visibleRegion(pipApp.component).coversExactly(startingBounds)
+ isInvisible(testApp.component)
}
}
@@ -133,7 +131,7 @@ class EnterPipToOtherOrientationTest(
@Test
fun testAppLayerCoversFullScreen() {
testSpec.assertLayersEnd {
- visibleRegion(testApp.defaultWindowName).coversExactly(endingBounds)
+ visibleRegion(testApp.component).coversExactly(endingBounds)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt
index eae7e973711c..28b1028d41ca 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt
@@ -21,8 +21,8 @@ import android.view.Surface
import androidx.test.filters.FlakyTest
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.LAUNCHER_COMPONENT
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.startRotation
import org.junit.Test
@@ -47,9 +47,9 @@ abstract class PipCloseTransition(testSpec: FlickerTestParameter) : PipTransitio
@Test
open fun pipWindowBecomesInvisible() {
testSpec.assertWm {
- this.showsAppWindow(PIP_WINDOW_TITLE)
+ this.invoke("hasPipWindow") { it.isPinned(pipApp.component) }
.then()
- .hidesAppWindow(PIP_WINDOW_TITLE)
+ .isAppWindowInvisible(pipApp.component)
}
}
@@ -57,15 +57,21 @@ abstract class PipCloseTransition(testSpec: FlickerTestParameter) : PipTransitio
@Test
open fun pipLayerBecomesInvisible() {
testSpec.assertLayers {
- this.isVisible(PIP_WINDOW_TITLE)
+ this.isVisible(pipApp.component)
+ .isVisible(LAUNCHER_COMPONENT)
.then()
- .isInvisible(PIP_WINDOW_TITLE)
+ .isInvisible(pipApp.component)
+ .isVisible(LAUNCHER_COMPONENT)
}
}
@FlakyTest(bugId = 151179149)
@Test
- open fun focusChanges() = testSpec.focusChanges(pipApp.launcherName, "NexusLauncherActivity")
+ open fun focusChanges() {
+ testSpec.assertEventLog {
+ this.focusChanges(pipApp.launcherName, "NexusLauncherActivity")
+ }
+ }
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt
index cf84a2c696d0..1c5d77f68f43 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt
@@ -48,13 +48,9 @@ class PipCloseWithDismissButtonTest(testSpec: FlickerTestParameter) : PipCloseTr
@FlakyTest
@Test
- override fun pipLayerBecomesInvisible() {
- super.pipLayerBecomesInvisible()
- }
+ override fun pipLayerBecomesInvisible() = super.pipLayerBecomesInvisible()
@FlakyTest
@Test
- override fun pipWindowBecomesInvisible() {
- super.pipWindowBecomesInvisible()
- }
+ override fun pipWindowBecomesInvisible() = super.pipWindowBecomesInvisible()
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
index 524a1b404591..356ec94b97e3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
@@ -56,19 +56,19 @@ class PipCloseWithSwipeTest(testSpec: FlickerTestParameter) : PipCloseTransition
@Presubmit
@Test
- override fun navBarLayerIsAlwaysVisible() = super.navBarLayerIsAlwaysVisible()
+ override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
@Presubmit
@Test
- override fun statusBarLayerIsAlwaysVisible() = super.statusBarLayerIsAlwaysVisible()
+ override fun statusBarLayerIsVisible() = super.statusBarLayerIsVisible()
@Presubmit
@Test
- override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
+ override fun navBarWindowIsVisible() = super.navBarWindowIsVisible()
@Presubmit
@Test
- override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
+ override fun statusBarWindowIsVisible() = super.statusBarWindowIsVisible()
@FlakyTest
@Test
@@ -85,7 +85,7 @@ class PipCloseWithSwipeTest(testSpec: FlickerTestParameter) : PipCloseTransition
@Presubmit
@Test
- override fun noUncoveredRegions() = super.noUncoveredRegions()
+ override fun entireScreenCovered() = super.entireScreenCovered()
@Presubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
index d88f94d5954a..5719413aff25 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
@@ -27,7 +27,7 @@ import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.startRotation
-import com.android.wm.shell.flicker.IME_WINDOW_NAME
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import com.android.wm.shell.flicker.helpers.ImeAppHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -79,7 +79,7 @@ class PipKeyboardTest(testSpec: FlickerTestParameter) : PipTransition(testSpec)
fun pipInVisibleBounds() {
testSpec.assertWm {
val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
- coversAtMost(displayBounds, pipApp.defaultWindowName)
+ coversAtMost(displayBounds, pipApp.component)
}
}
@@ -90,7 +90,7 @@ class PipKeyboardTest(testSpec: FlickerTestParameter) : PipTransition(testSpec)
@Test
fun pipIsAboveAppWindow() {
testSpec.assertWmTag(TAG_IME_VISIBLE) {
- isAboveWindow(IME_WINDOW_NAME, pipApp.defaultWindowName)
+ isAboveWindow(WindowManagerStateHelper.IME_COMPONENT, pipApp.component)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
index 6833b96a802b..c09fdc203dbc 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
@@ -46,7 +46,6 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 161435597)
@Group3
class PipLegacySplitScreenTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
private val imeApp = ImeAppHelper(instrumentation)
@@ -80,11 +79,11 @@ class PipLegacySplitScreenTest(testSpec: FlickerTestParameter) : PipTransition(t
}
}
- @Presubmit
+ @FlakyTest(bugId = 161435597)
@Test
fun pipWindowInsideDisplayBounds() {
testSpec.assertWm {
- coversAtMost(displayBounds, pipApp.defaultWindowName)
+ coversAtMost(displayBounds, pipApp.component)
}
}
@@ -92,25 +91,17 @@ class PipLegacySplitScreenTest(testSpec: FlickerTestParameter) : PipTransition(t
@Test
fun bothAppWindowsVisible() {
testSpec.assertWmEnd {
- isVisible(testApp.defaultWindowName)
- isVisible(imeApp.defaultWindowName)
- noWindowsOverlap(testApp.defaultWindowName, imeApp.defaultWindowName)
+ isVisible(testApp.component)
+ isVisible(imeApp.component)
+ noWindowsOverlap(testApp.component, imeApp.component)
}
}
- @Presubmit
- @Test
- override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
-
- @Presubmit
- @Test
- override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
-
- @Presubmit
+ @FlakyTest(bugId = 161435597)
@Test
fun pipLayerInsideDisplayBounds() {
testSpec.assertLayers {
- coversAtMost(displayBounds, pipApp.defaultWindowName)
+ coversAtMost(displayBounds, pipApp.component)
}
}
@@ -118,18 +109,14 @@ class PipLegacySplitScreenTest(testSpec: FlickerTestParameter) : PipTransition(t
@Test
fun bothAppLayersVisible() {
testSpec.assertLayersEnd {
- visibleRegion(testApp.defaultWindowName).coversAtMost(displayBounds)
- visibleRegion(imeApp.defaultWindowName).coversAtMost(displayBounds)
+ visibleRegion(testApp.component).coversAtMost(displayBounds)
+ visibleRegion(imeApp.component).coversAtMost(displayBounds)
}
}
- @Presubmit
- @Test
- override fun navBarLayerIsAlwaysVisible() = super.navBarLayerIsAlwaysVisible()
-
- @Presubmit
+ @FlakyTest(bugId = 161435597)
@Test
- override fun statusBarLayerIsAlwaysVisible() = super.statusBarLayerIsAlwaysVisible()
+ override fun entireScreenCovered() = super.entireScreenCovered()
companion object {
const val TEST_REPETITIONS = 2
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
index d531af28e2ad..e0ec75778342 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -26,10 +26,10 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.noUncoveredRegions
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.wm.shell.flicker.helpers.FixedAppHelper
@@ -73,9 +73,9 @@ class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testSpec)
}
}
- @FlakyTest(bugId = 185400889)
+ @Presubmit
@Test
- override fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ override fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation,
testSpec.config.endRotation, allStates = false)
@FlakyTest
@@ -90,21 +90,21 @@ class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testSpec)
testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation,
testSpec.config.endRotation)
- @FlakyTest(bugId = 185400889)
+ @Presubmit
@Test
fun appLayerRotates_StartingBounds() {
testSpec.assertLayersStart {
- visibleRegion(fixedApp.defaultWindowName).coversExactly(startingBounds)
- visibleRegion(pipApp.defaultWindowName).coversAtMost(startingBounds)
+ visibleRegion(fixedApp.component).coversExactly(startingBounds)
+ visibleRegion(pipApp.component).coversAtMost(startingBounds)
}
}
- @FlakyTest(bugId = 185400889)
+ @Presubmit
@Test
fun appLayerRotates_EndingBounds() {
testSpec.assertLayersEnd {
- visibleRegion(fixedApp.defaultWindowName).coversExactly(endingBounds)
- visibleRegion(pipApp.defaultWindowName).coversAtMost(endingBounds)
+ visibleRegion(fixedApp.component).coversExactly(endingBounds)
+ visibleRegion(pipApp.component).coversAtMost(endingBounds)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipShelfHeightTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipShelfHeightTest.kt
index 1294ac93f647..914bc8b4d1c9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipShelfHeightTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipShelfHeightTest.kt
@@ -63,13 +63,13 @@ class PipShelfHeightTest(testSpec: FlickerTestParameter) : PipTransition(testSpe
@Presubmit
@Test
- fun pipAlwaysVisible() = testSpec.assertWm { this.showsAppWindow(pipApp.windowName) }
+ fun pipAlwaysVisible() = testSpec.assertWm { this.isAppWindowVisible(pipApp.component) }
@Presubmit
@Test
fun pipLayerInsideDisplay() {
testSpec.assertLayersStart {
- visibleRegion(pipApp.defaultWindowName).coversAtMost(displayBounds)
+ visibleRegion(pipApp.component).coversAtMost(displayBounds)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
index 55e5c4128967..5abcf39f3fbd 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
@@ -22,9 +22,9 @@ 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.FlickerTestParameterFactory
+import com.android.server.wm.flicker.LAUNCHER_COMPONENT
import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.startRotation
import org.junit.FixMethodOrder
@@ -64,9 +64,11 @@ class PipToAppTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
@Test
fun appReplacesPipWindow() {
testSpec.assertWm {
- this.showsAppWindow(PIP_WINDOW_TITLE)
+ this.invoke("hasPipWindow") { it.isPinned(pipApp.component) }
+ .isAppWindowOnTop(pipApp.component)
.then()
- .showsAppWindowOnTop(pipApp.launcherName)
+ .invoke("hasNotPipWindow") { it.isNotPinned(pipApp.component) }
+ .isAppWindowOnTop(pipApp.component)
}
}
@@ -74,9 +76,11 @@ class PipToAppTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
@Test
fun appReplacesPipLayer() {
testSpec.assertLayers {
- this.isVisible(PIP_WINDOW_TITLE)
+ this.isVisible(pipApp.component)
+ .isVisible(LAUNCHER_COMPONENT)
.then()
- .isVisible(pipApp.launcherName)
+ .isVisible(pipApp.component)
+ .isInvisible(LAUNCHER_COMPONENT)
}
}
@@ -84,22 +88,26 @@ class PipToAppTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
@Test
fun testAppCoversFullScreen() {
testSpec.assertLayersStart {
- visibleRegion(pipApp.defaultWindowName).coversExactly(displayBounds)
+ visibleRegion(pipApp.component).coversExactly(displayBounds)
}
}
@FlakyTest(bugId = 151179149)
@Test
- fun focusChanges() = testSpec.focusChanges("NexusLauncherActivity",
- pipApp.launcherName, "NexusLauncherActivity")
+ fun focusChanges() {
+ testSpec.assertEventLog {
+ this.focusChanges("NexusLauncherActivity",
+ pipApp.launcherName, "NexusLauncherActivity")
+ }
+ }
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): List<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
- repetitions = 5)
+ .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
+ repetitions = 5)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
index b4c75a6d1165..ca80d1837ea8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
@@ -20,25 +20,24 @@ import android.app.Instrumentation
import android.content.Intent
import android.platform.test.annotations.Presubmit
import android.view.Surface
-import androidx.test.filters.FlakyTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.isRotated
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.wm.shell.flicker.helpers.PipAppHelper
import com.android.wm.shell.flicker.testapp.Components
import org.junit.Test
@@ -162,19 +161,19 @@ abstract class PipTransition(protected val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- open fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ open fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
@Presubmit
@Test
- open fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ open fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
- @FlakyTest
+ @Presubmit
@Test
- open fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+ open fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
- @FlakyTest
+ @Presubmit
@Test
- open fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+ open fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
@Presubmit
@Test
@@ -188,6 +187,6 @@ abstract class PipTransition(protected val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- open fun noUncoveredRegions() =
- testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
+ open fun entireScreenCovered() =
+ testSpec.entireScreenCovered(testSpec.config.startRotation, Surface.ROTATION_0)
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
index 1f58bb2bf9db..e7b61970cbeb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
@@ -83,54 +82,70 @@ class SetRequestedOrientationWhilePinnedTest(
@FlakyTest
@Test
+ override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
+
+ @FlakyTest
+ @Test
+ override fun navBarWindowIsVisible() = super.navBarWindowIsVisible()
+
+ @FlakyTest
+ @Test
+ override fun statusBarLayerIsVisible() = super.statusBarLayerIsVisible()
+
+ @FlakyTest
+ @Test
+ override fun statusBarWindowIsVisible() = super.statusBarWindowIsVisible()
+
+ @FlakyTest
+ @Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
@FlakyTest
@Test
override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
- @Presubmit
+ @FlakyTest
@Test
fun pipWindowInsideDisplay() {
testSpec.assertWmStart {
- frameRegion(pipApp.defaultWindowName).coversAtMost(startingBounds)
+ frameRegion(pipApp.component).coversAtMost(startingBounds)
}
}
- @Presubmit
+ @FlakyTest
@Test
fun pipAppShowsOnTop() {
testSpec.assertWmEnd {
- showsAppWindowOnTop(pipApp.defaultWindowName)
+ isAppWindowOnTop(pipApp.component)
}
}
- @Presubmit
+ @FlakyTest
@Test
fun pipLayerInsideDisplay() {
testSpec.assertLayersStart {
- visibleRegion(pipApp.defaultWindowName).coversAtMost(startingBounds)
+ visibleRegion(pipApp.component).coversAtMost(startingBounds)
}
}
- @Presubmit
+ @FlakyTest
@Test
fun pipAlwaysVisible() = testSpec.assertWm {
- this.showsAppWindow(pipApp.windowName)
+ this.isAppWindowVisible(pipApp.component)
}
- @Presubmit
+ @FlakyTest
@Test
fun pipAppLayerCoversFullScreen() {
testSpec.assertLayersEnd {
- visibleRegion(pipApp.defaultWindowName).coversExactly(endingBounds)
+ visibleRegion(pipApp.component).coversExactly(endingBounds)
}
}
@FlakyTest
@Test
- override fun noUncoveredRegions() {
- super.noUncoveredRegions()
+ override fun entireScreenCovered() {
+ super.entireScreenCovered()
}
companion object {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
index 0110ba3f5b30..061218a015e4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
@@ -37,14 +37,17 @@ class TvPipMenuTests : TvPipTestBase() {
private val systemUiResources =
packageManager.getResourcesForApplication(SYSTEM_UI_PACKAGE_NAME)
private val pipBoundsWhileInMenu: Rect = systemUiResources.run {
- val bounds = getString(getIdentifier("pip_menu_bounds", "string", SYSTEM_UI_PACKAGE_NAME))
+ val bounds = getString(getIdentifier("pip_menu_bounds", "string",
+ SYSTEM_UI_PACKAGE_NAME))
Rect.unflattenFromString(bounds) ?: error("Could not retrieve PiP menu bounds")
}
private val playButtonDescription = systemUiResources.run {
- getString(getIdentifier("pip_play", "string", SYSTEM_UI_PACKAGE_NAME))
+ getString(getIdentifier("pip_play", "string",
+ SYSTEM_UI_PACKAGE_NAME))
}
private val pauseButtonDescription = systemUiResources.run {
- getString(getIdentifier("pip_pause", "string", SYSTEM_UI_PACKAGE_NAME))
+ getString(getIdentifier("pip_pause", "string",
+ SYSTEM_UI_PACKAGE_NAME))
}
@Before
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
index 1b73920046dc..1c663409b913 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
@@ -70,7 +70,8 @@ fun UiDevice.waitForTvPipMenuElementWithDescription(desc: String): UiObject2? {
// descendant and then retrieve the element from the menu and return to the caller of this
// method.
val elementSelector = By.desc(desc)
- val menuContainingElementSelector = By.copy(TV_PIP_MENU_SELECTOR).hasDescendant(elementSelector)
+ val menuContainingElementSelector = By.copy(TV_PIP_MENU_SELECTOR)
+ .hasDescendant(elementSelector)
return wait(Until.findObject(menuContainingElementSelector), WAIT_TIME_MS)
?.findObject(elementSelector)
@@ -94,7 +95,8 @@ fun UiDevice.clickTvPipMenuFullscreenButton() {
}
fun UiDevice.clickTvPipMenuElementWithDescription(desc: String) {
- focusOnAndClickTvPipMenuElement(By.desc(desc).pkg(SYSTEM_UI_PACKAGE_NAME)) ||
+ focusOnAndClickTvPipMenuElement(By.desc(desc)
+ .pkg(SYSTEM_UI_PACKAGE_NAME)) ||
error("Could not focus on the Pip menu object with \"$desc\" description")
// So apparently Accessibility framework on TV is not very reliable and sometimes the state of
// the tree of accessibility nodes as seen by the accessibility clients kind of lags behind of
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java
index 6644eaf28a62..5c1bcb9753a4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java
@@ -63,7 +63,7 @@ public class BubbleFlyoutViewTest extends ShellTestCase {
mFlyoutMessage.senderName = "Josh";
mFlyoutMessage.message = "Hello";
- mFlyout = new BubbleFlyoutView(getContext());
+ mFlyout = new BubbleFlyoutView(getContext(), mPositioner);
mFlyoutText = mFlyout.findViewById(R.id.bubble_flyout_text);
mSenderName = mFlyout.findViewById(R.id.bubble_flyout_name);
@@ -75,9 +75,8 @@ public class BubbleFlyoutViewTest extends ShellTestCase {
public void testShowFlyout_isVisible() {
mFlyout.setupFlyoutStartingAsDot(
mFlyoutMessage,
- new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter,
- false,
- mPositioner);
+ new PointF(100, 100), true, Color.WHITE, null, null, mDotCenter,
+ false);
mFlyout.setVisibility(View.VISIBLE);
assertEquals("Hello", mFlyoutText.getText());
@@ -89,9 +88,8 @@ public class BubbleFlyoutViewTest extends ShellTestCase {
public void testFlyoutHide_runsCallback() {
Runnable after = mock(Runnable.class);
mFlyout.setupFlyoutStartingAsDot(mFlyoutMessage,
- new PointF(100, 100), 500, true, Color.WHITE, null, after, mDotCenter,
- false,
- mPositioner);
+ new PointF(100, 100), true, Color.WHITE, null, after, mDotCenter,
+ false);
mFlyout.hideFlyout();
verify(after).run();
@@ -100,9 +98,8 @@ public class BubbleFlyoutViewTest extends ShellTestCase {
@Test
public void testSetCollapsePercent() {
mFlyout.setupFlyoutStartingAsDot(mFlyoutMessage,
- new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter,
- false,
- mPositioner);
+ new PointF(100, 100), true, Color.WHITE, null, null, mDotCenter,
+ false);
mFlyout.setVisibility(View.VISIBLE);
mFlyout.setCollapsePercent(1f);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
index e138595c47f3..3557906531b2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -24,6 +24,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.res.Configuration;
@@ -42,6 +43,8 @@ import com.android.wm.shell.common.DisplayImeController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -53,19 +56,20 @@ public class SplitLayoutTests extends ShellTestCase {
@Mock SurfaceControl mRootLeash;
@Mock DisplayImeController mDisplayImeController;
@Mock ShellTaskOrganizer mTaskOrganizer;
+ @Captor ArgumentCaptor<Runnable> mRunnableCaptor;
private SplitLayout mSplitLayout;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mSplitLayout = new SplitLayout(
+ mSplitLayout = spy(new SplitLayout(
"TestSplitLayout",
mContext,
getConfiguration(),
mSplitLayoutHandler,
b -> b.setParent(mRootLeash),
mDisplayImeController,
- mTaskOrganizer);
+ mTaskOrganizer));
}
@Test
@@ -92,13 +96,13 @@ public class SplitLayoutTests extends ShellTestCase {
@Test
public void testUpdateDivideBounds() {
mSplitLayout.updateDivideBounds(anyInt());
- verify(mSplitLayoutHandler).onBoundsChanging(any(SplitLayout.class));
+ verify(mSplitLayoutHandler).onLayoutChanging(any(SplitLayout.class));
}
@Test
public void testSetDividePosition() {
mSplitLayout.setDividePosition(anyInt());
- verify(mSplitLayoutHandler).onBoundsChanged(any(SplitLayout.class));
+ verify(mSplitLayoutHandler).onLayoutChanged(any(SplitLayout.class));
}
@Test
@@ -109,18 +113,33 @@ public class SplitLayoutTests extends ShellTestCase {
@Test
@UiThreadTest
- public void testSnapToDismissTarget() {
+ public void testSnapToDismissStart() {
// verify it callbacks properly when the snap target indicates dismissing split.
DividerSnapAlgorithm.SnapTarget snapTarget = getSnapTarget(0 /* position */,
DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START);
+
mSplitLayout.snapToTarget(0 /* currentPosition */, snapTarget);
+ waitDividerFlingFinished();
verify(mSplitLayoutHandler).onSnappedToDismiss(eq(false));
- snapTarget = getSnapTarget(0 /* position */,
+ }
+
+ @Test
+ @UiThreadTest
+ public void testSnapToDismissEnd() {
+ // verify it callbacks properly when the snap target indicates dismissing split.
+ DividerSnapAlgorithm.SnapTarget snapTarget = getSnapTarget(0 /* position */,
DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_END);
+
mSplitLayout.snapToTarget(0 /* currentPosition */, snapTarget);
+ waitDividerFlingFinished();
verify(mSplitLayoutHandler).onSnappedToDismiss(eq(true));
}
+ private void waitDividerFlingFinished() {
+ verify(mSplitLayout).flingDividePosition(anyInt(), anyInt(), mRunnableCaptor.capture());
+ mRunnableCaptor.getValue().run();
+ }
+
private static Configuration getConfiguration() {
final Configuration configuration = new Configuration();
configuration.unset();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index 21329c75ebb0..84565e529e9e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -20,12 +20,18 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FIRST_CUSTOM;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
+import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -49,6 +55,9 @@ import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.view.IDisplayWindowListener;
+import android.view.IWindowManager;
+import android.view.Surface;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.IRemoteTransition;
@@ -66,12 +75,15 @@ import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.wm.shell.TestShellExecutor;
+import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import java.util.ArrayList;
@@ -98,8 +110,7 @@ public class ShellTransitionTests {
@Test
public void testBasicTransitionFlow() {
- Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
- mMainExecutor, mAnimExecutor);
+ Transitions transitions = createTestTransitions();
transitions.replaceDefaultHandlerForTest(mDefaultHandler);
IBinder transitToken = new Binder();
@@ -118,8 +129,7 @@ public class ShellTransitionTests {
@Test
public void testNonDefaultHandler() {
- Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
- mMainExecutor, mAnimExecutor);
+ Transitions transitions = createTestTransitions();
transitions.replaceDefaultHandlerForTest(mDefaultHandler);
final WindowContainerTransaction handlerWCT = new WindowContainerTransaction();
@@ -202,8 +212,7 @@ public class ShellTransitionTests {
@Test
public void testRequestRemoteTransition() {
- Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
- mMainExecutor, mAnimExecutor);
+ Transitions transitions = createTestTransitions();
transitions.replaceDefaultHandlerForTest(mDefaultHandler);
final boolean[] remoteCalled = new boolean[]{false};
@@ -297,8 +306,7 @@ public class ShellTransitionTests {
@Test
public void testRegisteredRemoteTransition() {
- Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
- mMainExecutor, mAnimExecutor);
+ Transitions transitions = createTestTransitions();
transitions.replaceDefaultHandlerForTest(mDefaultHandler);
final boolean[] remoteCalled = new boolean[]{false};
@@ -343,8 +351,7 @@ public class ShellTransitionTests {
@Test
public void testOneShotRemoteHandler() {
- Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
- mMainExecutor, mAnimExecutor);
+ Transitions transitions = createTestTransitions();
transitions.replaceDefaultHandlerForTest(mDefaultHandler);
final boolean[] remoteCalled = new boolean[]{false};
@@ -390,8 +397,7 @@ public class ShellTransitionTests {
@Test
public void testTransitionQueueing() {
- Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
- mMainExecutor, mAnimExecutor);
+ Transitions transitions = createTestTransitions();
transitions.replaceDefaultHandlerForTest(mDefaultHandler);
IBinder transitToken1 = new Binder();
@@ -431,8 +437,7 @@ public class ShellTransitionTests {
@Test
public void testTransitionMerging() {
- Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
- mMainExecutor, mAnimExecutor);
+ Transitions transitions = createTestTransitions();
mDefaultHandler.setSimulateMerge(true);
transitions.replaceDefaultHandlerForTest(mDefaultHandler);
@@ -468,6 +473,63 @@ public class ShellTransitionTests {
assertEquals(0, mDefaultHandler.activeCount());
}
+ @Test
+ public void testShouldRotateSeamlessly() throws Exception {
+ final RunningTaskInfo taskInfo =
+ createTaskInfo(1, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final RunningTaskInfo taskInfoPip =
+ createTaskInfo(1, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD);
+
+ final DisplayController displays = createTestDisplayController();
+ final @Surface.Rotation int upsideDown = displays
+ .getDisplayLayout(DEFAULT_DISPLAY).getUpsideDownRotation();
+
+ final TransitionInfo normalDispRotate = new TransitionInfoBuilder(TRANSIT_CHANGE)
+ .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY).setRotate()
+ .build())
+ .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfo).setRotate().build())
+ .build();
+ assertFalse(DefaultTransitionHandler.isRotationSeamless(normalDispRotate, displays));
+
+ // Seamless if all tasks are seamless
+ final TransitionInfo rotateSeamless = new TransitionInfoBuilder(TRANSIT_CHANGE)
+ .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY).setRotate()
+ .build())
+ .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfo)
+ .setRotate(ROTATION_ANIMATION_SEAMLESS).build())
+ .build();
+ assertTrue(DefaultTransitionHandler.isRotationSeamless(rotateSeamless, displays));
+
+ // Not seamless if there is PiP (or any other non-seamless task)
+ final TransitionInfo pipDispRotate = new TransitionInfoBuilder(TRANSIT_CHANGE)
+ .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY).setRotate()
+ .build())
+ .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfo)
+ .setRotate(ROTATION_ANIMATION_SEAMLESS).build())
+ .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfoPip)
+ .setRotate().build())
+ .build();
+ assertFalse(DefaultTransitionHandler.isRotationSeamless(pipDispRotate, displays));
+
+ // Not seamless if one of rotations is upside-down
+ final TransitionInfo seamlessUpsideDown = new TransitionInfoBuilder(TRANSIT_CHANGE)
+ .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(FLAG_IS_DISPLAY)
+ .setRotate(upsideDown, ROTATION_ANIMATION_UNSPECIFIED).build())
+ .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfo)
+ .setRotate(upsideDown, ROTATION_ANIMATION_SEAMLESS).build())
+ .build();
+ assertFalse(DefaultTransitionHandler.isRotationSeamless(seamlessUpsideDown, displays));
+
+ // Not seamless if system alert windows
+ final TransitionInfo seamlessButAlert = new TransitionInfoBuilder(TRANSIT_CHANGE)
+ .addChange(new ChangeBuilder(TRANSIT_CHANGE).setFlags(
+ FLAG_IS_DISPLAY | FLAG_DISPLAY_HAS_ALERT_WINDOWS).setRotate().build())
+ .addChange(new ChangeBuilder(TRANSIT_CHANGE).setTask(taskInfo)
+ .setRotate(ROTATION_ANIMATION_SEAMLESS).build())
+ .build();
+ assertFalse(DefaultTransitionHandler.isRotationSeamless(seamlessButAlert, displays));
+ }
+
class TransitionInfoBuilder {
final TransitionInfo mInfo;
@@ -490,11 +552,53 @@ public class ShellTransitionTests {
return addChange(mode, null /* taskInfo */);
}
+ TransitionInfoBuilder addChange(TransitionInfo.Change change) {
+ mInfo.addChange(change);
+ return this;
+ }
+
TransitionInfo build() {
return mInfo;
}
}
+ class ChangeBuilder {
+ final TransitionInfo.Change mChange;
+
+ ChangeBuilder(@WindowManager.TransitionType int mode) {
+ mChange = new TransitionInfo.Change(null /* token */, null /* leash */);
+ mChange.setMode(mode);
+ }
+
+ ChangeBuilder setFlags(@TransitionInfo.ChangeFlags int flags) {
+ mChange.setFlags(flags);
+ return this;
+ }
+
+ ChangeBuilder setTask(RunningTaskInfo taskInfo) {
+ mChange.setTaskInfo(taskInfo);
+ return this;
+ }
+
+ ChangeBuilder setRotate(int anim) {
+ return setRotate(Surface.ROTATION_90, anim);
+ }
+
+ ChangeBuilder setRotate() {
+ return setRotate(ROTATION_ANIMATION_UNSPECIFIED);
+ }
+
+ ChangeBuilder setRotate(@Surface.Rotation int target, int anim) {
+ mChange.setRotation(Surface.ROTATION_0, target);
+ mChange.setRotationAnimation(anim);
+ return this;
+ }
+
+ TransitionInfo.Change build() {
+ return mChange;
+ }
+ }
+
class TestTransitionHandler implements Transitions.TransitionHandler {
ArrayList<Transitions.TransitionFinishCallback> mFinishes = new ArrayList<>();
final ArrayList<IBinder> mMerged = new ArrayList<>();
@@ -566,4 +670,45 @@ public class ShellTransitionTests {
return taskInfo;
}
+ private DisplayController createTestDisplayController() {
+ IWindowManager mockWM = mock(IWindowManager.class);
+ final IDisplayWindowListener[] displayListener = new IDisplayWindowListener[1];
+ try {
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) {
+ displayListener[0] = invocation.getArgument(0);
+ return null;
+ }
+ }).when(mockWM).registerDisplayWindowListener(any());
+ } catch (RemoteException e) {
+ // No remote stuff happening, so this can't be hit
+ }
+ DisplayController out = new DisplayController(mContext, mockWM, mMainExecutor);
+ try {
+ displayListener[0].onDisplayAdded(DEFAULT_DISPLAY);
+ mMainExecutor.flushAll();
+ } catch (RemoteException e) {
+ // Again, no remote stuff
+ }
+ return out;
+ }
+
+ private Transitions createTestTransitions() {
+ return new Transitions(mOrganizer, mTransactionPool, createTestDisplayController(),
+ mContext, mMainExecutor, mAnimExecutor);
+ }
+//
+// private class TestDisplayController extends DisplayController {
+// private final DisplayLayout mTestDisplayLayout;
+// TestDisplayController() {
+// super(mContext, mock(IWindowManager.class), mMainExecutor);
+// mTestDisplayLayout = new DisplayLayout();
+// mTestDisplayLayout.
+// }
+//
+// @Override
+// DisplayLayout
+// }
+
}
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 025be7b2b6c1..2f3a509831d1 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -482,6 +482,12 @@ nsecs_t CanvasContext::draw() {
if (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw()) {
mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
+ if (auto grContext = getGrContext()) {
+ // Submit to ensure that any texture uploads complete and Skia can
+ // free its staging buffers.
+ grContext->flushAndSubmit();
+ }
+
// Notify the callbacks, even if there's nothing to draw so they aren't waiting
// indefinitely
waitOnFences();
diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java
index c827932194ae..cb887f2d523d 100644
--- a/media/java/android/media/AudioManagerInternal.java
+++ b/media/java/android/media/AudioManagerInternal.java
@@ -38,6 +38,17 @@ public abstract class AudioManagerInternal {
public abstract void updateRingerModeAffectedStreamsInternal();
+ /**
+ * Notify the UID of the currently active {@link android.service.voice.HotwordDetectionService}.
+ *
+ * <p>The caller is expected to take care of any performance implications, e.g. by using a
+ * background thread to call this method.</p>
+ *
+ * @param uid UID of the currently active service or {@link android.os.Process#INVALID_UID} if
+ * none.
+ */
+ public abstract void setHotwordDetectionServiceUid(int uid);
+
public abstract void setAccessibilityServiceUids(IntArray uids);
/**
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 8012f03d84b3..69d1889d5762 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1769,6 +1769,13 @@ public class AudioSystem
public static native int setAssistantUid(int uid);
/**
+ * Communicate UID of the current {@link android.service.voice.HotwordDetectionService} to audio
+ * policy service.
+ * @hide
+ */
+ public static native int setHotwordDetectionServiceUid(int uid);
+
+ /**
* @hide
* Communicate UIDs of active accessibility services to audio policy service.
*/
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index d746c850a018..37054b8383b1 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -1573,6 +1573,9 @@ public class ExifInterface {
if (isFdDuped) {
closeFileDescriptor(fileDescriptor);
}
+ if (modernFd != null) {
+ modernFd.close();
+ }
}
}
@@ -2554,12 +2557,13 @@ public class ExifInterface {
private void initForFilename(String filename) throws IOException {
FileInputStream in = null;
+ ParcelFileDescriptor modernFd = null;
mAssetInputStream = null;
mFilename = filename;
mIsInputStream = false;
try {
in = new FileInputStream(filename);
- ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(in.getFD());
+ modernFd = FileUtils.convertToModernFd(in.getFD());
if (modernFd != null) {
closeQuietly(in);
in = new FileInputStream(modernFd.getFileDescriptor());
@@ -2570,6 +2574,9 @@ public class ExifInterface {
loadAttributes(in);
} finally {
closeQuietly(in);
+ if (modernFd != null) {
+ modernFd.close();
+ }
}
}
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 2943eee5b1da..a15529e99d15 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -36,6 +36,7 @@ import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.SystemProperties;
import android.text.TextUtils;
+import android.util.Log;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -52,6 +53,8 @@ import java.util.Map;
* frame and meta data from an input media file.
*/
public class MediaMetadataRetriever implements AutoCloseable {
+ private static final String TAG = "MediaMetadataRetriever";
+
// borrowed from ExoPlayer
private static final String[] STANDARD_GENRES = new String[] {
// These are the official ID3v1 genres.
@@ -301,11 +304,15 @@ public class MediaMetadataRetriever implements AutoCloseable {
*/
public void setDataSource(FileDescriptor fd, long offset, long length)
throws IllegalArgumentException {
- ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(fd);
- if (modernFd == null) {
- _setDataSource(fd, offset, length);
- } else {
- _setDataSource(modernFd.getFileDescriptor(), offset, length);
+
+ try (ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(fd)) {
+ if (modernFd == null) {
+ _setDataSource(fd, offset, length);
+ } else {
+ _setDataSource(modernFd.getFileDescriptor(), offset, length);
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Ignoring IO error while setting data source", e);
}
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 4f761ba0bf6a..26eb2a9dc109 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1271,11 +1271,14 @@ public class MediaPlayer extends PlayerBase
*/
public void setDataSource(FileDescriptor fd, long offset, long length)
throws IOException, IllegalArgumentException, IllegalStateException {
- ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(fd);
- if (modernFd == null) {
- _setDataSource(fd, offset, length);
- } else {
- _setDataSource(modernFd.getFileDescriptor(), offset, length);
+ try (ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(fd)) {
+ if (modernFd == null) {
+ _setDataSource(fd, offset, length);
+ } else {
+ _setDataSource(modernFd.getFileDescriptor(), offset, length);
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Ignoring IO error while setting data source", e);
}
}
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 628f7eef84f9..7f7fb6023b07 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -292,8 +292,7 @@ public final class MediaRouter2Manager {
}
synchronized (mRoutesLock) {
for (MediaRoute2Info route : mRoutes.values()) {
- if (sessionInfo.getSelectedRoutes().contains(route.getId())
- || sessionInfo.getTransferableRoutes().contains(route.getId())) {
+ if (sessionInfo.getTransferableRoutes().contains(route.getId())) {
routes.add(route);
continue;
}
diff --git a/mms/OWNERS b/mms/OWNERS
index befc320b949c..7f05a2a24d6e 100644
--- a/mms/OWNERS
+++ b/mms/OWNERS
@@ -2,7 +2,6 @@ set noparent
tgunn@google.com
breadley@google.com
-hallliu@google.com
rgreenwalt@google.com
amitmahajan@google.com
fionaxu@google.com
@@ -10,7 +9,10 @@ jackyu@google.com
jminjie@google.com
satk@google.com
shuoq@google.com
-refuhoo@google.com
nazaninb@google.com
sarahchin@google.com
-dbright@google.com \ No newline at end of file
+xiaotonj@google.com
+huiwang@google.com
+jayachandranc@google.com
+chinmayd@google.com
+amruthr@google.com
diff --git a/packages/CarrierDefaultApp/OWNERS b/packages/CarrierDefaultApp/OWNERS
index 56688409bf78..0d23f053499c 100644
--- a/packages/CarrierDefaultApp/OWNERS
+++ b/packages/CarrierDefaultApp/OWNERS
@@ -1,7 +1,6 @@
set noparent
tgunn@google.com
breadley@google.com
-hallliu@google.com
rgreenwalt@google.com
amitmahajan@google.com
fionaxu@google.com
@@ -9,9 +8,11 @@ jackyu@google.com
jminjie@google.com
satk@google.com
shuoq@google.com
-refuhoo@google.com
nazaninb@google.com
sarahchin@google.com
-dbright@google.com
xiaotonj@google.com
+huiwang@google.com
+jayachandranc@google.com
+chinmayd@google.com
+amruthr@google.com
diff --git a/packages/PackageInstaller/res/values-te/strings.xml b/packages/PackageInstaller/res/values-te/strings.xml
index 8951e0def1cb..dba1ab4de61f 100644
--- a/packages/PackageInstaller/res/values-te/strings.xml
+++ b/packages/PackageInstaller/res/values-te/strings.xml
@@ -83,7 +83,7 @@
<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="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>
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
index 266fc78b2b6a..1f80a3e04093 100644
--- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
@@ -170,7 +170,14 @@ public class IllustrationPreference extends Preference {
}
/**
- * Sets image drawable to display image in {@link LottieAnimationView}
+ * Gets the lottie illustration resource id.
+ */
+ public int getLottieAnimationResId() {
+ return mImageResId;
+ }
+
+ /**
+ * Sets the image drawable to display image in {@link LottieAnimationView}.
*
* @param imageDrawable the drawable of an image
*/
@@ -183,7 +190,16 @@ public class IllustrationPreference extends Preference {
}
/**
- * Sets image uri to display image in {@link LottieAnimationView}
+ * Gets the image drawable from display image in {@link LottieAnimationView}.
+ *
+ * @return the drawable of an image
+ */
+ public Drawable getImageDrawable() {
+ return mImageDrawable;
+ }
+
+ /**
+ * Sets the image uri to display image in {@link LottieAnimationView}.
*
* @param imageUri the Uri of an image
*/
@@ -195,6 +211,15 @@ public class IllustrationPreference extends Preference {
}
}
+ /**
+ * Gets the image uri from display image in {@link LottieAnimationView}.
+ *
+ * @return the Uri of an image
+ */
+ public Uri getImageUri() {
+ return mImageUri;
+ }
+
private void resetImageResourceCache() {
mImageDrawable = null;
mImageUri = null;
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index b3bdf8977227..65992a7048b8 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -444,7 +444,7 @@
<string name="power_remaining_less_than_duration_only" msgid="8956656616031395152">"Carica residua: meno di <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration" msgid="318215464914990578">"Carica residua: meno di <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_more_than_subtext" msgid="446388082266121894">"Tempo residuo: più di <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="4873750633368888062">"Tempo residuo: più di <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
+ <string name="power_remaining_only_more_than_subtext" msgid="4873750633368888062">"Tempo rimanente: più di <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="137330009791560774">"Il telefono potrebbe spegnersi a breve"</string>
<string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="145489081521468132">"Il tablet potrebbe spegnersi a breve"</string>
<string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="1070562682853942350">"Il dispositivo potrebbe spegnersi a breve"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index b1aee5047fab..7387985cf457 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -309,7 +309,7 @@
<string name="dev_settings_warning_message" msgid="37741686486073668">"Бул орнотуулар өндүрүүчүлөр үчүн гана берилген. Булар түзмөгүңүздүн колдонмолорун бузулушуна же туура эмес иштешине алып келиши мүмкүн."</string>
<string name="verify_apps_over_usb_title" msgid="6031809675604442636">"Орнотулуучу колдонмону текшерүү"</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_show_devices_without_names_summary" msgid="780964354377854507">"Аталышсыз Bluetooth түзмөктөрү (MAC даректери менен гана) көрүнөт"</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>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index fea9601952e9..2bdd617e9e58 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -443,8 +443,8 @@
<string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"Bateria może się wyczerpać do <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration_only" msgid="8956656616031395152">"Pozostało mniej niż <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration" msgid="318215464914990578">"Pozostało mniej niż <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
- <string name="power_remaining_more_than_subtext" msgid="446388082266121894">"Pozostało mniej niż <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
- <string name="power_remaining_only_more_than_subtext" msgid="4873750633368888062">"Pozostało mniej niż <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
+ <string name="power_remaining_more_than_subtext" msgid="446388082266121894">"Pozostało ponad <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
+ <string name="power_remaining_only_more_than_subtext" msgid="4873750633368888062">"Pozostało ponad <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="137330009791560774">"Wkrótce telefon może się wyłączyć"</string>
<string name="power_remaining_duration_only_shutdown_imminent" product="tablet" msgid="145489081521468132">"Tablet może się wkrótce wyłączyć"</string>
<string name="power_remaining_duration_only_shutdown_imminent" product="device" msgid="1070562682853942350">"Urządzenie może się wkrótce wyłączyć"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index a87002679408..4f74d2492d43 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -489,7 +489,7 @@
<string name="active_input_method_subtypes" msgid="4232680535471633046">"సక్రియ ఇన్‌పుట్ పద్ధతులు"</string>
<string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"సిస్టమ్ భాషలను ఉపయోగించు"</string>
<string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> యొక్క సెట్టింగ్‌లను తెరవడం విఫలమైంది"</string>
- <string name="ime_security_warning" msgid="6547562217880551450">"ఈ ఇన్‌పుట్ పద్ధతి మీరు టైప్ చేసే మొత్తం వచనాన్ని అలాగే పాస్‌వర్డ్‌లు మరియు క్రెడిట్ కార్డు నంబర్‌ల వంటి వ్యక్తిగత డేటాను సేకరించగలదు. ఇది <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> అనువర్తనంలో అందించబడుతుంది. ఈ ఇన్‌పుట్ పద్ధతిని ఉపయోగించాలా?"</string>
+ <string name="ime_security_warning" msgid="6547562217880551450">"ఈ ఇన్‌పుట్ పద్ధతి మీరు టైప్ చేసే మొత్తం వచనాన్ని అలాగే పాస్‌వర్డ్‌లు మరియు క్రెడిట్ కార్డు నంబర్‌ల వంటి వ్యక్తిగత డేటాను సేకరించగలదు. ఇది <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> యాప్‌లో అందించబడుతుంది. ఈ ఇన్‌పుట్ పద్ధతిని ఉపయోగించాలా?"</string>
<string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"గమనిక: రీబూట్ చేసాక, మీరు మీ ఫోన్‌ను అన్‌లాక్ చేసే వరకు ఈ యాప్ ప్రారంభం కాదు"</string>
<string name="ims_reg_title" msgid="8197592958123671062">"IMS నమోదు స్థితి"</string>
<string name="ims_reg_status_registered" msgid="884916398194885457">"నమోదు చేయబడింది"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java
index 1472980efd4e..e0339dacf5ac 100644
--- a/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java
@@ -64,9 +64,9 @@ public class BiometricActionDisabledByAdminController extends BaseActionDisabled
return (dialog, which) -> {
Log.d(TAG, "Positive button clicked, component: " + enforcedAdmin.component);
final Intent intent = new Intent(ACTION_LEARN_MORE)
- .setComponent(enforcedAdmin.component)
.putExtra(EXTRA_SETTING_KEY, EXTRA_SETTING_VALUE)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .setPackage(enforcedAdmin.component.getPackageName());
context.startActivity(intent);
};
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 79446e430d4f..ed8d524b0132 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -44,6 +44,8 @@ import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.RequiresApi;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -56,6 +58,7 @@ import java.util.concurrent.Executors;
/**
* InfoMediaManager provide interface to get InfoMediaDevice list.
*/
+@RequiresApi(Build.VERSION_CODES.R)
public class InfoMediaManager extends MediaManager {
private static final String TAG = "InfoMediaManager";
@@ -145,9 +148,16 @@ public class InfoMediaManager extends MediaManager {
}
private RoutingSessionInfo getRoutingSessionInfo() {
+ return getRoutingSessionInfo(mPackageName);
+ }
+
+ private RoutingSessionInfo getRoutingSessionInfo(String packageName) {
final List<RoutingSessionInfo> sessionInfos =
- mRouterManager.getRoutingSessions(mPackageName);
+ mRouterManager.getRoutingSessions(packageName);
+ if (sessionInfos == null || sessionInfos.isEmpty()) {
+ return null;
+ }
return sessionInfos.get(sessionInfos.size() - 1);
}
@@ -367,33 +377,13 @@ public class InfoMediaManager extends MediaManager {
}
boolean shouldDisableMediaOutput(String packageName) {
- boolean shouldDisableMediaOutput = false;
if (TextUtils.isEmpty(packageName)) {
Log.w(TAG, "shouldDisableMediaOutput() package name is null or empty!");
- return false;
- }
- final List<MediaRoute2Info> infos = mRouterManager.getTransferableRoutes(packageName);
- if (infos.size() == 1) {
- final MediaRoute2Info info = infos.get(0);
- final int deviceType = info.getType();
- switch (deviceType) {
- case TYPE_UNKNOWN:
- case TYPE_REMOTE_TV:
- case TYPE_REMOTE_SPEAKER:
- case TYPE_GROUP:
- shouldDisableMediaOutput = true;
- break;
- default:
- shouldDisableMediaOutput = false;
- break;
- }
- }
- if (DEBUG) {
- Log.d(TAG, "shouldDisableMediaOutput() MediaRoute2Info size : " + infos.size()
- + ", package name : " + packageName + ", shouldDisableMediaOutput : "
- + shouldDisableMediaOutput);
+ return true;
}
- return shouldDisableMediaOutput;
+
+ // Disable when there is no transferable route
+ return mRouterManager.getTransferableRoutes(packageName).isEmpty();
}
@TargetApi(Build.VERSION_CODES.R)
@@ -456,7 +446,7 @@ public class InfoMediaManager extends MediaManager {
}
private void buildAvailableRoutes() {
- for (MediaRoute2Info route : mRouterManager.getTransferableRoutes(mPackageName)) {
+ for (MediaRoute2Info route : getAvailableRoutes(mPackageName)) {
if (DEBUG) {
Log.d(TAG, "buildAvailableRoutes() route : " + route.getName() + ", volume : "
+ route.getVolume() + ", type : " + route.getType());
@@ -465,6 +455,29 @@ public class InfoMediaManager extends MediaManager {
}
}
+ private List<MediaRoute2Info> getAvailableRoutes(String packageName) {
+ final List<MediaRoute2Info> infos = new ArrayList<>();
+ RoutingSessionInfo routingSessionInfo = getRoutingSessionInfo(packageName);
+ if (routingSessionInfo != null) {
+ infos.addAll(mRouterManager.getSelectedRoutes(routingSessionInfo));
+ }
+ final List<MediaRoute2Info> transferableRoutes =
+ mRouterManager.getTransferableRoutes(packageName);
+ for (MediaRoute2Info transferableRoute : transferableRoutes) {
+ boolean alreadyAdded = false;
+ for (MediaRoute2Info mediaRoute2Info : infos) {
+ if (TextUtils.equals(transferableRoute.getId(), mediaRoute2Info.getId())) {
+ alreadyAdded = true;
+ break;
+ }
+ }
+ if (!alreadyAdded) {
+ infos.add(transferableRoute);
+ }
+ }
+ return infos;
+ }
+
@VisibleForTesting
void addMediaDevice(MediaRoute2Info route) {
final int deviceType = route.getType();
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index a8da2c0ba269..22001c9c925a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -22,11 +22,13 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.media.RoutingSessionInfo;
+import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.bluetooth.A2dpProfile;
@@ -49,6 +51,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
/**
* LocalMediaManager provide interface to get MediaDevice list and transfer media to MediaDevice.
*/
+@RequiresApi(Build.VERSION_CODES.R)
public class LocalMediaManager implements BluetoothCallback {
private static final Comparator<MediaDevice> COMPARATOR = Comparator.naturalOrder();
private static final String TAG = "LocalMediaManager";
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 7a9f81e088cc..7aeacdc0cf71 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -34,7 +34,9 @@ import static android.provider.settings.validators.SettingsValidators.TILE_LIST_
import static android.provider.settings.validators.SettingsValidators.TTS_LIST_VALIDATOR;
import android.provider.Settings.Secure;
+import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
import java.util.Map;
@@ -287,5 +289,32 @@ public class SecureSettingsValidators {
VALIDATORS.put(Secure.CLIPBOARD_SHOW_ACCESS_NOTIFICATIONS, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.NOTIFICATION_BUBBLES, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.DEVICE_STATE_ROTATION_LOCK, value -> {
+ if (TextUtils.isEmpty(value)) {
+ return true;
+ }
+ String[] intValues = value.split(":");
+ if (intValues.length % 2 != 0) {
+ return false;
+ }
+ InclusiveIntegerRangeValidator enumValidator =
+ new InclusiveIntegerRangeValidator(
+ Secure.DEVICE_STATE_ROTATION_LOCK_IGNORED,
+ Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
+ ArraySet<String> keys = new ArraySet<>();
+ for (int i = 0; i < intValues.length - 1; ) {
+ String entryKey = intValues[i++];
+ String entryValue = intValues[i++];
+ if (!NON_NEGATIVE_INTEGER_VALIDATOR.validate(entryKey)
+ || !enumValidator.validate(entryValue)) {
+ return false;
+ }
+ // If the same device state key was specified more than once, this is invalid
+ if (!keys.add(entryKey)) {
+ return false;
+ }
+ }
+ return true;
+ });
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1e3ee22fee2f..db301f698753 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3585,7 +3585,7 @@ public class SettingsProvider extends ContentProvider {
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 203;
+ private static final int SETTINGS_VERSION = 204;
private final int mUserId;
@@ -5189,6 +5189,44 @@ public class SettingsProvider extends ContentProvider {
currentVersion = 203;
}
+ if (currentVersion == 203) {
+ // Version 204: Replace 'wifi' or 'cell' tiles with 'internet' if existed.
+ final SettingsState secureSettings = getSecureSettingsLocked(userId);
+ final Setting currentValue = secureSettings.getSettingLocked(Secure.QS_TILES);
+ if (!currentValue.isNull()) {
+ String tileList = currentValue.getValue();
+ String[] tileSplit = tileList.split(",");
+ final ArrayList<String> tiles = new ArrayList<String>();
+ boolean hasInternetTile = false;
+ for (int i = 0; i < tileSplit.length; i++) {
+ String tile = tileSplit[i].trim();
+ if (tile.isEmpty()) continue;
+ tiles.add(tile);
+ if (tile.equals("internet")) hasInternetTile = true;
+ }
+ if (!hasInternetTile) {
+ if (tiles.contains("wifi")) {
+ // Replace the WiFi with Internet, and remove the Cell
+ tiles.set(tiles.indexOf("wifi"), "internet");
+ tiles.remove("cell");
+ } else if (tiles.contains("cell")) {
+ // Replace the Cell with Internet
+ tiles.set(tiles.indexOf("cell"), "internet");
+ }
+ } else {
+ tiles.remove("wifi");
+ tiles.remove("cell");
+ }
+ secureSettings.insertSettingOverrideableByRestoreLocked(
+ Secure.QS_TILES,
+ TextUtils.join(",", tiles),
+ null /* tag */,
+ true /* makeDefault */,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+ currentVersion = 204;
+ }
+
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/Shell/res/values-te/strings.xml b/packages/Shell/res/values-te/strings.xml
index 989b53e7810d..fc49f079f82d 100644
--- a/packages/Shell/res/values-te/strings.xml
+++ b/packages/Shell/res/values-te/strings.xml
@@ -28,7 +28,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"స్క్రీన్‌షాట్ లేకుండా మీ బగ్ నివేదికను భాగస్వామ్యం చేయడానికి ఎంచుకోండి లేదా స్క్రీన్‌షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"స్క్రీన్‌షాట్ లేకుండా మీ బగ్ నివే. భాగ. చేయడానికి నొక్కండి లేదా స్క్రీన్‌షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"స్క్రీన్‌షాట్ లేకుండా మీ బగ్ నివే. భాగ. చేయడానికి నొక్కండి లేదా స్క్రీన్‌షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"బగ్ రిపోర్ట్స్‌లో మీరు గోప్యమైనదిగా పరిగణించే (యాప్ వినియోగం, లొకేష‌న్‌ డేటా వంటి) డేటాతో పాటు సిస్టమ్‌కు సంబంధించిన విభిన్న లాగ్ ఫైల్‌ల డేటా ఉంటుంది. బగ్ నివేదికలను మీరు విశ్వసించే యాప్‌లు, వ్యక్తులతో మాత్రమే షేర్ చేయండి."</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"బగ్ రిపోర్ట్స్‌లో మీరు గోప్యమైనదిగా పరిగణించే (యాప్ వినియోగం, లొకేష‌న్‌ డేటా వంటి) డేటాతో పాటు సిస్టమ్‌కు సంబంధించిన విభిన్న లాగ్ ఫైళ్ల డేటా ఉంటుంది. బగ్ నివేదికలను మీరు విశ్వసించే యాప్‌లు, వ్యక్తులతో మాత్రమే షేర్ చేయండి."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"మళ్లీ చూపవద్దు"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"బగ్ రిపోర్ట్స్"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"బగ్ నివేదిక ఫైల్‌ను చదవడం సాధ్యపడలేదు"</string>
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/flags/Flag.kt b/packages/SystemUI/plugin/src/com/android/systemui/flags/Flag.kt
new file mode 100644
index 000000000000..68834bc2aa23
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/flags/Flag.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.flags
+
+interface Flag<T> {
+ val id: Int
+ val default: T
+}
+
+data class BooleanFlag @JvmOverloads constructor(
+ override val id: Int,
+ override val default: Boolean = false
+) : Flag<Boolean>
+
+data class StringFlag @JvmOverloads constructor(
+ override val id: Int,
+ override val default: String = ""
+) : Flag<String>
+
+data class IntFlag @JvmOverloads constructor(
+ override val id: Int,
+ override val default: Int = 0
+) : Flag<Int>
+
+data class LongFlag @JvmOverloads constructor(
+ override val id: Int,
+ override val default: Long = 0
+) : Flag<Long>
+
+data class FloatFlag @JvmOverloads constructor(
+ override val id: Int,
+ override val default: Float = 0f
+) : Flag<Float>
+
+data class DoubleFlag @JvmOverloads constructor(
+ override val id: Int,
+ override val default: Double = 0.0
+) : Flag<Double> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/Extensions.kt b/packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java
index 0037059e2c51..d5b9243ebe86 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/Extensions.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java
@@ -14,16 +14,10 @@
* limitations under the License.
*/
-package com.android.wm.shell.flicker.pip
-
-import android.content.ComponentName
-import com.android.server.wm.traces.common.windowmanager.WindowManagerState
-import com.android.server.wm.traces.parser.toWindowName
+package com.android.systemui.flags;
/**
- * Checks that an activity [activity] is in PIP mode
+ * List of {@link Flag} objects for use in SystemUI.
*/
-fun WindowManagerState.isInPipMode(activity: ComponentName): Boolean {
- val windowName = activity.toWindowName()
- return isInPipMode(windowName)
+public class Flags {
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FlagReaderPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FlagReaderPlugin.java
new file mode 100644
index 000000000000..ab1749978653
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FlagReaderPlugin.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.plugins;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+
+/**
+ * Plugin for loading flag values from an alternate source of truth.
+ */
+@ProvidesInterface(action = FlagReaderPlugin.ACTION, version = FlagReaderPlugin.VERSION)
+public interface FlagReaderPlugin extends Plugin {
+ int VERSION = 1;
+ String ACTION = "com.android.systemui.flags.FLAG_READER_PLUGIN";
+
+ /** Returns a boolean value for the given flag. */
+ default boolean isEnabled(int id, boolean def) {
+ return def;
+ }
+
+ /** Returns a string value for the given flag id. */
+ default String getValue(int id, String def) {
+ return def;
+ }
+
+ /** Returns a int value for the given flag. */
+ default int getValue(int id, int def) {
+ return def;
+ }
+
+ /** Returns a long value for the given flag. */
+ default long getValue(int id, long def) {
+ return def;
+ }
+
+ /** Returns a float value for the given flag. */
+ default float getValue(int id, float def) {
+ return def;
+ }
+
+ /** Returns a double value for the given flag. */
+ default double getValue(int id, double def) {
+ return def;
+ }
+
+ /** Add a listener to be alerted when any flag changes. */
+ default void addListener(Listener listener) {}
+
+ /** Remove a listener to be alerted when any flag changes. */
+ default void removeListener(Listener listener) {}
+
+ /** A simple listener to be alerted when a flag changes. */
+ interface Listener {
+ /** */
+ void onFlagChanged(int id);
+ }
+}
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index 28c61663bd4d..6016aafbd6ae 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -68,6 +68,16 @@
lockScreenWeight="400"
/>
</FrameLayout>
+ <FrameLayout
+ android:id="@+id/keyguard_smartspace_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/below_clock_padding_start"
+ android:paddingEnd="@dimen/below_clock_padding_end"
+ android:layout_alignParentStart="true"
+ android:layout_below="@id/lockscreen_clock_view"
+ />
+ <!-- either keyguard_status_area or keyguard_smartspace_container is visible -->
<include layout="@layout/keyguard_status_area"
android:id="@+id/keyguard_status_area"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
index ce63082868bb..f613a195ea67 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
@@ -27,49 +27,44 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:clipChildren="false"
- android:clipToPadding="false"
androidprv:layout_maxWidth="@dimen/keyguard_security_width"
- androidprv:layout_maxHeight="@dimen/keyguard_security_height"
- android:gravity="center_horizontal">
+ android:clipChildren="false"
+ android:clipToPadding="false">
- <FrameLayout
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/pattern_container"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:clipChildren="false"
- android:clipToPadding="false">
-
- <LinearLayout
- android:id="@+id/pattern_container"
- android:layout_height="wrap_content"
+ android:layout_height="0dp"
+ android:layout_marginBottom="8dp"
+ android:layout_weight="1"
+ android:layoutDirection="ltr">
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/pattern_top_guideline"
android:layout_width="wrap_content"
- android:orientation="vertical"
- android:layout_gravity="center_horizontal|bottom"
- android:clipChildren="false"
- android:clipToPadding="false">
+ android:layout_height="wrap_content"
+ androidprv:layout_constraintGuide_percent="0"
+ android:orientation="horizontal" />
- <com.android.internal.widget.LockPatternView
- android:id="@+id/lockPatternView"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:layout_marginEnd="8dip"
- android:layout_marginBottom="4dip"
- android:layout_marginStart="8dip"
- android:layout_gravity="center_horizontal"
- android:gravity="center"
- android:clipChildren="false"
- android:clipToPadding="false" />
+ <com.android.internal.widget.LockPatternView
+ android:id="@+id/lockPatternView"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ androidprv:layout_constraintTop_toBottomOf="@id/pattern_top_guideline"
+ androidprv:layout_constraintBottom_toBottomOf="parent"
+ androidprv:layout_constraintLeft_toLeftOf="parent"
+ androidprv:layout_constraintRight_toRightOf="parent"
+ androidprv:layout_constraintDimensionRatio="1.0"
+ androidprv:layout_constraintVertical_bias="1.0"
+ />
+ </androidx.constraintlayout.widget.ConstraintLayout>
- <include layout="@layout/keyguard_eca"
- android:id="@+id/keyguard_selector_fade_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_gravity="bottom|center_horizontal"
- android:layout_marginTop="@dimen/keyguard_eca_top_margin"
- android:gravity="center_horizontal" />
- </LinearLayout>
- </FrameLayout>
+ <include layout="@layout/keyguard_eca"
+ android:id="@+id/keyguard_selector_fade_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_gravity="bottom|center_horizontal"
+ android:layout_marginTop="@dimen/keyguard_eca_top_margin"
+ android:gravity="center_horizontal" />
</com.android.keyguard.KeyguardPatternView>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
index a22a56fb3c61..7c54b90f1915 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -47,11 +47,11 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
- androidprv:layout_constraintBottom_toTopOf="@id/key1"
androidprv:layout_constraintEnd_toEndOf="parent"
androidprv:layout_constraintStart_toStartOf="parent"
androidprv:layout_constraintTop_toTopOf="parent"
+ androidprv:layout_constraintBottom_toTopOf="@id/key1"
androidprv:layout_constraintVertical_bias="1.0">
<com.android.keyguard.PasswordTextView
@@ -65,6 +65,15 @@
androidprv:scaledTextSize="@integer/scaled_password_text_size" />
</com.android.keyguard.AlphaOptimizedRelativeLayout>
+ <!-- Guideline used to place the top row of keys relative to the screen height. This will be
+ updated in KeyguardPINView to reduce the height of the PIN pad. -->
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/pin_pad_top_guideline"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ androidprv:layout_constraintGuide_percent="0"
+ android:orientation="horizontal" />
+
<androidx.constraintlayout.helper.widget.Flow
android:id="@+id/flow1"
android:layout_width="0dp"
@@ -78,16 +87,15 @@
androidprv:flow_horizontalStyle="packed"
androidprv:flow_maxElementsWrap="3"
+ androidprv:flow_verticalBias="1.0"
androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom"
androidprv:flow_verticalStyle="packed"
- androidprv:flow_verticalBias="1.0"
androidprv:flow_wrapMode="aligned"
-
- androidprv:layout_constraintTop_toTopOf="parent"
androidprv:layout_constraintBottom_toBottomOf="parent"
androidprv:layout_constraintEnd_toEndOf="parent"
- androidprv:layout_constraintStart_toStartOf="parent" />
+ androidprv:layout_constraintStart_toStartOf="parent"
+ androidprv:layout_constraintTop_toBottomOf="@id/pin_pad_top_guideline" />
<com.android.keyguard.NumPadKey
android:id="@+id/key1"
diff --git a/packages/SystemUI/res-keyguard/layout/qs_footer_actions.xml b/packages/SystemUI/res-keyguard/layout/qs_footer_actions.xml
new file mode 100644
index 000000000000..181ba078e948
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/qs_footer_actions.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+** Copyright 2021, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+-->
+<com.android.systemui.qs.QSFooterActionsView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/qs_footer_actions_container"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:gravity="center_vertical">
+
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
+ android:id="@android:id/edit"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/qs_footer_action_button_size"
+ android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
+ android:layout_weight="1"
+ android:background="@drawable/qs_footer_action_chip_background"
+ android:clickable="true"
+ android:clipToPadding="false"
+ android:contentDescription="@string/accessibility_quick_settings_edit"
+ android:focusable="true"
+ android:padding="@dimen/qs_footer_icon_padding"
+ android:src="@*android:drawable/ic_mode_edit"
+ android:tint="?android:attr/textColorPrimary" />
+
+ <com.android.systemui.statusbar.phone.MultiUserSwitch
+ android:id="@+id/multi_user_switch"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/qs_footer_action_button_size"
+ android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
+ android:layout_weight="1"
+ android:background="@drawable/qs_footer_action_chip_background"
+ android:focusable="true">
+
+ <ImageView
+ android:id="@+id/multi_user_avatar"
+ android:layout_width="@dimen/multi_user_avatar_expanded_size"
+ android:layout_height="@dimen/multi_user_avatar_expanded_size"
+ android:layout_gravity="center"
+ android:scaleType="centerInside" />
+ </com.android.systemui.statusbar.phone.MultiUserSwitch>
+
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
+ android:id="@+id/pm_lite"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/qs_footer_action_button_size"
+ android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
+ android:layout_weight="1"
+ android:background="@drawable/qs_footer_action_chip_background"
+ android:clickable="true"
+ android:clipToPadding="false"
+ android:focusable="true"
+ android:padding="@dimen/qs_footer_icon_padding"
+ android:src="@*android:drawable/ic_lock_power_off"
+ android:contentDescription="@string/accessibility_quick_settings_power_menu"
+ android:tint="?android:attr/textColorPrimary" />
+
+ <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
+ android:id="@+id/settings_button_container"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/qs_footer_action_button_size"
+ android:background="@drawable/qs_footer_action_chip_background"
+ android:layout_weight="1"
+ android:clipChildren="false"
+ android:clipToPadding="false">
+
+ <com.android.systemui.statusbar.phone.SettingsButton
+ android:id="@+id/settings_button"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/qs_footer_action_button_size"
+ android:layout_gravity="center"
+ android:contentDescription="@string/accessibility_quick_settings_settings"
+ android:background="@drawable/qs_footer_action_chip_background_borderless"
+ android:padding="@dimen/qs_footer_icon_padding"
+ android:scaleType="centerInside"
+ android:src="@drawable/ic_settings"
+ android:tint="?android:attr/textColorPrimary" />
+
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
+ android:id="@+id/tuner_icon"
+ android:layout_width="8dp"
+ android:layout_height="8dp"
+ android:layout_gravity="center_horizontal|bottom"
+ android:layout_marginBottom="@dimen/qs_footer_icon_padding"
+ android:src="@drawable/tuner"
+ android:tint="?android:attr/textColorTertiary"
+ android:visibility="invisible" />
+
+ </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
+
+</com.android.systemui.qs.QSFooterActionsView> \ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 7e3c87b24f07..a2ae5023166f 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -98,4 +98,10 @@
<dimen name="below_clock_padding_start">32dp</dimen>
<dimen name="below_clock_padding_end">16dp</dimen>
<dimen name="below_clock_padding_start_icons">28dp</dimen>
+
+ <!-- Proportion of the screen height to use to set the maximum height of the bouncer to when
+ the device is in the DEVICE_POSTURE_HALF_OPENED posture, for the PIN/pattern entry. 0 will
+ allow it to use the whole screen space, 0.6 will allow it to use just under half of the
+ screen. -->
+ <item name="half_opened_bouncer_height_ratio" type="dimen" format="float">0.0</item>
</resources>
diff --git a/packages/SystemUI/res/anim/fp_to_unlock.xml b/packages/SystemUI/res/anim/fp_to_unlock.xml
index a348208f48c7..a5f75b6726c8 100644
--- a/packages/SystemUI/res/anim/fp_to_unlock.xml
+++ b/packages/SystemUI/res/anim/fp_to_unlock.xml
@@ -19,10 +19,10 @@
<group android:name="_R_G">
<group android:name="_R_G_L_1_G_N_7_T_0" android:translateX="-27" android:translateY="-17.5">
<group android:name="_R_G_L_1_G" android:translateX="30.75" android:translateY="25.75">
- <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M27.52 38.98 C26.49,39.95 25.29,40.73 23.98,41.29 C23.17,41.65 22.31,41.91 21.41,42.07 C20.74,42.19 20.05,42.25 19.34,42.25 C18.44,42.25 17.56,42.15 16.72,41.96 C15.93,41.77 15.16,41.51 14.43,41.18 C13.23,40.63 12.13,39.88 11.16,38.98 " />
- <path android:name="_R_G_L_1_G_D_1_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M8.64 34.07 C7.89,31.97 7.89,29.85 7.89,29.85 C7.89,24.05 12.81,19.34 19.34,19.34 C25.87,19.34 30.8,24.05 30.8,29.85 C30.8,29.85 30.8,30.16 30.8,30.16 C30.8,32.32 29.04,34.07 26.89,34.07 C25.28,34.07 23.86,33.1 23.27,31.61 C23.27,31.61 21.96,28.34 21.96,28.34 C21.37,26.85 19.93,25.89 18.34,25.89 C16.18,25.89 14.43,27.64 14.43,29.8 C14.43,31.42 14.87,32.99 15.68,34.36 C16.22,35.26 16.93,36.08 17.77,36.75 C17.77,36.75 18.52,37.34 18.52,37.34 " />
- <path android:name="_R_G_L_1_G_D_2_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M6.25 19.34 C7.48,17.3 9.46,15.58 11.9,14.42 C12.93,13.94 14.03,13.55 15.2,13.27 C16.51,12.96 17.9,12.8 19.34,12.8 C20.77,12.8 22.14,12.96 23.45,13.26 C24.9,13.6 26.26,14.12 27.48,14.78 C29.6,15.92 31.32,17.5 32.43,19.34 " />
- <path android:name="_R_G_L_1_G_D_3_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M9.52 8.7 C10.98,7.91 12.58,7.28 14.28,6.86 C15.89,6.46 17.58,6.25 19.34,6.25 C21.06,6.25 22.72,6.45 24.3,6.83 C26.04,7.25 27.67,7.89 29.16,8.7 " />
+ <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M27.52 38.98 C26.49,39.95 25.29,40.73 23.98,41.29 C23.17,41.65 22.31,41.91 21.41,42.07 C20.74,42.19 20.05,42.25 19.34,42.25 C18.44,42.25 17.56,42.15 16.72,41.96 C15.93,41.77 15.16,41.51 14.43,41.18 C13.23,40.63 12.13,39.88 11.16,38.98 " />
+ <path android:name="_R_G_L_1_G_D_1_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M8.64 34.07 C7.89,31.97 7.89,29.85 7.89,29.85 C7.89,24.05 12.81,19.34 19.34,19.34 C25.87,19.34 30.8,24.05 30.8,29.85 C30.8,29.85 30.8,30.16 30.8,30.16 C30.8,32.32 29.04,34.07 26.89,34.07 C25.28,34.07 23.86,33.1 23.27,31.61 C23.27,31.61 21.96,28.34 21.96,28.34 C21.37,26.85 19.93,25.89 18.34,25.89 C16.18,25.89 14.43,27.64 14.43,29.8 C14.43,31.42 14.87,32.99 15.68,34.36 C16.22,35.26 16.93,36.08 17.77,36.75 C17.77,36.75 18.52,37.34 18.52,37.34 " />
+ <path android:name="_R_G_L_1_G_D_2_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M6.25 19.34 C7.48,17.3 9.46,15.58 11.9,14.42 C12.93,13.94 14.03,13.55 15.2,13.27 C16.51,12.96 17.9,12.8 19.34,12.8 C20.77,12.8 22.14,12.96 23.45,13.26 C24.9,13.6 26.26,14.12 27.48,14.78 C29.6,15.92 31.32,17.5 32.43,19.34 " />
+ <path android:name="_R_G_L_1_G_D_3_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M9.52 8.7 C10.98,7.91 12.58,7.28 14.28,6.86 C15.89,6.46 17.58,6.25 19.34,6.25 C21.06,6.25 22.72,6.45 24.3,6.83 C26.04,7.25 27.67,7.89 29.16,8.7 " />
</group>
</group>
<group android:name="_R_G_L_0_G_N_7_T_0" android:translateX="-27" android:translateY="-17.5">
diff --git a/packages/SystemUI/res/anim/lock_to_unlock.xml b/packages/SystemUI/res/anim/lock_to_unlock.xml
index ec51c0171709..76f7a05866d9 100644
--- a/packages/SystemUI/res/anim/lock_to_unlock.xml
+++ b/packages/SystemUI/res/anim/lock_to_unlock.xml
@@ -21,7 +21,7 @@
<group android:name="_R_G_L_2_G_N_10_T_1" android:translateX="50.25" android:translateY="61">
<group android:name="_R_G_L_2_G_N_10_T_0" android:translateX="-13.75" android:translateY="-7.5">
<group android:name="_R_G_L_2_G" android:translateX="-0.375" android:translateY="-22.375">
- <path android:name="_R_G_L_2_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M4.75 15 C4.75,15 23.25,15 23.25,15 C24.35,15 25.25,15.9 25.25,17 C25.25,17 25.25,33 25.25,33 C25.25,34.1 24.35,35 23.25,35 C23.25,35 4.75,35 4.75,35 C3.65,35 2.75,34.1 2.75,33 C2.75,33 2.75,17 2.75,17 C2.75,15.9 3.65,15 4.75,15c " />
+ <path android:name="_R_G_L_2_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M4.75 15 C4.75,15 23.25,15 23.25,15 C24.35,15 25.25,15.9 25.25,17 C25.25,17 25.25,33 25.25,33 C25.25,34.1 24.35,35 23.25,35 C23.25,35 4.75,35 4.75,35 C3.65,35 2.75,34.1 2.75,33 C2.75,33 2.75,17 2.75,17 C2.75,15.9 3.65,15 4.75,15c " />
</group>
</group>
</group>
@@ -30,7 +30,7 @@
<group android:name="_R_G_L_1_G_N_10_T_1" android:translateX="50.25" android:translateY="61">
<group android:name="_R_G_L_1_G_N_10_T_0" android:translateX="-13.75" android:translateY="-7.5">
<group android:name="_R_G_L_1_G" android:translateX="5" android:translateY="-22.5">
- <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M2.5 15 C2.5,15 2.5,8.61 2.5,8.61 C2.5,5.24 5.3,2.5 8.75,2.5 C12.2,2.5 15,5.24 15,8.61 C15,8.61 15,15 15,15 " />
+ <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M2.5 15 C2.5,15 2.5,8.61 2.5,8.61 C2.5,5.24 5.3,2.5 8.75,2.5 C12.2,2.5 15,5.24 15,8.61 C15,8.61 15,15 15,15 " />
</group>
</group>
</group>
diff --git a/packages/SystemUI/res/drawable/ic_unlock.xml b/packages/SystemUI/res/drawable/ic_unlock.xml
index c3b34699e8e2..46023e6160f5 100644
--- a/packages/SystemUI/res/drawable/ic_unlock.xml
+++ b/packages/SystemUI/res/drawable/ic_unlock.xml
@@ -21,7 +21,7 @@
android:strokeColor="#FF000000"
android:strokeLineCap="round"
android:strokeLineJoin="round"
- android:strokeWidth="2.5"
+ android:strokeWidth="2"
android:pathData="M4.75 15 C4.75,15 23.25,15 23.25,15 C24.35,15 25.25,15.9 25.25,17 C25.25,17 25.25,33 25.25,33 C25.25,34.1 24.35,35 23.25,35 C23.25,35 4.75,35 4.75,35 C3.65,35 2.75,34.1 2.75,33 C2.75,33 2.75,17 2.75,17 C2.75,15.9 3.65,15 4.75,15c " />
</group>
<group android:translateX="14" android:translateY="13.5">
@@ -29,7 +29,7 @@
android:strokeColor="#FF000000"
android:strokeLineCap="round"
android:strokeLineJoin="round"
- android:strokeWidth="2.5"
+ android:strokeWidth="2"
android:pathData="M27.19 14.81 C27.19,14.81 27.19,8.3 27.19,8.3 C27.19,4.92 24.44,2.88 21.19,2.75 C17.74,2.62 15,4.74 15,8.11 C15,8.11 15,15 15,15 " />
</group>
<group android:translateX="20" android:translateY="35.75">
diff --git a/packages/SystemUI/res/layout/keyguard_status_bar.xml b/packages/SystemUI/res/layout/keyguard_status_bar.xml
index 2789ed125b09..eb7638233efd 100644
--- a/packages/SystemUI/res/layout/keyguard_status_bar.xml
+++ b/packages/SystemUI/res/layout/keyguard_status_bar.xml
@@ -30,6 +30,7 @@
android:id="@+id/status_icon_area"
android:layout_width="wrap_content"
android:layout_height="match_parent"
+ android:paddingEnd="@dimen/system_icons_keyguard_padding_end"
android:paddingTop="@dimen/status_bar_padding_top"
android:layout_alignParentEnd="true"
android:gravity="center_vertical|end" >
@@ -38,12 +39,10 @@
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginStart="@dimen/system_icons_super_container_margin_start"
- android:gravity="center_vertical|end"
- android:paddingEnd="@dimen/system_icons_keyguard_padding_end" >
+ android:gravity="center_vertical|end">
<include layout="@layout/system_icons" />
</FrameLayout>
-
<ImageView android:id="@+id/multi_user_avatar"
android:layout_width="@dimen/multi_user_avatar_keyguard_size"
android:layout_height="@dimen/multi_user_avatar_keyguard_size"
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 317dbc09eae6..fe0b14aaad8d 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -68,93 +68,8 @@
</LinearLayout>
- <LinearLayout
- android:id="@+id/qs_footer_actions_container"
- android:layout_width="match_parent"
- android:layout_height="48dp"
- android:gravity="center_vertical">
-
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:id="@android:id/edit"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_footer_action_button_size"
- android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
- android:layout_weight="1"
- android:background="@drawable/qs_footer_action_chip_background"
- android:clickable="true"
- android:clipToPadding="false"
- android:contentDescription="@string/accessibility_quick_settings_edit"
- android:focusable="true"
- android:padding="@dimen/qs_footer_icon_padding"
- android:src="@*android:drawable/ic_mode_edit"
- android:tint="?android:attr/textColorPrimary" />
-
- <com.android.systemui.statusbar.phone.MultiUserSwitch
- android:id="@+id/multi_user_switch"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_footer_action_button_size"
- android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
- android:layout_weight="1"
- android:background="@drawable/qs_footer_action_chip_background"
- android:focusable="true">
-
- <ImageView
- android:id="@+id/multi_user_avatar"
- android:layout_width="@dimen/multi_user_avatar_expanded_size"
- android:layout_height="@dimen/multi_user_avatar_expanded_size"
- android:layout_gravity="center"
- android:scaleType="centerInside" />
- </com.android.systemui.statusbar.phone.MultiUserSwitch>
+ <include layout="@layout/qs_footer_actions"/>
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:id="@+id/pm_lite"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_footer_action_button_size"
- android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
- android:layout_weight="1"
- android:background="@drawable/qs_footer_action_chip_background"
- android:clickable="true"
- android:clipToPadding="false"
- android:focusable="true"
- android:padding="@dimen/qs_footer_icon_padding"
- android:src="@*android:drawable/ic_lock_power_off"
- android:contentDescription="@string/accessibility_quick_settings_power_menu"
- android:tint="?android:attr/textColorPrimary" />
-
- <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
- android:id="@+id/settings_button_container"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_footer_action_button_size"
- android:background="@drawable/qs_footer_action_chip_background"
- android:layout_weight="1"
- android:clipChildren="false"
- android:clipToPadding="false">
-
- <com.android.systemui.statusbar.phone.SettingsButton
- android:id="@+id/settings_button"
- android:layout_width="match_parent"
- android:layout_height="@dimen/qs_footer_action_button_size"
- android:layout_gravity="center"
- android:contentDescription="@string/accessibility_quick_settings_settings"
- android:background="@drawable/qs_footer_action_chip_background_borderless"
- android:padding="@dimen/qs_footer_icon_padding"
- android:scaleType="centerInside"
- android:src="@drawable/ic_settings"
- android:tint="?android:attr/textColorPrimary" />
-
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:id="@+id/tuner_icon"
- android:layout_width="8dp"
- android:layout_height="8dp"
- android:layout_gravity="center_horizontal|bottom"
- android:layout_marginBottom="@dimen/qs_footer_icon_padding"
- android:src="@drawable/tuner"
- android:tint="?android:attr/textColorTertiary"
- android:visibility="invisible" />
-
- </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
-
- </LinearLayout>
</LinearLayout>
</com.android.systemui.qs.QSFooterView>
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index 74c39a335f4d..5cac39f723e1 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -76,7 +76,7 @@
android:layout_height="match_parent"
android:paddingEnd="@dimen/signal_cluster_battery_padding" />
- <com.android.systemui.BatteryMeterView
+ <com.android.systemui.battery.BatteryMeterView
android:id="@+id/batteryRemainingIcon"
android:layout_height="match_parent"
android:layout_width="0dp"
diff --git a/packages/SystemUI/res/layout/split_shade_header.xml b/packages/SystemUI/res/layout/split_shade_header.xml
index 401dc1955dbd..f2c5b7bd491c 100644
--- a/packages/SystemUI/res/layout/split_shade_header.xml
+++ b/packages/SystemUI/res/layout/split_shade_header.xml
@@ -78,7 +78,7 @@
android:layout_height="match_parent"
android:paddingEnd="@dimen/signal_cluster_battery_padding" />
- <com.android.systemui.BatteryMeterView
+ <com.android.systemui.battery.BatteryMeterView
android:id="@+id/batteryRemainingIcon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 6f7358cd9ffe..b6921c682b1b 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -68,7 +68,7 @@
android:id="@+id/lock_icon"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:padding="48px"
+ android:padding="@dimen/lock_icon_padding"
android:layout_gravity="center"
android:scaleType="centerCrop"/>
</com.android.keyguard.LockIconView>
@@ -87,6 +87,18 @@
layout="@layout/keyguard_status_view"
android:visibility="gone"/>
+ <FrameLayout
+ android:id="@+id/split_shade_smartspace_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/notification_side_paddings"
+ android:paddingEnd="@dimen/notification_side_paddings"
+ systemui:layout_constraintStart_toStartOf="@id/qs_edge_guideline"
+ systemui:layout_constraintEnd_toEndOf="parent"
+ systemui:layout_constraintTop_toTopOf="parent"
+ android:visibility="gone">
+ </FrameLayout>
+
<include layout="@layout/dock_info_overlay" />
<FrameLayout
diff --git a/packages/SystemUI/res/layout/system_icons.xml b/packages/SystemUI/res/layout/system_icons.xml
index 818d1d77177b..6d5c7d40a5f8 100644
--- a/packages/SystemUI/res/layout/system_icons.xml
+++ b/packages/SystemUI/res/layout/system_icons.xml
@@ -29,7 +29,7 @@
android:gravity="center_vertical"
android:orientation="horizontal"/>
- <com.android.systemui.BatteryMeterView android:id="@+id/battery"
+ <com.android.systemui.battery.BatteryMeterView android:id="@+id/battery"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:clipToPadding="false"
diff --git a/packages/SystemUI/res/layout/udfps_keyguard_view.xml b/packages/SystemUI/res/layout/udfps_keyguard_view.xml
index 1851790673e3..a9eb27ad3b02 100644
--- a/packages/SystemUI/res/layout/udfps_keyguard_view.xml
+++ b/packages/SystemUI/res/layout/udfps_keyguard_view.xml
@@ -34,7 +34,7 @@
android:id="@+id/udfps_aod_fp"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:padding="48px"
+ android:padding="@dimen/lock_icon_padding"
android:layout_gravity="center"
android:scaleType="centerCrop"
app:lottie_autoPlay="false"
@@ -46,7 +46,7 @@
android:id="@+id/udfps_lockscreen_fp"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:padding="48px"
+ android:padding="@dimen/lock_icon_padding"
android:layout_gravity="center"
android:scaleType="centerCrop"
app:lottie_autoPlay="false"
diff --git a/packages/SystemUI/res/raw/udfps_aod_fp.json b/packages/SystemUI/res/raw/udfps_aod_fp.json
index 3247fe74fcfe..3b273ff92814 100644
--- a/packages/SystemUI/res/raw/udfps_aod_fp.json
+++ b/packages/SystemUI/res/raw/udfps_aod_fp.json
@@ -164,7 +164,7 @@
},
"w":{
"a":0,
- "k":1,
+ "k":1.3,
"ix":5
},
"lc":2,
@@ -526,7 +526,7 @@
},
"w":{
"a":0,
- "k":1,
+ "k":1.3,
"ix":5
},
"lc":2,
@@ -829,7 +829,7 @@
},
"w":{
"a":0,
- "k":1,
+ "k":1.3,
"ix":5
},
"lc":2,
@@ -1132,7 +1132,7 @@
},
"w":{
"a":0,
- "k":1,
+ "k":1.3,
"ix":5
},
"lc":2,
@@ -1507,7 +1507,7 @@
},
"w":{
"a":0,
- "k":1,
+ "k":1.3,
"ix":5
},
"lc":2,
@@ -1882,7 +1882,7 @@
},
"w":{
"a":0,
- "k":1,
+ "k":1.3,
"ix":5
},
"lc":2,
@@ -2257,7 +2257,7 @@
},
"w":{
"a":0,
- "k":1,
+ "k":1.3,
"ix":5
},
"lc":2,
@@ -2560,7 +2560,7 @@
},
"w":{
"a":0,
- "k":1,
+ "k":1.3,
"ix":5
},
"lc":2,
diff --git a/packages/SystemUI/res/raw/udfps_lockscreen_fp.json b/packages/SystemUI/res/raw/udfps_lockscreen_fp.json
index a25a47595fe7..a30a03a7e608 100644
--- a/packages/SystemUI/res/raw/udfps_lockscreen_fp.json
+++ b/packages/SystemUI/res/raw/udfps_lockscreen_fp.json
@@ -1 +1 @@
-{"v":"5.7.8","fr":60,"ip":0,"op":46,"w":46,"h":65,"nm":"fingerprint_build_on","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Fingerprint_20210701 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[23.091,32.5,0],"ix":2,"l":2},"a":{"a":0,"k":[19.341,24.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.701,0.42],[-1.757,0],[-1.577,-0.381],[-1.485,-0.816]],"o":[[1.455,-0.799],[1.608,-0.397],[1.719,0],[1.739,0.42],[0,0]],"v":[[-9.818,1.227],[-5.064,-0.618],[0,-1.227],[4.96,-0.643],[9.818,1.227]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2.5]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,7.477],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Top","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-2.446,1.161],[-1.168,0.275],[-1.439,0],[-1.301,-0.304],[-1.225,-0.66],[-1.11,-1.844]],"o":[[1.23,-2.044],[1.024,-0.486],[1.312,-0.31],[1.425,0],[1.454,0.34],[2.122,1.143],[0,0]],"v":[[-13.091,3.273],[-7.438,-1.646],[-4.14,-2.797],[0,-3.273],[4.104,-2.805],[8.141,-1.29],[13.091,3.273]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2.5]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,16.069],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Mid Top","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-6.53,0],[0,-5.793],[0,0],[2.159,0],[0.59,1.489],[0,0],[1.587,0],[0,-2.16],[-0.81,-1.363],[-0.844,-0.674],[0,0]],"o":[[-0.753,-2.095],[0,-5.793],[6.529,0],[0,0],[0,2.16],[-1.604,0],[0,0],[-0.589,-1.489],[-2.161,0],[0,1.62],[0.54,0.909],[0,0],[0,0]],"v":[[-10.702,5.728],[-11.454,1.506],[0.001,-9],[11.454,1.506],[11.454,1.817],[7.544,5.728],[3.926,3.273],[2.618,0],[-0.997,-2.454],[-4.91,1.457],[-3.657,6.014],[-1.57,8.412],[-0.818,9]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.949000000954,0.624000012875,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2.5]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,28.341],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Inside to dot ","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.307,-0.561],[0.894,-0.16],[0.706,0],[0.844,0.193],[0.728,0.334],[0.967,0.901]],"o":[[-1.038,0.967],[-0.817,0.351],[-0.673,0.12],[-0.9,0],[-0.794,-0.182],[-1.203,-0.551],[0,0]],"v":[[8.182,-1.636],[4.642,0.681],[2.07,1.453],[-0.001,1.636],[-2.621,1.341],[-4.909,0.563],[-8.182,-1.636]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2.5]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,40.614],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Bottom","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[{"tm":210,"cm":"2","dr":0},{"tm":255,"cm":"1","dr":0}]} \ No newline at end of file
+{"v":"5.7.8","fr":60,"ip":0,"op":46,"w":46,"h":65,"nm":"fingerprint_build_on","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Fingerprint_20210701 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[23.091,32.5,0],"ix":2,"l":2},"a":{"a":0,"k":[19.341,24.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.701,0.42],[-1.757,0],[-1.577,-0.381],[-1.485,-0.816]],"o":[[1.455,-0.799],[1.608,-0.397],[1.719,0],[1.739,0.42],[0,0]],"v":[[-9.818,1.227],[-5.064,-0.618],[0,-1.227],[4.96,-0.643],[9.818,1.227]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,7.477],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Top","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-2.446,1.161],[-1.168,0.275],[-1.439,0],[-1.301,-0.304],[-1.225,-0.66],[-1.11,-1.844]],"o":[[1.23,-2.044],[1.024,-0.486],[1.312,-0.31],[1.425,0],[1.454,0.34],[2.122,1.143],[0,0]],"v":[[-13.091,3.273],[-7.438,-1.646],[-4.14,-2.797],[0,-3.273],[4.104,-2.805],[8.141,-1.29],[13.091,3.273]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,16.069],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Mid Top","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-6.53,0],[0,-5.793],[0,0],[2.159,0],[0.59,1.489],[0,0],[1.587,0],[0,-2.16],[-0.81,-1.363],[-0.844,-0.674],[0,0]],"o":[[-0.753,-2.095],[0,-5.793],[6.529,0],[0,0],[0,2.16],[-1.604,0],[0,0],[-0.589,-1.489],[-2.161,0],[0,1.62],[0.54,0.909],[0,0],[0,0]],"v":[[-10.702,5.728],[-11.454,1.506],[0.001,-9],[11.454,1.506],[11.454,1.817],[7.544,5.728],[3.926,3.273],[2.618,0],[-0.997,-2.454],[-4.91,1.457],[-3.657,6.014],[-1.57,8.412],[-0.818,9]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.949000000954,0.624000012875,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,28.341],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Inside to dot ","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.307,-0.561],[0.894,-0.16],[0.706,0],[0.844,0.193],[0.728,0.334],[0.967,0.901]],"o":[[-1.038,0.967],[-0.817,0.351],[-0.673,0.12],[-0.9,0],[-0.794,-0.182],[-1.203,-0.551],[0,0]],"v":[[8.182,-1.636],[4.642,0.681],[2.07,1.453],[-0.001,1.636],[-2.621,1.341],[-4.909,0.563],[-8.182,-1.636]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,40.614],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Bottom","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[{"tm":210,"cm":"2","dr":0},{"tm":255,"cm":"1","dr":0}]} \ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 3506057bd5ac..8229661fbc24 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Kan nie gesig herken nie. Gebruik eerder vingerafdruk."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Gebruik jou vingerafdruk om voort te gaan"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Kan nie vingerafdruk herken nie. Gebruik eerder skermslot."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Soek tans vir jou …"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Gesig-ikoon"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Versoenbaarheid-zoem se knoppie."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Tik weer om oop te maak"</string>
<string name="tap_again" msgid="1315420114387908655">"Tik weer"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Swiep op om oop te maak"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Druk om oop te maak"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Swiep op om weer te probeer"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ontsluit om NFC te gebruik"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Hierdie toestel behoort aan jou organisasie"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 74009bf50bbc..7f101d73b925 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"መልክን መለየት አልተቻለም። በምትኩ የጣት አሻራ ይጠቀሙ።"</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"ለመቀጠል የእርስዎን የጣት አሻራ ይጠቀሙ"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"የጣት አሻራን መለየት አልተቻለም። በምትኩ የማያ ገጽ መቆለፊያ ይጠቀሙ።"</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"እርስዎን በመፈለግ ላይ…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"የፊት አዶ"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"የተኳኋኝአጉላ አዝራር።"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"ለመክፈት ዳግም መታ ያድርጉ"</string>
<string name="tap_again" msgid="1315420114387908655">"እንደገና መታ ያድርጉ"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"ለመክፈት በጣት ወደ ላይ ጠረግ ያድርጉ"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"ለመክፈት ይጫኑ"</string>
<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>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 993ee39ab808..8f230246a70e 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"يتعذّر التعرّف على الوجه. استخدِم بصمة الإصبع بدلاً من ذلك."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"عليك استخدام بصمة الإصبع للمتابعة."</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"يتعذّر التعرّف على بصمة الإصبع. عليك استخدام قفل الشاشة بدلاً من ذلك."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"جارٍ البحث عن وجهك…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"رمز الوجه"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"زر تكبير/تصغير للتوافق."</string>
@@ -460,6 +462,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"انقر مرة أخرى للفتح"</string>
<string name="tap_again" msgid="1315420114387908655">"انقر مرة أخرى"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"يمكنك الفتح بالتمرير سريعًا لأعلى."</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"اضغط لفتح الجهاز."</string>
<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>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 20023c0b36d0..c4438fca51e3 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"মুখাৱয়ব চিনিব নোৱাৰি। ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক।"</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"অব্যাহত ৰাখিবলৈ আপোনাৰ ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"ফিংগাৰপ্ৰিণ্ট চিনাক্ত কৰিব নোৱাৰি। তাৰ সলনি স্ক্ৰীন লক ব্যৱহাৰ কৰক।"</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"আপোনাৰ মুখমণ্ডল বিচাৰি আছে…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"মুখমণ্ডলৰ আইকন"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"উপযোগিতা অনুসৰি জুম কৰা বুটাম।"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"খুলিবলৈ পুনৰাই টিপক"</string>
<string name="tap_again" msgid="1315420114387908655">"পুনৰ টিপক"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"খুলিবলৈ ওপৰলৈ ছোৱাইপ কৰক"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"খুলিবলৈ টিপক"</string>
<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>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 71f90fd519aa..7e50b194000a 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tanımaq olmur. Barmaq izini işlədin."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Davam etmək üçün barmaq izinizi istifadə edin"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Barmaq izini tanımaq olmur. Əvəzində ekran kilidindən istifadə edin."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Siz axtarılırsınız…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Üz işarəsi"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Uyğunluq zoom düyməsi."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Açmaq üçün yenidən tıklayın"</string>
<string name="tap_again" msgid="1315420114387908655">"Yenidən toxunun"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Açmaq üçün yuxarı sürüşdürün"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Açmaq üçün basın"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Yenidən cəhd etmək üçün yuxarı sürüşdürün"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC istifadə etmək üçün kiliddən çıxarın"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Bu cihaz təşkilatınıza məxsusdur"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 7402594b3c59..701765f4036c 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Lice nije prepoznato. Koristite otisak prsta."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Nastavite pomoću otiska prsta"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Prepoznavanje otiska prsta nije uspelo. Koristite zaključavanje ekrana umesto toga."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Tražimo vas…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikona lica"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Dugme Zum kompatibilnosti."</string>
@@ -454,6 +456,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Dodirnite ponovo da biste otvorili"</string>
<string name="tap_again" msgid="1315420114387908655">"Dodirnite ponovo"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Prevucite nagore da biste otvorili"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pritisnite da biste otvorili"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Prevucite nagore da biste probali ponovo"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da biste koristili NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada organizaciji"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 7688e06dba25..5da6cf8b9c35 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Твар не распазнаны. Скарыстайце адбітак пальца."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Каб працягнуць, скарыстайце адбітак пальца"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Не ўдалося распазнаць адбітак пальца. Разблакіруйце экран іншым спосабам."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Ідзе пошук вашага твару…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Значок твару"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Кнопка сумяшчальнасці маштаба."</string>
@@ -456,6 +458,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Дакраніцеся яшчэ раз, каб адкрыць"</string>
<string name="tap_again" msgid="1315420114387908655">"Націсніце яшчэ раз"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Каб адкрыць, прагарніце ўверх"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Націсніце, каб адкрыць"</string>
<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>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 386fbd6a8520..742de25d539c 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Лицето не е разпознато. Използвайте отпечатък."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Използвайте отпечатъка си, за да продължите"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Отпечатъкът не може да бъде разпознат. Вместо това използвайте опция за заключване на екрана."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Търсим ви…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Икона на лице"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Бутон за промяна на мащаба с цел съвместимост."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Докоснете отново, за да отворите"</string>
<string name="tap_again" msgid="1315420114387908655">"Докоснете отново"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Прекарайте пръст нагоре, за да отключите"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Натиснете за отваряне"</string>
<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>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index d26912604bb5..b35ae1f1efde 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"মুখ শনাক্ত করতে পারছি না। পরিবর্তে আঙ্গুলের ছাপ ব্যবহার করুন।"</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"চালিয়ে যেতে আঙ্গুলের ছাপ ব্যবহার করুন"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"আঙ্গুলের ছাপ শনাক্ত করতে পারছি না। পরিবর্তে স্ক্রিন লক ব্যবহার করুন।"</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"আপনার জন্য খোঁজা হচ্ছে…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"ফেস আইকন"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"সামঞ্জস্যের জুম বোতাম৷"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"খোলার জন্য আবার আলতো চাপুন"</string>
<string name="tap_again" msgid="1315420114387908655">"আবার ট্যাপ করুন"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"খোলার জন্য উপরে সোয়াইপ করুন"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"আনলক করার জন্য প্রেস করুন"</string>
<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>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 2857eccd0633..b87739732e4b 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nije moguće prepoznati lice. Koristite otisak prsta."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Nastavite pomoću otiska prsta"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Nije moguće prepoznati otisak prsta. Umjesto toga koristite zaključavanje ekrana."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Tražimo vas…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikona lica"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Dugme za uvećavanje u slučaju nekompatibilnosti."</string>
@@ -454,6 +456,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Dodirnite ponovo da otvorite"</string>
<string name="tap_again" msgid="1315420114387908655">"Ponovo dodirnite"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Prevucite da otvorite"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pritisnite da otvorite"</string>
<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>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada vašoj organizaciji"</string>
@@ -992,7 +995,7 @@
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Nećete imati pristup podacima ni internetu putem mobilnog operatera <xliff:g id="CARRIER">%s</xliff:g>. Internet će biti dostupan samo putem WiFi mreže."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"vaš operater"</string>
<string name="touch_filtered_warning" msgid="8119511393338714836">"Postavke ne mogu potvrditi vaš odgovor jer aplikacija zaklanja zahtjev za odobrenje."</string>
- <string name="slice_permission_title" msgid="3262615140094151017">"Dozvoliti aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> prikazivanje isječaka aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
+ <string name="slice_permission_title" msgid="3262615140094151017">"Dozvoliti aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> da prikazuje isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Može čitati informacije iz aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="slice_permission_text_2" msgid="6758906940360746983">"- Može poduzeti radnje u aplikaciji <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="slice_permission_checkbox" msgid="4242888137592298523">"Dozvoli aplikaciji <xliff:g id="APP">%1$s</xliff:g> prikazivanje isječaka iz svake aplikacije"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index c25dca5c91e6..a5504f02833e 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No podem detectar la cara. Usa l\'empremta digital."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Fes servir l\'empremta digital per continuar"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"No es pot reconèixer l\'empremta digital. Utilitza el bloqueig de pantalla."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"S\'està cercant la teva cara…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Icona facial"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Botó de zoom de compatibilitat."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Torna a tocar per obrir-la."</string>
<string name="tap_again" msgid="1315420114387908655">"Torna a tocar"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Llisca cap amunt per obrir"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Prem per obrir"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Llisca cap a dalt per tornar-ho a provar"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueja per utilitzar l\'NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Aquest dispositiu pertany a la teva organització"</string>
@@ -576,7 +579,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"L\'administrador ha activat el registre de xarxa, que supervisa el trànsit del teu dispositiu.\n\nPer obtenir més informació, contacta amb l\'administrador."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Has donat permís a una aplicació per configurar una connexió VPN.\n\nAquesta aplicació pot supervisar el dispositiu i l\'activitat a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona el teu perfil de treball.\n\nL\'administrador pot supervisar la teva activitat a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web.\n\nPer obtenir més informació, contacta amb l\'administrador.\n\nA més, estàs connectat a una VPN, que també pot supervisar la teva activitat a la xarxa."</string>
- <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"El teu pare o la teva mare gestionen aquest dispositiu, i poden veure i gestionar informació com ara les aplicacions que utilitzes, la teva ubicació i el teu temps de connexió."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"El teu pare o mare gestionen aquest dispositiu, i poden veure i gestionar informació com ara les aplicacions que utilitzes, la teva ubicació i el teu temps de connexió."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat personal a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 5fed1b3e3f30..f48c9fb1cd77 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Obličej se nepodařilo rozpoznat. Použijte místo něj otisk prstu."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Pokračujte přiložením prstu"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Otisk prstu se nepodařilo rozpoznat. Použijte místo něj zámek obrazovky."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Hledáme vás…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikona obličeje"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Tlačítko úpravy velikosti z důvodu kompatibility"</string>
@@ -456,6 +458,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Oznámení otevřete opětovným klepnutím"</string>
<string name="tap_again" msgid="1315420114387908655">"Znovu klepněte"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Otevřete přejetím prstem nahoru"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Stisknutím otevřete"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Přejetím nahoru to zkusíte znovu"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC vyžaduje odemknutou obrazovku"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Toto zařízení patří vaší organizaci"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index facedf0ff039..cbef46488c5a 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansigtet kan ikke genkendes. Brug fingeraftryk i stedet."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Brug dit fingeraftryk for at fortsætte"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Fingeraftrykket kan ikke genkendes. Brug skærmlåsen i stedet."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Forsøger at finde dig…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ansigt"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Knap for kompatibilitetszoom."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Tryk igen for at åbne"</string>
<string name="tap_again" msgid="1315420114387908655">"Tryk igen"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Stryg opad for at åbne"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Tryk for at åbne"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Stryg opad for at prøve igen"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås op for at bruge NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Denne enhed tilhører din organisation"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 5d10eb4b25b9..50fcdfb7032a 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Gesicht wurde nicht erkannt. Verwende stattdessen den Fingerabdruck."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Mithilfe deines Fingerabdrucks fortfahren"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Fingerabdruck wurde nicht erkannt. Verwende stattdessen die Displaysperre."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Wir suchen nach dir…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Gesichtssymbol"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Schaltfläche für Kompatibilitätszoom"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Erneut tippen, um Benachrichtigung zu öffnen"</string>
<string name="tap_again" msgid="1315420114387908655">"Noch einmal tippen"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Zum Öffnen nach oben wischen"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Zum Öffnen klicken"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Zum Wiederholen nach oben wischen"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Zur Verwendung von NFC entsperren"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Dieses Gerät gehört deiner Organisation"</string>
@@ -1082,7 +1085,7 @@
<string name="controls_media_title" msgid="1746947284862928133">"Medien"</string>
<string name="controls_media_close_session" msgid="1193000643003066508">"Diese Mediensitzung ausblenden?"</string>
<string name="controls_media_active_session" msgid="3146882316024153337">"Die Mediensitzung kann nicht ausgeblendet werden."</string>
- <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ablehnen"</string>
+ <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ausblenden"</string>
<string name="controls_media_resume" msgid="1933520684481586053">"Fortsetzen"</string>
<string name="controls_media_settings_button" msgid="5815790345117172504">"Einstellungen"</string>
<string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> von <xliff:g id="ARTIST_NAME">%2$s</xliff:g> wird gerade über <xliff:g id="APP_LABEL">%3$s</xliff:g> wiedergegeben"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index cfda46f64eda..b8d357f3ff95 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Το πρόσωπο δεν αναγνωρίζεται. Χρησιμ. δακτ. αποτ."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Χρησιμοποιήστε δακτυλ. αποτύπωμα για να συνεχίσετε"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Δεν είναι δυνατή η αναγνώριση του δακτυλικού αποτυπώματος. Χρησιμοποιήστε εναλλακτικά το κλείδωμα οθόνης."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Αναζήτηση για εσάς…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Εικονίδιο προσώπου"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Κουμπί εστίασης συμβατότητας."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Πατήστε ξανά για να ανοίξετε"</string>
<string name="tap_again" msgid="1315420114387908655">"Πατήστε ξανά"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Σύρετε προς τα επάνω για άνοιγμα"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Πατήστε για άνοιγμα"</string>
<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>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 9af2d89ce21d..d69a95bba878 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Use your fingerprint to continue"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Can’t recognise fingerprint. Use screen lock instead."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Looking for you…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Face icon"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Compatibility zoom button."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Tap again to open"</string>
<string name="tap_again" msgid="1315420114387908655">"Tap again"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Swipe up to open"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Press to open"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Swipe up to try again"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 398420a68f5c..3666069ee54b 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Use your fingerprint to continue"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Can’t recognise fingerprint. Use screen lock instead."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Looking for you…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Face icon"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Compatibility zoom button."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Tap again to open"</string>
<string name="tap_again" msgid="1315420114387908655">"Tap again"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Swipe up to open"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Press to open"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Swipe up to try again"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 9af2d89ce21d..d69a95bba878 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Use your fingerprint to continue"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Can’t recognise fingerprint. Use screen lock instead."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Looking for you…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Face icon"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Compatibility zoom button."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Tap again to open"</string>
<string name="tap_again" msgid="1315420114387908655">"Tap again"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Swipe up to open"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Press to open"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Swipe up to try again"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 9af2d89ce21d..d69a95bba878 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Use your fingerprint to continue"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Can’t recognise fingerprint. Use screen lock instead."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Looking for you…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Face icon"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Compatibility zoom button."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Tap again to open"</string>
<string name="tap_again" msgid="1315420114387908655">"Tap again"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Swipe up to open"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Press to open"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Swipe up to try again"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Unlock to use NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"This device belongs to your organisation"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index b21102657db8..030c5884d3e3 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‏‏‎‏‎‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‎‏‎‎‎Can’t recognize face. Use fingerprint instead.‎‏‎‎‏‎"</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‎‏‏‏‏‎‏‎‏‎‎‏‎‏‎‎‎‏‎‎‏‎‎‏‏‏‎‏‎‏‏‏‎‏‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‏‎Use your fingerprint to continue‎‏‎‎‏‎"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‎‎‎‎‏‎‏‎‎‏‎‏‎‏‏‎‏‎‎‏‏‏‎‎‏‏‏‎‎‎‏‏‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‎‎‏‎Can’t recognize fingerprint. Use screen lock instead.‎‏‎‎‏‎"</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‏‎‏‎‏‎‏‏‎‏‎‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‎Looking for you…‎‏‎‎‏‎"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‎‎‎‏‏‎‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‏‏‏‏‏‎‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎Face icon‎‏‎‎‏‎"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‏‏‎‎‎‏‏‏‎‎‏‏‏‎‎‎‎‏‎‏‏‎‎‏‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎Compatibility zoom button.‎‏‎‎‏‎"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‎‎‏‎‏‎‏‎‎‎‎‏‎‎‏‎‎‏‏‎‎‎‏‏‎‎‎‎‎‎‎‏‏‎‎‏‎‏‏‏‎‎‎‏‎‎‏‎‎‎‎‏‎Tap again to open‎‏‎‎‏‎"</string>
<string name="tap_again" msgid="1315420114387908655">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‎‎‏‎‏‎‎‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‎‏‎‏‏‏‏‎Tap again‎‏‎‎‏‎"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‎‏‏‏‏‎‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‎‎‎‎‏‏‏‎‏‏‏‎‎‎‏‎‎‏‎‎‎‎‎‏‎Swipe up to open‎‏‎‎‏‎"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‏‏‎‎‏‎‏‎‏‏‎‏‏‏‎‏‏‏‎‏‏‏‏‎‏‏‏‏‎‎‏‎‏‎‏‏‎‏‏‏‏‏‎‏‎‏‎‎‎‏‎‎‎Press to open‎‏‎‎‏‎"</string>
<string name="keyguard_retry" msgid="886802522584053523">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‏‎‎‏‎‎‎‏‎‎‎‎‎‏‎‎‎‏‎‏‎‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎Swipe up to try again‎‏‎‎‏‎"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‏‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‎‎‎‏‎‏‎‎‏‏‏‏‎Unlock to use NFC‎‏‎‎‏‎"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‏‎‏‎‎‏‎‏‏‏‏‎‎‎‏‎‏‎‎‏‎‎‏‏‎‏‎‏‏‎‎‏‎‏‏‏‏‎‏‏‏‏‏‎This device belongs to your organization‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 4520ed33f784..bb43d81596be 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No se reconoce el rostro. Usa la huella dactilar."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Utiliza tu huella dactilar para continuar"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"No se reconoce la huella dactilar. Utiliza el bloqueo de pantalla en su lugar."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Autenticando tu rostro…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ícono de rostro"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Botón de zoom de compatibilidad"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Presiona de nuevo para abrir"</string>
<string name="tap_again" msgid="1315420114387908655">"Presiona otra vez"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Desliza el dedo hacia arriba para abrir"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Presiona para abrir"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Desliza el dedo hacia arriba para volver a intentarlo"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea el dispositivo para usar NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertenece a tu organización"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index c5096e9c1a35..820c708e4fe1 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No se reconoce la cara. Usa la huella digital."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Usa tu huella digital para continuar"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"No se reconoce la huella digital. Usa el bloqueo de pantalla."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Buscando tu cara…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Icono de cara"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Botón de zoom de compatibilidad"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Toca de nuevo para abrir"</string>
<string name="tap_again" msgid="1315420114387908655">"Toca de nuevo"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Desliza el dedo hacia arriba para abrir"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pulsa para abrirlo"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Desliza el dedo hacia arriba para volverlo a intentar"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea para usar el NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertenece a tu organización"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index ee7c76039408..6cd609fa6151 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nägu ei õnnestu tuvastada. Kasutage sõrmejälge."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Jätkamiseks kasutage sõrmejälge"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Sõrmejälge ei õnnestu tuvastada. Kasutage selle asemel ekraanilukku."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Otsitakse teid …"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Näoikoon"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Sobivussuumi nupp."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Avamiseks puudutage uuesti"</string>
<string name="tap_again" msgid="1315420114387908655">"Puudutage uuesti"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Pühkige avamiseks üles"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Avamiseks vajutage"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Uuesti proovimiseks pühkige üles"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC kasutamiseks avage."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"See seade kuulub teie organisatsioonile"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 0972c26b9ed1..4f4892cf8f00 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ez da hauteman aurpegia. Erabili hatz-marka."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Aurrera egiteko, erabili hatz-marka"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Ez da hauteman hatz-marka. Erabili pantailaren blokeoa."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Zure bila…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Aurpegiaren ikonoa"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Zoom-bateragarritasunaren botoia."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Irekitzeko, ukitu berriro"</string>
<string name="tap_again" msgid="1315420114387908655">"Sakatu berriro"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Pasatu hatza gora irekitzeko"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Sakatu irekitzeko"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Berriro saiatzeko, pasatu hatza gora"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desblokea ezazu NFC erabiltzeko"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Gailu hau zure erakundearena da"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 2899e173e11c..d1ddd8c042f4 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"چهره شناسایی نشد. درعوض از اثر انگشت استفاده کنید."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"برای ادامه، از اثر انگشتتان استفاده کنید"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"اثر انگشت شناسایی نشد. درعوض از قفل صفحه استفاده کنید."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"درحال جستجوی شما…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"نماد چهره"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"دکمه بزرگ‌نمایی سازگار."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"دوباره ضربه بزنید تا باز شود"</string>
<string name="tap_again" msgid="1315420114387908655">"دوباره ضربه بزنید"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"برای باز کردن، انگشتتان را تند به‌بالا بکشید"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"برای باز کردن فشار دهید"</string>
<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>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index dc49957d6773..652acf7ddd89 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Kasvoja ei voi tunnistaa. Käytä sormenjälkeä."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Jatka sormenjäljen avulla"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Sormenjälkeä ei voi tunnistaa. Käytä sen sijaan näytön lukitusta."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Etsitään kasvoja…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Kasvokuvake"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Yhteensopivuuszoomaus-painike."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Avaa napauttamalla uudelleen"</string>
<string name="tap_again" msgid="1315420114387908655">"Napauta uudelleen"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Avaa pyyhkäisemällä ylös"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Avaa painamalla"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Yritä uudelleen pyyhkäisemällä ylös"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Avaa lukitus, jotta voit käyttää NFC:tä"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Organisaatiosi omistaa tämän laitteen"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 83c0ef4da28d..1ec1f9190a22 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Visage non reconnu. Utilisez plutôt l\'empreinte digitale."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Utilisez votre empreinte digitale pour continuer"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Empreinte digitale non reconnue. Utilisez plutôt le verrouillage de l\'écran."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Recherche de votre visage…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Icône de visage"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Bouton \"Zoom de compatibilité\""</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Touchez à nouveau pour ouvrir"</string>
<string name="tap_again" msgid="1315420114387908655">"Toucher de nouveau"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Balayez l\'écran vers le haut pour ouvrir"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Appuyez pour ouvrir"</string>
<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 utiliser la CCP"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index bb3183e3761b..6a08d8716677 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Visage non reconnu. Utilisez votre empreinte."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Utilisez votre empreinte pour continuer"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Empreinte non reconnue. Utilisez le verrouillage de l\'écran."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Recherche de votre visage…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Icône représentant un visage"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Bouton \"Zoom de compatibilité\""</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Appuyer à nouveau pour ouvrir"</string>
<string name="tap_again" msgid="1315420114387908655">"Appuyer à nouveau"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Balayer vers le haut pour ouvrir"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Appuyez pour ouvrir"</string>
<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 NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index d8fe4b8249d1..15678e4cc907 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Non se recoñeceu a cara. Usa a impresión dixital."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Utiliza a túa impresión dixital para continuar"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Non se puido recoñecer a impresión dixital. Mellor usa o bloqueo de pantalla."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Buscándote…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Icona de cara"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Botón de zoom de compatibilidade"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Toca de novo para abrir"</string>
<string name="tap_again" msgid="1315420114387908655">"Toca de novo"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Pasa o dedo cara arriba para abrir"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Preme para abrir"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Pasa o dedo cara arriba para tentalo de novo"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquea o dispositivo para utilizar a NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence á túa organización."</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 553924abda3b..9255827aa64e 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ચહેરો ઓળખી શકતા નથી. તેને બદલે ફિંગરપ્રિન્ટ વાપરો."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"આગળ વધવા માટે તમારી ફિંગરપ્રિન્ટનો ઉપયોગ કરો"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"ફિંગરપ્રિન્ટ ઓળખી શકતા નથી. તેને બદલે સ્ક્રીન લૉકનો ઉપયોગ કરો."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"તમારા માટે શોધી રહ્યાં છે..."</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"ચહેરા આઇકન"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"સુસંગતતા ઝૂમ બટન."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"ખોલવા માટે ફરીથી ટૅપ કરો"</string>
<string name="tap_again" msgid="1315420114387908655">"ફરીથી ટૅપ કરો"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"ખોલવા માટે ઉપરની તરફ સ્વાઇપ કરો"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"અનલૉક કરવા માટે દબાવો"</string>
<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>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index ac4a9035f3d3..1ebb517dc316 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"चेहरे की पहचान नहीं हुई. फ़िंगरप्रिंट इस्तेमाल करें."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"जारी रखने के लिए, फ़िंगरप्रिंट का इस्तेमाल करें"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"फ़िंगरप्रिंट पहचाना नहीं जा सका. इसके बजाय, स्क्रीन लॉक इस्तेमाल करके देखें."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"आपको पहचान रहा है…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"चेहरे का आइकॉन"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"संगतता ज़ूम बटन."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"खोलने के लिए फिर से टैप करें"</string>
<string name="tap_again" msgid="1315420114387908655">"फिर से टैप करें"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"खोलने के लिए ऊपर स्वाइप करें"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"अनलॉक करने के लिए दबाएं"</string>
<string name="keyguard_retry" msgid="886802522584053523">"फिर से कोशिश करने के लिए ऊपर की ओर स्वाइप करें"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"एनएफ़सी इस्तेमाल करने के लिए स्क्रीन को अनलॉक करें"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"इस डिवाइस का मालिकाना हक आपके संगठन के पास है"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 571ca2427e35..9ec657d8d19d 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Prepoznavanje lica nije uspjelo. Upotrijebite otisak prsta."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Nastavite pomoću otiska prsta"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Prepoznavanje otiska prsta nije uspjelo. Umjesto toga upotrebljavajte zaključavanje zaslona."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Tražimo vas…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikona lica"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Gumb za kompatibilnost zumiranja."</string>
@@ -454,6 +456,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Dodirnite opet za otvaranje"</string>
<string name="tap_again" msgid="1315420114387908655">"Dodirnite ponovo"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Prijeđite prstom prema gore da biste otvorili"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pritisnite da biste otvorili"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Prijeđite prstom prema gore za ponovni pokušaj"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Otključajte da biste upotrijebili NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ovaj uređaj pripada vašoj organizaciji"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 9a7ca9d6d3a5..d9d8148938de 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Az arc nem felismerhető. Használjon ujjlenyomatot."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"A folytatáshoz használja ujjlenyomatát"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Az ujjlenyomat nem ismerhető fel. Használja inkább a képernyőzárat."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Keresem az Ön arcát…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Arcikon"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Kompatibilitási zoom gomb."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Koppintson ismét a megnyitáshoz"</string>
<string name="tap_again" msgid="1315420114387908655">"Koppintson újra"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Csúsztasson felfelé a megnyitáshoz"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"A megnyitáshoz nyomja meg"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Az újrapróbálkozáshoz csúsztassa felfelé az ujját"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Az NFC használatához oldja fel a képernyőzárat"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ez az eszköz az Ön szervezetének tulajdonában van"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 74ab34df000b..1d8094a4f61c 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Դեմքը չի հաջողվում ճանաչել։ Օգտագործեք մատնահետքը։"</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Շարունակելու համար անհրաժեշտ է ձեր մատնահետքը"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Մատնահետքը չի հաջողվում ճանաչել։ Օգտագործեք էկրանի կողպումը։"</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Դեմքի ճանաչում…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Դեմքի պատկերակ"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Համատեղելիության խոշորացման կոճակը:"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Կրկին հպեք՝ բացելու համար"</string>
<string name="tap_again" msgid="1315420114387908655">"Նորից հպեք"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Բացելու համար սահեցրեք վերև"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Սեղմեք՝ բացելու համար"</string>
<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>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 204484c8b58a..76ee7224933c 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tidak dapat mengenali wajah. Gunakan sidik jari."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Gunakan sidik jari untuk melanjutkan"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Tidak dapat mengenali sidik jari. Gunakan kunci layar."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Mencari wajah Anda…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikon wajah"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Tombol perbesar/perkecil kompatibilitas."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Ketuk lagi untuk membuka"</string>
<string name="tap_again" msgid="1315420114387908655">"Ketuk lagi"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Geser ke atas untuk membuka"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Tekan untuk membuka"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Geser ke atas untuk mencoba lagi"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Buka kunci untuk menggunakan NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Perangkat ini milik organisasi Anda"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 5afc8bc41f34..01905542684d 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Andlit þekkist ekki. Notaðu fingrafar í staðinn."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Notaðu fingrafarið þitt til að halda áfram"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Fingrafar þekkist ekki. Notaðu skjálás í staðinn."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Leitar að þér ..."</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Andlitstákn"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Hnappur fyrir samhæfisaðdrátt."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Ýttu aftur til að opna"</string>
<string name="tap_again" msgid="1315420114387908655">"Ýttu aftur"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Strjúktu upp til að opna"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Ýttu til að opna"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Strjúktu upp til að reyna aftur"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Taktu úr lás til að nota NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Þetta tæki tilheyrir fyrirtækinu þínu"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 9c283634b81e..0efab5ceb84e 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Impossibile riconoscere il volto. Usa l\'impronta."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Utilizza la tua impronta per continuare"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Impossibile riconoscere l\'impronta. Usa il blocco schermo."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"In attesa del volto…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Icona volto"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Pulsante zoom compatibilità."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Tocca ancora per aprire"</string>
<string name="tap_again" msgid="1315420114387908655">"Tocca di nuovo"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Scorri verso l\'alto per aprire"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Premi per aprire"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Scorri verso l\'alto per riprovare"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Sblocca per usare NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Questo dispositivo appartiene alla tua organizzazione"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index b7153b12ff3e..1e4c9d66ed9c 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"לא ניתן לזהות את הפנים. יש להשתמש בטביעת אצבע במקום."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"יש להשתמש בטביעת האצבע כדי להמשיך"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"לא ניתן לזהות את טביעת האצבע. יש להשתמש בנעילת המסך במקום."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"מתבצע חיפוש…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"סמל הפנים"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"לחצן מרחק מתצוגה של תאימות."</string>
@@ -456,6 +458,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"יש להקיש שוב כדי לפתוח את ההתראה"</string>
<string name="tap_again" msgid="1315420114387908655">"צריך להקיש פעם נוספת"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"צריך להחליק כדי לפתוח"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"יש להקיש כדי לפתוח"</string>
<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>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index a8fb87d40e1a..27259791f664 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"顔を認識できません。指紋認証を使用してください。"</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"続行するには指紋認証を使用してください"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"指紋を認識できません。代わりに画面ロックを使用してください。"</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"顔を認証しています…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"顔アイコン"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"互換ズームボタン。"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"開くにはもう一度タップしてください"</string>
<string name="tap_again" msgid="1315420114387908655">"もう一度タップしてください"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"開くには上にスワイプします"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"押すと開きます"</string>
<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>
@@ -798,7 +801,7 @@
<item quantity="other">%d分</item>
<item quantity="one">%d分</item>
</plurals>
- <string name="battery_panel_title" msgid="5931157246673665963">"電池の使用状況"</string>
+ <string name="battery_panel_title" msgid="5931157246673665963">"バッテリーの使用状況"</string>
<string name="battery_detail_charging_summary" msgid="8821202155297559706">"充電中はバッテリー セーバーは利用できません"</string>
<string name="battery_detail_switch_title" msgid="6940976502957380405">"バッテリー セーバー"</string>
<string name="battery_detail_switch_summary" msgid="3668748557848025990">"パフォーマンスとバックグラウンド データを制限します"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index da4f5bc855f6..21e1c52ae136 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"სახის ამოცნობა ვერ ხერხდება. სანაცვლოდ თითის ანაბეჭდი გამოიყენეთ."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"გასაგრძელებლად გამოიყენეთ თქვენი თითის ანაბეჭდი"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"თითის ანაბეჭდის ამოცნობა ვერ ხერხდება. სანაცვლოდ, გამოიყენეთ ეკრანის დაბლოკვა."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"მიმდინარეობს თქვენი ძიება…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"სახის ხატულა"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"თავსებადი მასშტაბირების ღილაკი."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"შეეხეთ ისევ გასახსნელად"</string>
<string name="tap_again" msgid="1315420114387908655">"შეეხეთ ხელახლა"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"გასახსნელად გადაფურცლეთ ზემოთ"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"დააჭირეთ გასახსნელად"</string>
<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>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index c15c6be99669..6a9a9b5d8d11 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Бет танылмады. Орнына саусақ ізін пайдаланыңыз."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Жалғастыру үшін саусақ ізін пайдаланыңыз."</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Саусақ ізі танылмады. Орнына экран құлпын пайдаланыңыз."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Бет ізделуде…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Бет белгішесі"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Үйлесімділік ұлғайту түймесі."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Ашу үшін қайта түртіңіз"</string>
<string name="tap_again" msgid="1315420114387908655">"Қайта түртіңіз."</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Ашу үшін жоғары қарай сырғытыңыз."</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Ашу үшін басыңыз."</string>
<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>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 31de2be76e46..080ba1958e24 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"មិនអាចសម្គាល់មុខបានទេ។ សូមប្រើស្នាមម្រាមដៃជំនួសវិញ។"</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"ប្រើ​ស្នាមម្រាមដៃ​របស់អ្នក ដើម្បីបន្ត"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"មិនអាចសម្គាល់​ស្នាមម្រាមដៃបានទេ។ សូមប្រើសោ​អេក្រង់ជំនួសវិញ។"</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"កំពុងស្វែងរកអ្នក…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"រូប​ផ្ទៃមុខ"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"ប៊ូតុង​ពង្រីក​ត្រូវ​គ្នា។"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"ប៉ះ​ម្ដង​ទៀត ដើម្បី​បើក"</string>
<string name="tap_again" msgid="1315420114387908655">"ចុច​ម្ដងទៀត"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"អូសឡើងលើ​ដើម្បីបើក"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"ចុច ដើម្បីបើក"</string>
<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>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 9b9138c44119..f63d02f6682a 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ಮುಖ ಗುರುತಿಸಲಾಗುತ್ತಿಲ್ಲ ಬದಲಿಗೆ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಬಳಸಿ."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"ಮುಂದುವರಿಸಲು ನಿಮ್ಮ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಬಳಸಿ"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಅನ್ನು ಗುರುತಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಬದಲಾಗಿ ಪರದೆಲಾಕ್ ಬಳಸಿ."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"ನಿಮಗಾಗಿ ಹುಡುಕಲಾಗುತ್ತಿದೆ…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"ಮುಖದ ಐಕಾನ್‌"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"ಹೊಂದಾಣಿಕೆಯ ಝೂಮ್ ಬಟನ್."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"ತೆರೆಯಲು ಮತ್ತೆ ಟ್ಯಾಪ್‌ ಮಾಡಿ"</string>
<string name="tap_again" msgid="1315420114387908655">"ಪುನಃ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"ತೆರೆಯಲು ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"ತೆರೆಯಲು ಒತ್ತಿ"</string>
<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>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 9aaea76baed5..371b7de67806 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"얼굴을 인식할 수 없습니다. 대신 지문을 사용하세요."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"계속하려면 지문을 사용하세요."</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"지문을 인식할 수 없습니다. 화면 잠금을 대신 사용하세요."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"찾는 중..."</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"얼굴 아이콘"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"호환성 확대/축소 버튼입니다."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"다시 탭하여 열기"</string>
<string name="tap_again" msgid="1315420114387908655">"다시 탭하세요."</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"위로 스와이프하여 열기"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"열려면 누르세요"</string>
<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>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 0a0bf4c4ef96..404b9ac45179 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Жүз таанылбай жатат. Манжа изин колдонуңуз."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Улантуу үчүн манжаңызды сканерге тийгизиңиз"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Манжа изи таанылбай жатат. Эрканды кулпулоо функциясын колдонуңуз."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Жүзүңүз изделүүдө…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Жүздүн сүрөтчөсү"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Масштабды сыйыштыруу баскычы."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Ачуу үчүн кайра таптап коюңуз"</string>
<string name="tap_again" msgid="1315420114387908655">"Кайра таптап коюңуз"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Ачуу үчүн өйдө сүрүңүз"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Ачуу үчүн басыңыз"</string>
<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>
@@ -706,11 +709,11 @@
<string name="tuner_full_importance_settings" msgid="1388025816553459059">"Эскертмелерди башкаруу каражаттары"</string>
<string name="tuner_full_importance_settings_on" msgid="917981436602311547">"Күйүк"</string>
<string name="tuner_full_importance_settings_off" msgid="5580102038749680829">"Өчүк"</string>
- <string name="power_notification_controls_description" msgid="1334963837572708952">"Бул функциянын жардамы менен, ар бир колдонмо үчүн билдирменин маанилүүлүгүн 0дон 5ке чейин бааласаңыз болот. \n\n"<b>"5-деңгээл"</b>" \n- Билдирмелер тизмесинин өйдө жагында көрсөтүлөт \n- Билдирмелер толук экранда көрсөтүлөт \n- Калкып чыгуучу билдирмелерге уруксат берилет \n\n"<b>"4-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге уруксат берилет \n\n"<b>"3-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n\n"<b>"2-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n- Эч качан үн чыкпайт же дирилдебейт \n\n"<b>"1-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n- Эч качан үн чыкпайт же дирилдебейт \n- Кулпуланган экрандан жана абал тилкесинен жашырылат \n- Билдирмелер тизмесинин ылдый жагында көрсөтүлөт \n\n"<b>"0-деңгээл"</b>" \n- Колдонмодон алынган бардык билдирмелер бөгөттөлөт"</string>
+ <string name="power_notification_controls_description" msgid="1334963837572708952">"Бул функциянын жардамы менен, ар бир колдонмо үчүн билдирменин маанилүүлүгүн 0дон 5ке чейин бааласаңыз болот. \n\n"<b>"5-деңгээл"</b>" \n- Билдирмелер тизмесинин өйдө жагында көрүнөт \n- Билдирмелер толук экранда көрүнөт \n- Калкып чыгуучу билдирмелерге уруксат берилет \n\n"<b>"4-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге уруксат берилет \n\n"<b>"3-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n\n"<b>"2-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n- Эч качан үн чыкпайт же дирилдебейт \n\n"<b>"1-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n- Эч качан үн чыкпайт же дирилдебейт \n- Кулпуланган экрандан жана абал тилкесинен жашырылат \n- Билдирмелер тизмесинин ылдый жагында көрүнөт \n\n"<b>"0-деңгээл"</b>" \n- Колдонмодон алынган бардык билдирмелер бөгөттөлөт"</string>
<string name="notification_header_default_channel" msgid="225454696914642444">"Билдирмелер"</string>
<string name="notification_channel_disabled" msgid="928065923928416337">"Мындан ары бул билдирмелер сизге көрүнбөйт"</string>
<string name="notification_channel_minimized" msgid="6892672757877552959">"Бул билдирмелер кичирейтилет"</string>
- <string name="notification_channel_silenced" msgid="1995937493874511359">"Бул билдирмелер үнсүз көрсөтүлөт"</string>
+ <string name="notification_channel_silenced" msgid="1995937493874511359">"Бул билдирмелер үнсүз көрүнөт"</string>
<string name="notification_channel_unsilenced" msgid="94878840742161152">"Бул билдирмелер тууралуу кабарлап турабыз"</string>
<string name="inline_blocking_helper" msgid="2891486013649543452">"Адатта мындай билдирмелерди өткөрүп жибересиз. \nАлар көрүнө берсинби?"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Бүттү"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 53a0ace0ee33..33fddef3efb3 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ບໍ່ສາມາດຈຳແນກໜ້າໄດ້. ກະລຸນາໃຊ້ລາຍນິ້ວມືແທນ."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"ກະລຸນາໃຊ້ລາຍນິ້ວມືຂອງທ່ານເພື່ອສືບຕໍ່"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"ບໍ່ສາມາດຈຳແນກລາຍນິ້ວມືໄດ້. ກະລຸນາໃຊ້ການລອກໜ້າຈໍແທນ."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"ກຳລັງຊອກຫາທ່ານ…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"ໄອຄອນໃບໜ້າ"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"ປຸ່ມຊູມທີ່ໃຊ້ຮ່ວມກັນໄດ້."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"ແຕະ​ອີກ​ຄັ້ງ​ເພື່ອ​ເປີດ"</string>
<string name="tap_again" msgid="1315420114387908655">"ແຕະອີກເທື່ອໜຶ່ງ"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"ປັດຂຶ້ນເພື່ອເປີດ"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"ກົດເພື່ອເປີດ"</string>
<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>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 56f187e2d352..94faaf42d1b9 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Veidas neatpažintas. Naudokite kontrolinį kodą."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Jei norite tęsti, naudokite kontrolinį kodą"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Nepavyko atpažinti kontrolinio kodo. Naudokite ekrano užraktą."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Ieškoma jūsų…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Veido piktograma"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Suderinamumo priartinimo mygtukas."</string>
@@ -456,6 +458,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Palieskite dar kartą, kad atidarytumėte"</string>
<string name="tap_again" msgid="1315420114387908655">"Palieskite dar kartą"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Perbraukite aukštyn, kad atidarytumėte"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Paspauskite, kad atidarytumėte"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Jei norite bandyti dar kartą, perbraukite aukštyn"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Norėdami naudoti NFC, atrakinkite"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Šis įrenginys priklauso jūsų organizacijai"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 4522b98dbba3..0d14405ea4fb 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nevar atpazīt seju. Lietojiet pirksta nospiedumu."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Lai turpinātu, izmantojiet pirksta nospiedumu."</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Nevar atpazīt pirksta nospiedumu. Izmantojiet ekrāna bloķēšanu."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Notiek jūsu sejas meklēšana…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Sejas ikona"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Saderības tālummaiņas poga."</string>
@@ -454,6 +456,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Pieskarieties vēlreiz, lai atvērtu"</string>
<string name="tap_again" msgid="1315420114387908655">"Pieskarieties vēlreiz"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Velciet augšup, lai atvērtu"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Nospiediet, lai atvērtu"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Velciet augšup, lai mēģinātu vēlreiz"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Atbloķējiet ierīci, lai izmantotu NFC."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Šī ierīce pieder jūsu organizācijai."</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 9a8de862aa34..5fda8b211ab1 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Не се препознава ликот. Користете отпечаток."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Употребете го отпечатокот за да продолжите"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Не се препознава отпечатокот. Користете заклучување екран."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Ве бараме вас…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Икона за лице"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Копче за компатибилност на зум."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Допрете повторно за да се отвори"</string>
<string name="tap_again" msgid="1315420114387908655">"Допрете повторно"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Повлечете за да отворите"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Притиснете за да отворите"</string>
<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>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index e798c7d61dfe..6956934d7af7 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"മുഖം തിരിച്ചറിയാനായില്ല. പകരം ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കൂ."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"തുടരുന്നതിന് നിങ്ങളുടെ ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കുക"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"ഫിംഗർപ്രിന്റ് തിരിച്ചറിയാനാകുന്നില്ല. പകരം സ്‌ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"നിങ്ങൾക്കായി തിരയുന്നു…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"മുഖത്തിന്റെ ഐക്കൺ"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"അനുയോജ്യതാ സൂം ബട്ടൺ."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"തുറക്കുന്നതിന് വീണ്ടും ടാപ്പുചെയ്യുക"</string>
<string name="tap_again" msgid="1315420114387908655">"വീണ്ടും ടാപ്പ് ചെയ്യുക"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"തുറക്കാൻ മുകളിലോട്ട് സ്വൈപ്പ് ചെയ്യുക"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"തുറക്കാൻ അമർത്തുക"</string>
<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>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 0e4cac02ea2d..0d1ad4bebce6 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Царай таних боломжгүй. Оронд нь хурууны хээ ашигла"</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Үргэлжлүүлэхийн тулд хурууныхаа хээг ашиглана уу"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Хурууны хээг таних боломжгүй. Оронд нь дэлгэцийн түгжээ ашиглана уу."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Таныг хайж байна…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Царайны дүрс тэмдэг"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Тохиромжтой өсгөх товч."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Нээхийн тулд дахин товшино уу"</string>
<string name="tap_again" msgid="1315420114387908655">"Дaхин товшино уу"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Нээхийн тулд дээш шударна уу"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Нээхийн тулд дарна уу"</string>
<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>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 45a9a1bed0e5..cee701953f69 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"चेहरा ओळखू शकत नाही. त्याऐवजी फिंगरप्रिंट वापरा."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"पुढे सुरू ठेवण्‍यासाठी तुमची फिंगरप्रिंट वापरा"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"फिंगरप्रिंट ओळखता आली नाही. त्याऐवजी स्क्रीन लॉक वापरा."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"तुमच्यासाठी शोधत आहे…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"चेहरा आयकन"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"सुसंगतता झूम बटण."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"उघडण्यासाठी पुन्हा टॅप करा"</string>
<string name="tap_again" msgid="1315420114387908655">"पुन्हा टॅप करा"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"उघडण्यासाठी वर स्वाइप करा"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"उघडण्यासाठी दाबा"</string>
<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>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 2349e286b491..b7d0246c4095 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tidak mengenali wajah. Gunakan cap jari."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Gunakan cap jari anda untuk teruskan"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Tidak mengenali cap jari. Sebaliknya, gunakan kunci skrin."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Mencari anda…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikon wajah"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Butang zum keserasian."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Ketik lagi untuk membuka"</string>
<string name="tap_again" msgid="1315420114387908655">"Ketik sekali lagi"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Leret ke atas untuk buka"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Tekan untuk buka"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Leret ke atas untuk mencuba lagi"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Buka kunci untuk menggunakan NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Peranti ini milik organisasi anda"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 23de47fba55d..81d168b79065 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"မျက်နှာကို မမှတ်မိပါ။ လက်ဗွေကို အစားထိုးသုံးပါ။"</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"ရှေ့ဆက်ရန် သင့်လက်ဗွေကို သုံးပါ"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"လက်ဗွေကို မမှတ်မိပါ။ ဖန်သားပြင်လော့ခ်ချခြင်းကို အစားထိုးသုံးပါ။"</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"သင့်ကို ရှာဖွေနေသည်…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"မျက်နှာသင်္ကေတ"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"အံဝင်ခွင်ကျ ဇူးမ်ခလုတ်"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"ဖွင့်ရန် ထပ်ပြီး ပုတ်ပါ"</string>
<string name="tap_again" msgid="1315420114387908655">"ထပ်တို့ပါ"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"ဖွင့်ရန် အပေါ်သို့ပွတ်ဆွဲပါ"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"ဖွင့်ရန် နှိပ်ပါ"</string>
<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>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 9c18b95f3387..360c58b9e2dc 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansiktet gjenkjennes ikke. Bruk fingeravtrykk."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Bruk fingeravtrykket for å fortsette"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Fingeravtrykket gjenkjennes ikke. Bruk skjermlås i stedet."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Ser etter deg …"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ansiktikon"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Zoomknapp for kompatibilitet."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Trykk på nytt for å åpne"</string>
<string name="tap_again" msgid="1315420114387908655">"Trykk igjen"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Sveip opp for å åpne"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Trykk for å åpne"</string>
<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>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 9ae2d43e26ed..e5787b578430 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"अनुहार पहिचान गर्न सकिएन। बरु फिंगरप्रिन्ट प्रयोग गर्नुहोस्।"</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"जारी राख्न आफ्नो फिंगरप्रिन्ट प्रयोग गर्नुहोस्"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"फिंगरप्रिन्ट पहिचान गर्न सकिएन। बरु स्क्रिन लक प्रयोग गर्नुहोस्।"</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"तपाईंलाई खोज्दै…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"अनुहारको आइकन"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"मिलाउने जुम बटन।"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"खोल्न पुनः ट्याप गर्नुहोस्"</string>
<string name="tap_again" msgid="1315420114387908655">"फेरि ट्याप गर्नुहोस्"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"खोल्न माथितिर स्वाइप गर्नुहोस्"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"अनलक गर्न प्रेस गर्नुहोस्"</string>
<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>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 155d1ad6975d..7d75b6e20a1e 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Gezicht niet herkend. Gebruik je vingerafdruk."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Gebruik je vingerafdruk om door te gaan."</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Vingerafdruk niet herkend. Gebruik in plaats daarvan de schermvergrendeling."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Jouw gezicht zoeken…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Gezichtspictogram"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Knop voor compatibiliteitszoom."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Tik nog eens om te openen"</string>
<string name="tap_again" msgid="1315420114387908655">"Tik nog een keer"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Swipe omhoog om te openen"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Druk om te openen"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Swipe omhoog om het opnieuw te proberen"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ontgrendel het apparaat om NFC te gebruiken"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Dit apparaat is eigendom van je organisatie"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 4d44690b5951..ee524bf2e3c8 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ଫେସ୍ ଚିହ୍ନଟ କରିହେବ ନାହିଁ। ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"ଟିପଚିହ୍ନକୁ ଚିହ୍ନଟ କରାଯାଇପାରିବ ନାହିଁ। ଏହା ପରିବର୍ତ୍ତେ ସ୍କ୍ରିନ୍ ଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"ଆପଣଙ୍କୁ ଚିହ୍ନଟ କରୁଛି…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"ମୁହଁ ଆଇକନ୍"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"କମ୍ପାଟିବିଲିଟୀ ଜୁମ୍ ବଟନ୍।"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"ଖୋଲିବା ପାଇଁ ପୁଣି ଟାପ୍‍ କରନ୍ତୁ"</string>
<string name="tap_again" msgid="1315420114387908655">"ପୁଣି ଟାପ୍ କରନ୍ତୁ"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"ଖୋଲିବା ପାଇଁ ଉପରକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"ଖୋଲିବାକୁ ଦବାନ୍ତୁ"</string>
<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>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 7bb60a0a80f9..d68ab4fe347a 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ਚਿਹਰਾ ਨਹੀਂ ਪਛਾਣ ਸਕਦੇ। ਇਸਦੀ ਬਜਾਏ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ।"</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਆਪਣਾ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦੀ ਪਛਾਣ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਇਸਦੀ ਬਜਾਏ ਸਕ੍ਰੀਨ ਲਾਕ ਵਰਤੋ।"</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"ਤੁਹਾਡੀ ਪਛਾਣ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"ਚਿਹਰਾ ਪ੍ਰਤੀਕ"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"ਅਨੁਰੂਪਤਾ ਜ਼ੂਮ ਬਟਨ।"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"ਖੋਲ੍ਹਣ ਲਈ ਦੁਬਾਰਾ ਟੈਪ ਕਰੋ"</string>
<string name="tap_again" msgid="1315420114387908655">"ਦੁਬਾਰਾ ਟੈਪ ਕਰੋ"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"ਖੋਲ੍ਹਣ ਲਈ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"ਖੋਲ੍ਹਣ ਲਈ ਦਬਾਓ"</string>
<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>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index ea6f2252c0cd..9aade18169ad 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nie rozpoznaję twarzy. Użyj odcisku palca."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Użyj odcisku palca, aby kontynuować"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Nie rozpoznaję odcisku palca. Użyj blokady ekranu."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Szukam Cię…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikona twarzy"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Przycisk powiększenia na potrzeby zgodności."</string>
@@ -456,6 +458,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Kliknij ponownie, by otworzyć"</string>
<string name="tap_again" msgid="1315420114387908655">"Kliknij jeszcze raz"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Przesuń w górę, by otworzyć"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Naciśnij, by otworzyć"</string>
<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>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 2f1501b26c6c..cab482ae56fd 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Não foi possível reconhecer o rosto Use a impressão digital."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Use sua impressão digital para continuar"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Não foi possível reconhecer a impressão digital. Use o bloqueio de tela."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Procurando você…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ícone facial"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Botão de zoom da compatibilidade."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Toque novamente para abrir"</string>
<string name="tap_again" msgid="1315420114387908655">"Toque novamente"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Deslize para cima para abrir"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pressione para abrir"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Deslize para cima para tentar novamente"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueie para usar a NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua organização"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 563e99d56547..eec34684ff4a 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Impos. reconh. rosto. Utilize a impressão digital."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Utilize a sua impressão digital para continuar"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Não é possível reconhecer a impressão digital. Em alternativa, utilize o bloqueio de ecrã."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"À sua procura…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ícone de rosto"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Botão zoom de compatibilidade."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Toque novamente para abrir"</string>
<string name="tap_again" msgid="1315420114387908655">"Toque novamente"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Deslize rapidamente para cima para abrir"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Prima para abrir"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Deslize rapidamente para cima para tentar novamente."</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloquear para utilizar o NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua entidade."</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 2f1501b26c6c..cab482ae56fd 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Não foi possível reconhecer o rosto Use a impressão digital."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Use sua impressão digital para continuar"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Não foi possível reconhecer a impressão digital. Use o bloqueio de tela."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Procurando você…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ícone facial"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Botão de zoom da compatibilidade."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Toque novamente para abrir"</string>
<string name="tap_again" msgid="1315420114387908655">"Toque novamente"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Deslize para cima para abrir"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pressione para abrir"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Deslize para cima para tentar novamente"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Desbloqueie para usar a NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Este dispositivo pertence à sua organização"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 21026001e0fc..1e30ea713210 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Chipul nu a fost recunoscut. Folosiți amprenta."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Folosiți amprenta pentru a continua"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Amprenta nu a fost recunoscută. Folosiți blocarea ecranului."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Vă căutăm…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Pictograma chip"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Buton zoom pentru compatibilitate."</string>
@@ -454,6 +456,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Atingeți din nou pentru a deschide"</string>
<string name="tap_again" msgid="1315420114387908655">"Atingeți din nou"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Glisați în sus pentru a deschide"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Apăsați pentru a deschide"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Glisați pentru a încerca din nou"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Deblocați pentru a folosi NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Dispozitivul aparține organizației dvs."</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index eeb1f3e392aa..99465d54e124 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Не удалось распознать лицо. Используйте отпечаток."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Чтобы продолжить, прикоснитесь пальцем к сканеру."</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Не удалось распознать отпечаток пальца. Используйте другой способ разблокировки экрана."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Поиск лица…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Значок лица"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Кнопка масштабирования (режим совместимости)"</string>
@@ -456,6 +458,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Нажмите ещё раз, чтобы открыть"</string>
<string name="tap_again" msgid="1315420114387908655">"Нажмите ещё раз"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Проведите вверх, чтобы открыть"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Нажмите, чтобы открыть."</string>
<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>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 247b7a544cdd..6ea2a0dd5d7a 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"මුහුණ හැඳිනිය නොහැක. ඒ වෙනුවට ඇඟිලි සලකුණ භාවිත ක."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"ඉදිරියට යාමට ඔබගේ ඇඟිලි සලකුණ භාවිත කරන්න"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"ඇඟිලි සලකුණ හඳුනා ගත නොහැකිය. ඒ වෙනුවට තිර අගුල භාවිත කරන්න."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"ඔබව සොයමින්…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"මුහුණ නිරූපකය"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"ගැළපෙන විශාලන බොත්තම."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"විවෘත කිරීමට නැවත තට්ටු කරන්න"</string>
<string name="tap_again" msgid="1315420114387908655">"නැවත තට්ටු කරන්න"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"විවෘත කිරීමට ස්වයිප් කරන්න"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"විවෘත කිරීමට ඔබන්න"</string>
<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>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 74b24bdd531c..399b9797d21f 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tvár sa nedá rozpoznať. Použite odtlačok prsta."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Pokračujte nasnímaním odtlačku prsta"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Odtlačok prsta sa nedá rozpoznať. Použite radšej zámku obrazovky."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Hľadáme vás…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikona tváre"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Tlačidlo úpravy veľkosti z dôvodu kompatibility."</string>
@@ -456,6 +458,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Upozornenie otvoríte opätovným klepnutím"</string>
<string name="tap_again" msgid="1315420114387908655">"Klepnite znova"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Otvorte potiahnutím prstom nahor"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Stlačením otvoríte"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Potiahnutím nahor to skúste znova"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Ak chcete použiť NFC, odomknite"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Toto zariadenie patrí vašej organizácii"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index cfb89d4c8194..0c93bced9f41 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Obraza ni mogoče prepoznati. Uporabite prstni odtis."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Uporabite prstni odtis, če želite nadaljevati."</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Prstnega odtisa ni mogoče prepoznati. Uporabite odklepanje s poverilnico."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Preverjanje vašega obraza …"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikona obraza"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Gumb povečave za združljivost."</string>
@@ -456,6 +458,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Znova se dotaknite, da odprete"</string>
<string name="tap_again" msgid="1315420114387908655">"Znova se dotaknite možnosti"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Povlecite navzgor, da odprete"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pritisnite, če želite odpreti."</string>
<string name="keyguard_retry" msgid="886802522584053523">"Povlecite navzgor za vnovičen poskus"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Odklenite napravo, če želite uporabljati NFC."</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Ta naprava pripada vaši organizaciji"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index f7753c7a5086..7f101dbd3f57 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nuk mund ta dallojë fytyrën. Përdor më mirë gjurmën e gishtit."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Përdor gjurmën e gishtit për të vazhduar"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Nuk mund ta dallojë gjurmën e gishtit. Përdor më mirë kyçjen e ekranit."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Po të kërkojmë…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikona e fytyrës"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Butoni i zmadhimit të pajtueshmërisë."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Trokit përsëri për ta hapur"</string>
<string name="tap_again" msgid="1315420114387908655">"Trokit sërish"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Rrëshqit lart për ta hapur"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Shtyp për të hapur"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Rrëshqit lart për të provuar përsëri"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Shkyçe për të përdorur NFC-në"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Kjo pajisje i përket organizatës sate"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 73ecc4c7b72b..1da42cfb2d3d 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Лице није препознато. Користите отисак прста."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Наставите помоћу отиска прста"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Препознавање отиска прста није успело. Користите закључавање екрана уместо тога."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Тражимо вас…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Икона лица"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Дугме Зум компатибилности."</string>
@@ -454,6 +456,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Додирните поново да бисте отворили"</string>
<string name="tap_again" msgid="1315420114387908655">"Додирните поново"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Превуците нагоре да бисте отворили"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Притисните да бисте отворили"</string>
<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>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index c27cd83f0541..05aeffbc300d 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansiktet kändes inte igen. Använd fingeravtryck."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Fortsätt med hjälp av ditt fingeravtryck"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Fingeravtrycket kändes inte igen. Använd låsskärmen i stället."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Håller utkik efter dig …"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ansiktsikon"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Knapp för kompatibilitetszoom."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Tryck igen för att öppna"</string>
<string name="tap_again" msgid="1315420114387908655">"Tryck igen"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Öppna genom att svepa uppåt"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Tryck för att öppna"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Svep uppåt om du vill försöka igen"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås upp om du vill använda NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Den här enheten tillhör organisationen"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 7ac26be4c614..7f51e82683b7 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Imeshindwa kutambua uso. Tumia alama ya kidole."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Tumia alama ya kidole chako ili uendelee"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Imeshindwa kutambua alama ya kidole. Tumia mbinu ya kufunga skrini badala yake."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Inakutafuta…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Aikoni ya uso"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Kichupo cha kukuza kwa utangamanifu"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Gusa tena ili ufungue"</string>
<string name="tap_again" msgid="1315420114387908655">"Gusa tena"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Telezesha kidole juu ili ufungue"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Bofya ili ufungue"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Telezesha kidole juu ili ujaribu tena"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Fungua ili utumie NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Kifaa hiki kinamilikiwa na shirika lako"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 426ddd4b3e83..b51fb9efbbee 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"முகத்தை அடையாளம் காண முடியவில்லை. கைரேகையைப் பயன்படுத்தவும்."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"தொடர்வதற்குக் கைரேகையைப் பயன்படுத்தவும்"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"கைரேகையை அடையாளம் காண முடியவில்லை. அதற்குப் பதிலாகத் திரைப்பூட்டைப் பயன்படுத்தவும்."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"உங்கள் முகத்தைத் தேடுகிறது…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"முக ஐகான்"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"பொருந்துமாறு அளவை மாற்றும் பட்டன்."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"திறக்க, மீண்டும் தட்டவும்"</string>
<string name="tap_again" msgid="1315420114387908655">"மீண்டும் தட்டவும்"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"திறப்பதற்கு மேல் நோக்கி ஸ்வைப் செய்யவும்"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"திறப்பதற்கு அழுத்தவும்"</string>
<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>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index b8a3ccd15956..7ad382ec6bbc 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -103,7 +103,7 @@
<string name="screenrecord_description" msgid="1123231719680353736">"రికార్డ్ చేస్తున్నప్పుడు, Android సిస్టమ్ మీ స్క్రీన్‌పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన ఏ సున్నితమైన సమాచారాన్నైనా క్యాప్చర్ చేయగలదు. ఈ సమాచారంలో, పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, ఫోటోలు, మెసేజ్‌లు, ఆడియో ఉంటాయి."</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"ఆడియోను రికార్డ్ చేయి"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"పరికరం ఆడియో"</string>
- <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"మీ పరికరం నుండి వచ్చే సంగీతం, కాల్‌లు, రింగ్‌టోన్‌ల వంటి ధ్వనులు"</string>
+ <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"మీ పరికరం నుండి వచ్చే సంగీతం, కాల్స్‌, రింగ్‌టోన్‌ల వంటి ధ్వనులు"</string>
<string name="screenrecord_mic_label" msgid="2111264835791332350">"మైక్రోఫోన్"</string>
<string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"పరికరం ఆడియో, మైక్రోఫోన్"</string>
<string name="screenrecord_start" msgid="330991441575775004">"ప్రారంభించు"</string>
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ముఖం గుర్తించలేము. బదులుగా వేలిముద్ర ఉపయోగించండి."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"కొనసాగించడానికి మీ వేలిముద్రను ఉపయోగించండి"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"వేలిముద్రను గుర్తించడం సాధ్యపడదు. బదులుగా స్క్రీన్ లాక్‌ను ఉపయోగించండి."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"మీ కోసం చూస్తోంది…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"ముఖ చిహ్నం"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"అనుకూలత జూమ్ బటన్."</string>
@@ -445,13 +447,14 @@
<string name="zen_priority_introduction" msgid="3159291973383796646">"మీరు పేర్కొనే అలారాలు, రిమైండర్‌లు, ఈవెంట్‌లు మరియు కాలర్‌ల నుండి మినహా మరే ఇతర ధ్వనులు మరియు వైబ్రేషన్‌లతో మీకు అంతరాయం కలగదు. మీరు ఇప్పటికీ సంగీతం, వీడియోలు మరియు గేమ్‌లతో సహా మీరు ప్లే చేయడానికి ఎంచుకున్నవి ఏవైనా వింటారు."</string>
<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_voice" msgid="853573681302712348">"ఇది అలారాలు, సంగీతం, వీడియోలు మరియు గేమ్‌లతో సహా అన్ని ధ్వనులు మరియు వైబ్రేషన్‌లను బ్లాక్ చేస్తుంది. మీరు ఇప్పటికీ ఫోన్ కాల్స్‌ చేయగలుగుతారు."</string>
<string name="zen_silence_introduction" msgid="6117517737057344014">"ఇది అలారాలు, సంగీతం, వీడియోలు మరియు గేమ్‌లతో సహా అన్ని ధ్వనులు మరియు వైబ్రేషన్‌లను బ్లాక్ చేస్తుంది."</string>
<string name="keyguard_more_overflow_text" msgid="5819512373606638727">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="7248696377626341060">"తక్కువ అత్యవసర నోటిఫికేషన్‌లు దిగువన"</string>
<string name="notification_tap_again" msgid="4477318164947497249">"తెరవడానికి మళ్లీ నొక్కండి"</string>
<string name="tap_again" msgid="1315420114387908655">"మళ్లీ ట్యాప్ చేయండి"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"తెరవడానికి, పైకి స్వైప్ చేయండి"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"తెరవడానికి నొక్కండి"</string>
<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>
@@ -628,7 +631,7 @@
<string name="stream_bluetooth_sco" msgid="6234562365528664331">"బ్లూటూత్"</string>
<string name="stream_dtmf" msgid="7322536356554673067">"డ్యూయల్ మల్టీ టోన్ ఫ్రీక్వెన్సీ"</string>
<string name="stream_accessibility" msgid="3873610336741987152">"యాక్సెసిబిలిటీ"</string>
- <string name="ring_toggle_title" msgid="5973120187287633224">"కాల్‌లు"</string>
+ <string name="ring_toggle_title" msgid="5973120187287633224">"కాల్స్‌"</string>
<string name="volume_ringer_status_normal" msgid="1339039682222461143">"రింగ్"</string>
<string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"వైబ్రేట్"</string>
<string name="volume_ringer_status_silent" msgid="3691324657849880883">"మ్యూట్"</string>
@@ -644,7 +647,7 @@
<string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"అన్‌మ్యూట్ చేయి"</string>
<string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"వైబ్రేట్"</string>
<string name="volume_dialog_title" msgid="6502703403483577940">"%s వాల్యూమ్ నియంత్రణలు"</string>
- <string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"కాల్‌లు మరియు నోటిఫికేషన్‌లు రింగ్ అవుతాయి (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
+ <string name="volume_dialog_ringer_guidance_ring" msgid="9143194270463146858">"కాల్స్‌ మరియు నోటిఫికేషన్‌లు రింగ్ అవుతాయి (<xliff:g id="VOLUME_LEVEL">%1$s</xliff:g>)"</string>
<string name="output_title" msgid="3938776561655668350">"మీడియా అవుట్‌పుట్"</string>
<string name="output_calls_title" msgid="7085583034267889109">"ఫోన్ కాల్ అవుట్‌పుట్"</string>
<string name="output_none_found" msgid="5488087293120982770">"పరికరాలు ఏవీ కనుగొనబడలేదు"</string>
@@ -934,7 +937,7 @@
<string name="tuner_lock_screen" msgid="2267383813241144544">"లాక్ స్క్రీన్"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"వేడెక్కినందుకు ఫోన్ ఆఫ్ చేయబడింది"</string>
<string name="thermal_shutdown_message" msgid="6142269839066172984">"మీ ఫోన్ ఇప్పుడు సాధారణంగా పని చేస్తోంది.\nమరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"మీ ఫోన్ చాలా వేడిగా ఉంది, కనుక చల్లబర్చడానికి ఆఫ్ చేయబడింది. మీ ఫోన్ ఇప్పుడు సాధారణంగా పని చేస్తుంది.\n\nమీరు ఇలా చేస్తే మీ ఫోన్ చాలా వేడెక్కవచ్చు:\n • వనరు-ఆధారిత యాప్‌లు (గేమింగ్, వీడియో లేదా నావిగేషన్ వంటి యాప్‌లు) ఉపయోగించడం\n • పెద్ద ఫైల్‌లను డౌన్‌లోడ్ లేదా అప్‌లోడ్ చేయడం\n • అధిక ఉష్ణోగ్రతలలో మీ ఫోన్‌ని ఉపయోగించడం"</string>
+ <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"మీ ఫోన్ చాలా వేడిగా ఉంది, కనుక చల్లబర్చడానికి ఆఫ్ చేయబడింది. మీ ఫోన్ ఇప్పుడు సాధారణంగా పని చేస్తుంది.\n\nమీరు ఇలా చేస్తే మీ ఫోన్ చాలా వేడెక్కవచ్చు:\n • వనరు-ఆధారిత యాప్‌లు (గేమింగ్, వీడియో లేదా నావిగేషన్ వంటి యాప్‌లు) ఉపయోగించడం\n • పెద్ద ఫైళ్లను డౌన్‌లోడ్ లేదా అప్‌లోడ్ చేయడం\n • అధిక ఉష్ణోగ్రతలలో మీ ఫోన్‌ని ఉపయోగించడం"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"తీసుకోవాల్సిన జాగ్రత్తలు ఏమిటో చూడండి"</string>
<string name="high_temp_title" msgid="2218333576838496100">"ఫోన్ వేడెక్కుతోంది"</string>
<string name="high_temp_notif_message" msgid="1277346543068257549">"ఫోన్‌ను చల్లబరిచే క్రమంలో కొన్ని ఫీచర్లు పరిమితం చేయబడ్డాయి.\nమరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
@@ -1141,7 +1144,7 @@
<string name="status_before_loading" msgid="1500477307859631381">"కంటెంట్ త్వరలో కనిపిస్తుంది"</string>
<string name="missed_call" msgid="4228016077700161689">"మిస్డ్ కాల్"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
- <string name="people_tile_description" msgid="8154966188085545556">"ఇటీవలి మెసేజ్‌లు, మిస్డ్ కాల్‌లు, అలాగే స్టేటస్ అప్‌డేట్‌లను చూడండి"</string>
+ <string name="people_tile_description" msgid="8154966188085545556">"ఇటీవలి మెసేజ్‌లు, మిస్డ్ కాల్స్‌, అలాగే స్టేటస్ అప్‌డేట్‌లను చూడండి"</string>
<string name="people_tile_title" msgid="6589377493334871272">"సంభాషణ"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"అంతరాయం కలిగించవద్దు ద్వారా పాజ్ చేయబడింది"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> మెసేజ్‌ను పంపారు: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index e8a6c16d7991..1fd1313719dc 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ไม่รู้จักใบหน้า ใช้ลายนิ้วมือแทน"</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"ใช้ลายนิ้วมือของคุณเพื่อดำเนินการต่อ"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"ไม่รู้จักลายนิ้วมือ ใช้การล็อกหน้าจอแทน"</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"กำลังหาใบหน้าคุณ…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"ไอคอนใบหน้า"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"ปุ่มซูมที่ใช้งานร่วมกันได้"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"แตะอีกครั้งเพื่อเปิด"</string>
<string name="tap_again" msgid="1315420114387908655">"แตะอีกครั้ง"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"เลื่อนขึ้นเพื่อเปิด"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"กดเพื่อเปิด"</string>
<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>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 8d0a8475122c..3837364887cf 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Hindi makilala ang mukha. Gumamit ng fingerprint."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Gamitin ang iyong fingerprint para magpatuloy"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Hindi makilala ang fingerprint. Gamitin na lang ang lock ng screen."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Hinahanap ka…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Face icon"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Button ng zoom ng pagiging tugma."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"I-tap ulit upang buksan"</string>
<string name="tap_again" msgid="1315420114387908655">"I-tap ulit"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Mag-swipe pataas para buksan"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Pindutin para buksan"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Mag-swipe pataas para subukan ulit"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"I-unlock para magamit ang NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Pagmamay-ari ng iyong organisasyon ang device na ito"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 6b55d1c7e1d6..1cd547ca7793 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Yüz tanınamadı. Bunun yerine parmak izi kullanın."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Devam etmek için parmak izinizi kullanın"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Parmak izi tanınamadı. Bunun yerine ekran kilidini kullanın."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Yüzünüz tanınmaya çalışılıyor…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Yüz simgesi"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Uyumluluk zum düğmesi."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Açmak için tekrar dokunun"</string>
<string name="tap_again" msgid="1315420114387908655">"Tekrar dokunun"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Açmak için yukarı kaydırın"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Açmak için basın"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Tekrar denemek için yukarı kaydırın"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC\'yi kullanmak için kilidi açın"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Bu cihaz, kuruluşunuza ait"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 0a5992bf1b48..70922aa77db3 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Обличчя не розпізнано. Скористайтеся відбитком пальця."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Щоб продовжити, скористайтеся відбитком пальця"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Відбиток пальця не розпізнано. Використайте натомість дані для розблокування екрана."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Пошук обличчя…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Значок обличчя"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Кнопка масштабування сумісності."</string>
@@ -456,6 +458,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Торкніться знову, щоб відкрити"</string>
<string name="tap_again" msgid="1315420114387908655">"Натисніть знову"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Проведіть пальцем угору, щоб відкрити"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Натисніть, щоб відкрити"</string>
<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>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 5a96fa876031..7ef014923960 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"چہرے کی شناخت نہیں ہو سکی۔ اس کے بجائے فنگر پرنٹ استعمال کریں۔"</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"جاری رکھنے کے لیے اپنا فنگر پرنٹ استعمال کریں"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"فنگر پرنٹ کی شناخت نہیں کی جا سکی۔ اس کے بجائے اسکرین لاک کا استعمال کریں۔"</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"آپ کے لیے تلاش کیا جا رہا ہے…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"چہرے کا آئیکن"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"مطابقت پذیری زوم بٹن۔"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"کھولنے کیلئے دوبارہ تھپتھپائیں"</string>
<string name="tap_again" msgid="1315420114387908655">"دوبارہ تھپتھپائیں"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"کھولنے کے لیے اوپر سوائپ کريں"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"کھولنے کے لیے دبائیں"</string>
<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>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index d96ea064aaac..08ac980d3bee 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Bu yuz notanish. Barmoq izi orqali urining."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Davom etish uchun barmoq izingizdan foydalaning"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Bu barmoq izi notanish. Ekran qulfi orqali urining."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Yuzingiz tekshirilmoqda…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Yuz belgisi"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Kattalashtirish tugmasi mosligi."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Ochish uchun yana bosing"</string>
<string name="tap_again" msgid="1315420114387908655">"Yana bosing"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Ochish uchun tepaga suring"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Ochish uchun bosing"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Qayta urinish uchun tepaga suring"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC ishlatish uchun qurilma qulfini oching"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Bu qurilma tashkilotingizga tegishli"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 54b49671be36..60b1232cd8a3 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Không thể nhận dạng khuôn mặt. Hãy dùng vân tay."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Hãy dùng vân tay để tiếp tục"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Không thể nhận dạng vân tay. Hãy dùng phương thức khóa màn hình."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Đang tìm kiếm bạn…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Biểu tượng khuôn mặt"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Nút thu phóng khả năng tương thích."</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Nhấn lại để mở"</string>
<string name="tap_again" msgid="1315420114387908655">"Nhấn lại"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Vuốt lên để mở"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Nhấn để mở"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Vuốt lên để thử lại"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Mở khóa để sử dụng NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Thiết bị này thuộc về tổ chức của bạn"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 3cbcf3119437..357e59e7ece5 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"无法识别人脸。请改用指纹。"</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"使用指纹验证身份后才能继续"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"无法识别指纹。请改用屏幕锁定功能。"</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"正在查找您的面孔…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"面孔图标"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"兼容性缩放按钮。"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"再次点按即可打开"</string>
<string name="tap_again" msgid="1315420114387908655">"请再点按一次"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"向上滑动即可打开"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"按一下即可打开"</string>
<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>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 726947ff2e53..f8ede3a55b88 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"無法辨識面孔,請改用指紋完成驗證。"</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"請使用您的指紋繼續"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"無法辨識指紋,請改用螢幕鎖定完成驗證。"</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"正在搜尋您的臉孔…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"面孔圖示"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"相容性縮放按鈕。"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"再次輕按即可開啟"</string>
<string name="tap_again" msgid="1315420114387908655">"再次輕按"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"向上滑動即可開啟"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"按下即可開啟"</string>
<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>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 437bece4a6c3..df84fb0699c9 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"無法辨識臉孔,請改用指紋完成驗證。"</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"使用指紋完成驗證才能繼續操作"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"無法辨識指紋,請改用螢幕鎖定完成驗證。"</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"正在尋找你的臉孔…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"臉孔圖示"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"相容性縮放按鈕。"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"再次輕觸即可開啟"</string>
<string name="tap_again" msgid="1315420114387908655">"再輕觸一次"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"向上滑動即可開啟"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"按下即可開啟"</string>
<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>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 6b7d577e3db9..fe97daa7682e 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -184,6 +184,8 @@
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ayibazi ubuso. Sebenzisa izigxivizo zeminwe kunalokho."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"Sebenzisa izigxivizo zakho zeminwe ukuze uqhubeke"</string>
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock" msgid="4805522676254378353">"Ayizazi izigxivizo zeminwe. Sebenzisa ukukhiya isikrini kunalokho."</string>
+ <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
+ <skip />
<string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Kufunwa wena…"</string>
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Isithonjana sobuso"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Inkinobho evumelekile yokusondeza"</string>
@@ -452,6 +454,7 @@
<string name="notification_tap_again" msgid="4477318164947497249">"Thepha futhi ukuze uvule"</string>
<string name="tap_again" msgid="1315420114387908655">"Thepha futhi"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Swayiphela phezulu ukuze uvule"</string>
+ <string name="keyguard_unlock_press" msgid="8488350566398524740">"Chofoza ukuze uvule"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Swayiphela phezulu ukuze uzame futhi"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Vula ukuze usebenzise i-NFC"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Le divayisi eyenhlangano yakho"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index d664ddabd3f4..dc5c472ea0ed 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -110,7 +110,7 @@
<!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
<string name="quick_settings_tiles_stock" translatable="false">
- internet,wifi,cell,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness
+ internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness
</string>
<!-- The tiles to display in QuickSettings -->
@@ -671,4 +671,7 @@
1 - Override the setting to always bypass keyguard
2 - Override the setting to never bypass keyguard -->
<integer name="config_face_unlock_bypass_override">0</integer>
+
+ <!-- Flag to activate notification to contents feature -->
+ <bool name="config_notificationToContents">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 2ee0026d2e01..307da67e8ea4 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -538,6 +538,9 @@
<!-- Gravity for the notification panel -->
<integer name="notification_panel_layout_gravity">0x31</integer><!-- center_horizontal|top -->
+ <!-- Padding for the lock icon on the keyguard. In pixels - should not scale with display size. -->
+ <dimen name="lock_icon_padding">48px</dimen>
+
<!-- Height of the carrier/wifi name label -->
<dimen name="carrier_label_height">24dp</dimen>
@@ -1591,4 +1594,6 @@
<!-- The padding between the icon and the text. -->
<dimen name="ongoing_call_chip_icon_text_padding">4dp</dimen>
<dimen name="ongoing_call_chip_corner_radius">28dp</dimen>
+
+ <dimen name="drag_and_drop_icon_size">70dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 62688ca590c9..47f474061301 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -438,6 +438,8 @@
<string name="fingerprint_dialog_use_fingerprint">Use your fingerprint to continue</string>
<!-- Message shown to ask the user to use screenlock to continue.[CHAR LIMIT=NONE] -->
<string name="fingerprint_dialog_cant_recognize_fp_use_screenlock">Can\u2019t recognize fingerprint. Use screen lock instead.</string>
+ <!-- Message shown to inform the user a face cannot be recognized and fingerprint should instead be used.[CHAR LIMIT=50] -->
+ <string name="keyguard_face_failed_use_fp">@string/fingerprint_dialog_use_fingerprint_instead</string>
<!-- Message shown when the system-provided face dialog is shown, asking for authentication [CHAR LIMIT=30] -->
<string name="face_dialog_looking_for_face">Looking for you\u2026</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
index 442716878af4..b82d896e6bea 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
@@ -80,8 +80,7 @@ public final class InteractionJankMonitorWrapper {
public static void begin(View v, @CujType int cujType, long timeout) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return;
Configuration.Builder builder =
- new Configuration.Builder(cujType)
- .setView(v)
+ Configuration.Builder.withView(cujType, v)
.setTimeout(timeout);
InteractionJankMonitor.getInstance().begin(builder);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index 2407d216b4ab..23a365a1acef 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -68,6 +68,7 @@ public class RemoteAnimationTargetCompat {
public final boolean isNotInRecents;
public final Rect contentInsets;
public final ActivityManager.RunningTaskInfo taskInfo;
+ public final boolean allowEnterPip;
public final int rotationChange;
public final int windowType;
@@ -88,6 +89,7 @@ public class RemoteAnimationTargetCompat {
contentInsets = app.contentInsets;
activityType = app.windowConfiguration.getActivityType();
taskInfo = app.taskInfo;
+ allowEnterPip = app.allowEnterPip;
rotationChange = 0;
mStartLeash = app.startLeash;
@@ -214,6 +216,7 @@ public class RemoteAnimationTargetCompat {
activityType = ACTIVITY_TYPE_UNDEFINED;
}
taskInfo = change.getTaskInfo();
+ allowEnterPip = false; /* always false in shell-transition case */
mStartLeash = null;
rotationChange = change.getEndRotation() - change.getStartRotation();
windowType = INVALID_WINDOW_TYPE;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 9e456cf55500..27b6182d1aa2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -17,13 +17,13 @@
package com.android.keyguard;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
import android.app.WallpaperManager;
import android.text.TextUtils;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
@@ -93,8 +93,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
private final ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
- // If set, will replace keyguard_status_area
- private View mSmartspaceView;
+ private ViewGroup mSmartspaceContainer;
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private SmartspaceTransitionController mSmartspaceTransitionController;
@@ -139,6 +138,8 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mClockFrame = mView.findViewById(R.id.lockscreen_clock_view);
mLargeClockFrame = mView.findViewById(R.id.lockscreen_clock_view_large);
+ mSmartspaceContainer = mView.findViewById(R.id.keyguard_smartspace_container);
+ mSmartspaceController.setKeyguardStatusContainer(mSmartspaceContainer);
mClockViewController =
new AnimatableClockController(
@@ -170,35 +171,25 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mView.updateColors(getGradientColors());
updateAodIcons();
- if (mSmartspaceController.isEnabled()) {
- mSmartspaceView = mSmartspaceController.buildAndConnectView(mView);
+ if (mSmartspaceController.isSmartspaceEnabled()) {
+ // "Enabled" doesn't mean smartspace is displayed here - inside mSmartspaceContainer -
+ // it might be a part of another view when in split shade. But it means that it CAN be
+ // displayed here, so we want to hide keyguard_status_area and set views relations
+ // accordingly.
View ksa = mView.findViewById(R.id.keyguard_status_area);
- int ksaIndex = mView.indexOfChild(ksa);
+ // we show either keyguard_status_area or smartspace, so when smartspace can be visible,
+ // keyguard_status_area should be hidden
ksa.setVisibility(View.GONE);
- // Place smartspace view below normal clock...
- RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
- MATCH_PARENT, WRAP_CONTENT);
- lp.addRule(RelativeLayout.BELOW, R.id.lockscreen_clock_view);
-
- mView.addView(mSmartspaceView, ksaIndex, lp);
- int startPadding = getContext().getResources()
- .getDimensionPixelSize(R.dimen.below_clock_padding_start);
- int endPadding = getContext().getResources()
- .getDimensionPixelSize(R.dimen.below_clock_padding_end);
- mSmartspaceView.setPaddingRelative(startPadding, 0, endPadding, 0);
-
updateClockLayout();
- View nic = mView.findViewById(
- R.id.left_aligned_notification_icon_container);
- lp = (RelativeLayout.LayoutParams) nic.getLayoutParams();
- lp.addRule(RelativeLayout.BELOW, mSmartspaceView.getId());
+ View nic = mView.findViewById(R.id.left_aligned_notification_icon_container);
+ RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) nic.getLayoutParams();
+ lp.addRule(RelativeLayout.BELOW, mSmartspaceContainer.getId());
nic.setLayoutParams(lp);
-
- mView.setSmartspaceView(mSmartspaceView);
- mSmartspaceTransitionController.setLockscreenSmartspace(mSmartspaceView);
+ mView.setSmartspaceView(mSmartspaceContainer);
+ mSmartspaceTransitionController.setLockscreenSmartspace(mSmartspaceContainer);
}
}
@@ -221,10 +212,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
// instance of this class. In order to fix this, we need to modify the plugin so that
// (a) we get a new view each time and (b) we can properly clean up an old view by making
// it unregister itself as a plugin listener.
- if (mSmartspaceView != null) {
- mView.removeView(mSmartspaceView);
- mSmartspaceView = null;
- }
+ mSmartspaceContainer.removeAllViews();
}
/**
@@ -237,7 +225,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
}
private void updateClockLayout() {
- if (mSmartspaceController.isEnabled()) {
+ if (mSmartspaceController.isSmartspaceEnabled()) {
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(MATCH_PARENT,
MATCH_PARENT);
lp.topMargin = getContext().getResources().getDimensionPixelSize(
@@ -302,8 +290,8 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
PropertyAnimator.setProperty(mLargeClockFrame, AnimatableProperty.SCALE_Y,
scale, props, animate);
- if (mSmartspaceView != null) {
- PropertyAnimator.setProperty(mSmartspaceView, AnimatableProperty.TRANSLATION_X,
+ if (mSmartspaceContainer != null) {
+ PropertyAnimator.setProperty(mSmartspaceContainer, AnimatableProperty.TRANSLATION_X,
x, props, animate);
// If we're unlocking with the SmartSpace shared element transition, let the controller
@@ -321,8 +309,8 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
public void setChildrenAlphaExcludingSmartspace(float alpha) {
final Set<View> excludedViews = new HashSet<>();
- if (mSmartspaceView != null) {
- excludedViews.add(mSmartspaceView);
+ if (mSmartspaceContainer != null) {
+ excludedViews.add(mSmartspaceContainer);
}
setChildrenAlphaExcluding(alpha, excludedViews);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index 97d3a5a4cd18..75425e1e6ca3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -28,6 +28,7 @@ import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -166,6 +167,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
private final TelephonyManager mTelephonyManager;
private final EmergencyButtonController.Factory mEmergencyButtonControllerFactory;
private final FalsingCollector mFalsingCollector;
+ private final DevicePostureController mDevicePostureController;
@Inject
public Factory(KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -175,7 +177,8 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
InputMethodManager inputMethodManager, @Main DelayableExecutor mainExecutor,
@Main Resources resources, LiftToActivateListener liftToActivateListener,
TelephonyManager telephonyManager, FalsingCollector falsingCollector,
- EmergencyButtonController.Factory emergencyButtonControllerFactory) {
+ EmergencyButtonController.Factory emergencyButtonControllerFactory,
+ DevicePostureController devicePostureController) {
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
mLatencyTracker = latencyTracker;
@@ -187,6 +190,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
mTelephonyManager = telephonyManager;
mEmergencyButtonControllerFactory = emergencyButtonControllerFactory;
mFalsingCollector = falsingCollector;
+ mDevicePostureController = devicePostureController;
}
/** Create a new {@link KeyguardInputViewController}. */
@@ -200,7 +204,8 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
return new KeyguardPatternViewController((KeyguardPatternView) keyguardInputView,
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
keyguardSecurityCallback, mLatencyTracker, mFalsingCollector,
- emergencyButtonController, mMessageAreaControllerFactory);
+ emergencyButtonController, mMessageAreaControllerFactory,
+ mDevicePostureController);
} else if (keyguardInputView instanceof KeyguardPasswordView) {
return new KeyguardPasswordViewController((KeyguardPasswordView) keyguardInputView,
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
@@ -212,7 +217,8 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
return new KeyguardPinViewController((KeyguardPINView) keyguardInputView,
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
- mLiftToActivateListener, emergencyButtonController, mFalsingCollector);
+ mLiftToActivateListener, emergencyButtonController, mFalsingCollector,
+ mDevicePostureController);
} else if (keyguardInputView instanceof KeyguardSimPinView) {
return new KeyguardSimPinViewController((KeyguardSimPinView) keyguardInputView,
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 82ade7aa1806..1efda7edee2f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -16,19 +16,23 @@
package com.android.keyguard;
+import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED;
+import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN;
+
import android.content.Context;
import android.content.res.Configuration;
import android.util.AttributeSet;
import android.view.View;
-import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.constraintlayout.widget.ConstraintSet;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.settingslib.animation.DisappearAnimationUtils;
import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.DevicePostureController.DevicePostureInt;
/**
* Displays a PIN pad for unlocking.
@@ -38,9 +42,10 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
private final AppearAnimationUtils mAppearAnimationUtils;
private final DisappearAnimationUtils mDisappearAnimationUtils;
private final DisappearAnimationUtils mDisappearAnimationUtilsLocked;
- private ViewGroup mContainer;
+ private ConstraintLayout mContainer;
private int mDisappearYTranslation;
private View[][] mViews;
+ @DevicePostureInt private int mLastDevicePosture = DEVICE_POSTURE_UNKNOWN;
public KeyguardPINView(Context context) {
this(context, null);
@@ -67,6 +72,11 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
updateMargins();
}
+ void onDevicePostureChanged(@DevicePostureInt int posture) {
+ mLastDevicePosture = posture;
+ updateMargins();
+ }
+
@Override
protected void resetState() {
}
@@ -109,6 +119,16 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
key.setLayoutParams(lp);
}
}
+
+ // Update the guideline based on the device posture...
+ float halfOpenPercentage =
+ mContext.getResources().getFloat(R.dimen.half_opened_bouncer_height_ratio);
+
+ ConstraintSet cs = new ConstraintSet();
+ cs.clone(mContainer);
+ cs.setGuidelinePercent(R.id.pin_pad_top_guideline,
+ mLastDevicePosture == DEVICE_POSTURE_HALF_OPENED ? halfOpenPercentage : 0.0f);
+ cs.applyTo(mContainer);
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 90c1e402d248..3a3d30861132 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -209,6 +209,11 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView {
@Override
public void onCancelled(
@Nullable WindowInsetsAnimationController controller) {
+ // It is possible to be denied control of ime insets, which means onReady
+ // is never called. We still need to notify the runnables in order to
+ // complete the bouncer disappearing
+ runOnFinishImeAnimationRunnable();
+ finishRunnable.run();
}
});
return true;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 98e7fb48b7a6..a35aedf6f503 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -15,6 +15,8 @@
*/
package com.android.keyguard;
+import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED;
+
import android.content.Context;
import android.graphics.Rect;
import android.os.SystemClock;
@@ -22,16 +24,19 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.constraintlayout.widget.ConstraintSet;
+
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.widget.LockPatternView;
import com.android.settingslib.animation.AppearAnimationCreator;
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.settingslib.animation.DisappearAnimationUtils;
import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.DevicePostureController.DevicePostureInt;
public class KeyguardPatternView extends KeyguardInputView
implements AppearAnimationCreator<LockPatternView.CellState> {
@@ -68,7 +73,7 @@ public class KeyguardPatternView extends KeyguardInputView
KeyguardMessageArea mSecurityMessageDisplay;
private View mEcaView;
- private ViewGroup mContainer;
+ private ConstraintLayout mContainer;
public KeyguardPatternView(Context context) {
this(context, null);
@@ -90,6 +95,18 @@ public class KeyguardPatternView extends KeyguardInputView
mContext, android.R.interpolator.fast_out_linear_in));
}
+ void onDevicePostureChanged(@DevicePostureInt int posture) {
+ // Update the guideline based on the device posture...
+ float halfOpenPercentage =
+ mContext.getResources().getFloat(R.dimen.half_opened_bouncer_height_ratio);
+
+ ConstraintSet cs = new ConstraintSet();
+ cs.clone(mContainer);
+ cs.setGuidelinePercent(R.id.pin_pad_top_guideline, posture == DEVICE_POSTURE_HALF_OPENED
+ ? halfOpenPercentage : 0.0f);
+ cs.applyTo(mContainer);
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index d5be7bacaadc..94e07b713915 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -38,6 +38,7 @@ import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingClassifier;
import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.statusbar.policy.DevicePostureController;
import java.util.List;
@@ -56,6 +57,9 @@ public class KeyguardPatternViewController
private final FalsingCollector mFalsingCollector;
private final EmergencyButtonController mEmergencyButtonController;
private final KeyguardMessageAreaController.Factory mMessageAreaControllerFactory;
+ private final DevicePostureController mPostureController;
+ private final DevicePostureController.Callback mPostureCallback =
+ posture -> mView.onDevicePostureChanged(posture);
private KeyguardMessageAreaController mMessageAreaController;
private LockPatternView mLockPatternView;
@@ -192,7 +196,8 @@ public class KeyguardPatternViewController
LatencyTracker latencyTracker,
FalsingCollector falsingCollector,
EmergencyButtonController emergencyButtonController,
- KeyguardMessageAreaController.Factory messageAreaControllerFactory) {
+ KeyguardMessageAreaController.Factory messageAreaControllerFactory,
+ DevicePostureController postureController) {
super(view, securityMode, keyguardSecurityCallback, emergencyButtonController);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
@@ -203,6 +208,7 @@ public class KeyguardPatternViewController
KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView);
mMessageAreaController = mMessageAreaControllerFactory.create(kma);
mLockPatternView = mView.findViewById(R.id.lockPatternView);
+ mPostureController = postureController;
}
@Override
@@ -235,6 +241,7 @@ public class KeyguardPatternViewController
getKeyguardSecurityCallback().onCancelClicked();
});
}
+ mPostureController.addCallback(mPostureCallback);
}
@Override
@@ -247,6 +254,7 @@ public class KeyguardPatternViewController
if (cancelBtn != null) {
cancelBtn.setOnClickListener(null);
}
+ mPostureController.removeCallback(mPostureCallback);
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
index 262bed3f695c..9f4585fb1a92 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
@@ -23,10 +23,14 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.statusbar.policy.DevicePostureController;
public class KeyguardPinViewController
extends KeyguardPinBasedInputViewController<KeyguardPINView> {
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final DevicePostureController mPostureController;
+ private final DevicePostureController.Callback mPostureCallback = posture ->
+ mView.onDevicePostureChanged(posture);
protected KeyguardPinViewController(KeyguardPINView view,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -35,11 +39,13 @@ public class KeyguardPinViewController
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener,
EmergencyButtonController emergencyButtonController,
- FalsingCollector falsingCollector) {
+ FalsingCollector falsingCollector,
+ DevicePostureController postureController) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
messageAreaControllerFactory, latencyTracker, liftToActivateListener,
emergencyButtonController, falsingCollector);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mPostureController = postureController;
}
@Override
@@ -53,6 +59,14 @@ public class KeyguardPinViewController
getKeyguardSecurityCallback().onCancelClicked();
});
}
+
+ mPostureController.addCallback(mPostureCallback);
+ }
+
+ @Override
+ protected void onViewDetached() {
+ super.onViewDetached();
+ mPostureController.removeCallback(mPostureCallback);
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index bd0d0682b74b..6908409cdeac 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -103,10 +103,10 @@ 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.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.telephony.TelephonyListenerManager;
@@ -347,13 +347,16 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private static final int HAL_ERROR_RETRY_TIMEOUT = 500; // ms
private static final int HAL_ERROR_RETRY_MAX = 20;
- private final Runnable mCancelNotReceived = new Runnable() {
- @Override
- public void run() {
- Log.w(TAG, "Cancel not received, transitioning to STOPPED");
- mFingerprintRunningState = mFaceRunningState = BIOMETRIC_STATE_STOPPED;
- updateBiometricListeningState();
- }
+ private final Runnable mFpCancelNotReceived = () -> {
+ Log.e(TAG, "Fp cancellation not received, transitioning to STOPPED");
+ mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
+ updateFingerprintListeningState();
+ };
+
+ private final Runnable mFaceCancelNotReceived = () -> {
+ Log.e(TAG, "Face cancellation not received, transitioning to STOPPED");
+ mFaceRunningState = BIOMETRIC_STATE_STOPPED;
+ updateFaceListeningState();
};
private final Handler mHandler;
@@ -791,19 +794,19 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private void handleFingerprintError(int msgId, String errString) {
Assert.isMainThread();
- if (msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED && mHandler.hasCallbacks(
- mCancelNotReceived)) {
- mHandler.removeCallbacks(mCancelNotReceived);
+ if (mHandler.hasCallbacks(mFpCancelNotReceived)) {
+ mHandler.removeCallbacks(mFpCancelNotReceived);
}
+ // Error is always the end of authentication lifecycle.
+ mFingerprintCancelSignal = null;
+
if (msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED
&& mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
updateFingerprintListeningState();
} else {
setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
- mFingerprintCancelSignal = null;
- mFaceCancelSignal = null;
}
if (msgId == FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE) {
@@ -905,6 +908,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private void handleFaceAuthFailed() {
Assert.isMainThread();
+ mFaceCancelSignal = null;
setFaceRunningState(BIOMETRIC_STATE_STOPPED);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -983,10 +987,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private void handleFaceError(int msgId, String errString) {
Assert.isMainThread();
if (DEBUG_FACE) Log.d(TAG, "Face error received: " + errString);
- if (msgId == FaceManager.FACE_ERROR_CANCELED && mHandler.hasCallbacks(mCancelNotReceived)) {
- mHandler.removeCallbacks(mCancelNotReceived);
+ if (mHandler.hasCallbacks(mFaceCancelNotReceived)) {
+ mHandler.removeCallbacks(mFaceCancelNotReceived);
}
+ // Error is always the end of authentication lifecycle
+ mFaceCancelSignal = null;
+
if (msgId == FaceManager.FACE_ERROR_CANCELED
&& mFaceRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
setFaceRunningState(BIOMETRIC_STATE_STOPPED);
@@ -2368,6 +2375,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
private void startListeningForFingerprint() {
+ final int userId = getCurrentUser();
+ final boolean unlockPossible = isUnlockWithFingerprintPossible(userId);
+ if (mFingerprintCancelSignal != null) {
+ Log.e(TAG, "Cancellation signal is not null, high chance of bug in fp auth lifecycle"
+ + " management. FP state: " + mFingerprintRunningState
+ + ", unlockPossible: " + unlockPossible);
+ }
+
if (mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING) {
setFingerprintRunningState(BIOMETRIC_STATE_CANCELLING_RESTARTING);
return;
@@ -2377,11 +2392,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
return;
}
if (DEBUG) Log.v(TAG, "startListeningForFingerprint()");
- int userId = getCurrentUser();
- if (isUnlockWithFingerprintPossible(userId)) {
- if (mFingerprintCancelSignal != null) {
- mFingerprintCancelSignal.cancel();
- }
+
+ if (unlockPossible) {
mFingerprintCancelSignal = new CancellationSignal();
if (isEncryptedOrLockdown(userId)) {
@@ -2397,6 +2409,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
private void startListeningForFace() {
+ final int userId = getCurrentUser();
+ final boolean unlockPossible = isUnlockWithFacePossible(userId);
+ if (mFaceCancelSignal != null) {
+ Log.e(TAG, "Cancellation signal is not null, high chance of bug in face auth lifecycle"
+ + " management. Face state: " + mFaceRunningState
+ + ", unlockPossible: " + unlockPossible);
+ }
+
if (mFaceRunningState == BIOMETRIC_STATE_CANCELLING) {
setFaceRunningState(BIOMETRIC_STATE_CANCELLING_RESTARTING);
return;
@@ -2405,11 +2425,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
return;
}
if (DEBUG) Log.v(TAG, "startListeningForFace(): " + mFaceRunningState);
- int userId = getCurrentUser();
- if (isUnlockWithFacePossible(userId)) {
- if (mFaceCancelSignal != null) {
- mFaceCancelSignal.cancel();
- }
+
+ if (unlockPossible) {
mFaceCancelSignal = new CancellationSignal();
// This would need to be updated for multi-sensor devices
@@ -2461,9 +2478,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
if (mFingerprintCancelSignal != null) {
mFingerprintCancelSignal.cancel();
mFingerprintCancelSignal = null;
- if (!mHandler.hasCallbacks(mCancelNotReceived)) {
- mHandler.postDelayed(mCancelNotReceived, DEFAULT_CANCEL_SIGNAL_TIMEOUT);
- }
+ mHandler.removeCallbacks(mFpCancelNotReceived);
+ mHandler.postDelayed(mFpCancelNotReceived, DEFAULT_CANCEL_SIGNAL_TIMEOUT);
}
setFingerprintRunningState(BIOMETRIC_STATE_CANCELLING);
}
@@ -2478,9 +2494,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
if (mFaceCancelSignal != null) {
mFaceCancelSignal.cancel();
mFaceCancelSignal = null;
- if (!mHandler.hasCallbacks(mCancelNotReceived)) {
- mHandler.postDelayed(mCancelNotReceived, DEFAULT_CANCEL_SIGNAL_TIMEOUT);
- }
+ mHandler.removeCallbacks(mFaceCancelNotReceived);
+ mHandler.postDelayed(mFaceCancelNotReceived, DEFAULT_CANCEL_SIGNAL_TIMEOUT);
}
setFaceRunningState(BIOMETRIC_STATE_CANCELLING);
}
@@ -2842,6 +2857,11 @@ 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/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 4317e258d8f7..509ac8a6d9fe 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -514,7 +514,15 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
if (!wasClickableOnDownEvent()) {
return false;
}
+ onAffordanceClick();
+ return true;
+ }
+ public boolean onFling(MotionEvent e1, MotionEvent e2,
+ float velocityX, float velocityY) {
+ if (!wasClickableOnDownEvent()) {
+ return false;
+ }
onAffordanceClick();
return true;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java
index a6725234e4af..fc14b6a99008 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java
@@ -18,6 +18,7 @@ package com.android.keyguard.dagger;
import com.android.keyguard.CarrierText;
import com.android.systemui.R;
+import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
import dagger.Module;
@@ -31,4 +32,11 @@ public abstract class KeyguardStatusBarViewModule {
static CarrierText getCarrierText(KeyguardStatusBarView view) {
return view.findViewById(R.id.keyguard_carrier_text);
}
+
+ /** */
+ @Provides
+ @KeyguardStatusBarViewScope
+ static BatteryMeterView getBatteryMeterView(KeyguardStatusBarView view) {
+ return view.findViewById(R.id.battery);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index f8c57bfc9292..e51de66dc2b8 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -47,6 +47,7 @@ import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
@@ -72,7 +73,6 @@ import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index affad7a57d86..b126cddf8eec 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -25,6 +25,8 @@ import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.Notification;
+import android.app.PendingIntent;
import android.content.res.Resources;
import android.graphics.RectF;
import android.os.Handler;
@@ -73,6 +75,9 @@ public class SwipeHelper implements Gefingerpoken {
private final FlingAnimationUtils mFlingAnimationUtils;
private float mPagingTouchSlop;
private final float mSlopMultiplier;
+ private int mTouchSlop;
+ private float mTouchSlopMultiplier;
+
private final Callback mCallback;
private final int mSwipeDirection;
private final VelocityTracker mVelocityTracker;
@@ -105,6 +110,10 @@ public class SwipeHelper implements Gefingerpoken {
final int y = (int) mDownLocation[1] - mViewOffset[1];
mTouchedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
((ExpandableNotificationRow) mTouchedView).doLongClickCallback(x, y);
+
+ if (isAvailableToDragAndDrop(mTouchedView)) {
+ mCallback.onLongPressSent(mTouchedView);
+ }
}
}
}
@@ -126,6 +135,8 @@ public class SwipeHelper implements Gefingerpoken {
mVelocityTracker = VelocityTracker.obtain();
mPagingTouchSlop = viewConfiguration.getScaledPagingTouchSlop();
mSlopMultiplier = viewConfiguration.getScaledAmbiguousGestureMultiplier();
+ mTouchSlop = viewConfiguration.getScaledTouchSlop();
+ mTouchSlopMultiplier = viewConfiguration.getAmbiguousGestureMultiplier();
// Extra long-press!
mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f);
@@ -297,7 +308,9 @@ public class SwipeHelper implements Gefingerpoken {
mIsSwiping = false;
mSnappingChild = false;
mLongPressSent = false;
+ mCallback.onLongPressSent(null);
mVelocityTracker.clear();
+ cancelLongPress();
mTouchedView = mCallback.getChildAtPosition(ev);
if (mTouchedView != null) {
@@ -349,6 +362,7 @@ public class SwipeHelper implements Gefingerpoken {
mIsSwiping = false;
mTouchedView = null;
mLongPressSent = false;
+ mCallback.onLongPressSent(null);
mMenuRowIntercepting = false;
cancelLongPress();
if (captured) return true;
@@ -593,11 +607,7 @@ public class SwipeHelper implements Gefingerpoken {
@Override
public boolean onTouchEvent(MotionEvent ev) {
- if (mLongPressSent && !mMenuRowIntercepting) {
- return true;
- }
-
- if (!mIsSwiping && !mMenuRowIntercepting) {
+ if (!mIsSwiping && !mMenuRowIntercepting && !mLongPressSent) {
if (mCallback.getChildAtPosition(ev) != null) {
// We are dragging directly over a card, make sure that we also catch the gesture
// even if nobody else wants the touch event.
@@ -623,30 +633,40 @@ public class SwipeHelper implements Gefingerpoken {
if (absDelta >= getFalsingThreshold()) {
mTouchAboveFalsingThreshold = true;
}
- // don't let items that can't be dismissed be dragged more than
- // maxScrollDistance
- if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissedInDirection(
- mTouchedView,
- delta > 0)) {
- float size = getSize(mTouchedView);
- float maxScrollDistance = MAX_SCROLL_SIZE_FRACTION * size;
- if (absDelta >= size) {
- delta = delta > 0 ? maxScrollDistance : -maxScrollDistance;
- } else {
- int startPosition = mCallback.getConstrainSwipeStartPosition();
- if (absDelta > startPosition) {
- int signedStartPosition =
- (int) (startPosition * Math.signum(delta));
- delta = signedStartPosition
- + maxScrollDistance * (float) Math.sin(
- ((delta - signedStartPosition) / size) * (Math.PI / 2));
+
+ if (mLongPressSent) {
+ if (absDelta >= getTouchSlop(ev)) {
+ if (mTouchedView instanceof ExpandableNotificationRow) {
+ ((ExpandableNotificationRow) mTouchedView)
+ .doDragCallback(ev.getX(), ev.getY());
+ }
+ }
+ } else {
+ // don't let items that can't be dismissed be dragged more than
+ // maxScrollDistance
+ if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissedInDirection(
+ mTouchedView,
+ delta > 0)) {
+ float size = getSize(mTouchedView);
+ float maxScrollDistance = MAX_SCROLL_SIZE_FRACTION * size;
+ if (absDelta >= size) {
+ delta = delta > 0 ? maxScrollDistance : -maxScrollDistance;
+ } else {
+ int startPosition = mCallback.getConstrainSwipeStartPosition();
+ if (absDelta > startPosition) {
+ int signedStartPosition =
+ (int) (startPosition * Math.signum(delta));
+ delta = signedStartPosition
+ + maxScrollDistance * (float) Math.sin(
+ ((delta - signedStartPosition) / size) * (Math.PI / 2));
+ }
}
}
- }
- setTranslation(mTouchedView, mTranslation + delta);
- updateSwipeProgressFromOffset(mTouchedView, mCanCurrViewBeDimissed);
- onMoveUpdate(mTouchedView, ev, mTranslation + delta, delta);
+ setTranslation(mTouchedView, mTranslation + delta);
+ updateSwipeProgressFromOffset(mTouchedView, mCanCurrViewBeDimissed);
+ onMoveUpdate(mTouchedView, ev, mTranslation + delta, delta);
+ }
}
break;
case MotionEvent.ACTION_UP:
@@ -747,6 +767,29 @@ public class SwipeHelper implements Gefingerpoken {
mIsSwiping = false;
}
+ private float getTouchSlop(MotionEvent event) {
+ // Adjust the touch slop if another gesture may be being performed.
+ return event.getClassification() == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE
+ ? mTouchSlop * mTouchSlopMultiplier
+ : mTouchSlop;
+ }
+
+ private boolean isAvailableToDragAndDrop(View v) {
+ if (v.getResources().getBoolean(R.bool.config_notificationToContents)) {
+ if (v instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow enr = (ExpandableNotificationRow) v;
+ boolean canBubble = enr.getEntry().canBubble();
+ Notification notif = enr.getEntry().getSbn().getNotification();
+ PendingIntent dragIntent = notif.contentIntent != null ? notif.contentIntent
+ : notif.fullScreenIntent;
+ if (dragIntent != null && dragIntent.isActivity() && !canBubble) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
public interface Callback {
View getChildAtPosition(MotionEvent ev);
@@ -771,6 +814,13 @@ public class SwipeHelper implements Gefingerpoken {
void onDragCancelled(View v);
/**
+ * Called when the child is long pressed and available to start drag and drop.
+ *
+ * @param v the view that was long pressed.
+ */
+ void onLongPressSent(View v);
+
+ /**
* Called when the child is snapped to a position.
*
* @param animView the view that was snapped.
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
index 9e764920b13f..a7c120e7cc84 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,12 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui;
+package com.android.systemui.battery;
import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
import static com.android.systemui.DejankUtils.whitelistIpcs;
-import static com.android.systemui.util.SysuiLifecycle.viewAttachLifecycle;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -36,12 +35,10 @@ import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
import android.text.TextUtils;
-import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
-import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -50,18 +47,16 @@ import android.widget.TextView;
import androidx.annotation.StyleRes;
import com.android.settingslib.graph.ThemedBatteryDrawable;
+import com.android.systemui.Dependency;
+import com.android.systemui.DualToneHandler;
+import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.settings.CurrentUserTracker;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.tuner.TunerService.Tunable;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -69,8 +64,7 @@ import java.lang.annotation.Retention;
import java.text.NumberFormat;
public class BatteryMeterView extends LinearLayout implements
- BatteryStateChangeCallback, Tunable, DarkReceiver, ConfigurationListener {
-
+ BatteryStateChangeCallback, DarkReceiver {
@Retention(SOURCE)
@IntDef({MODE_DEFAULT, MODE_ON, MODE_OFF, MODE_ESTIMATE})
@@ -81,7 +75,6 @@ public class BatteryMeterView extends LinearLayout implements
public static final int MODE_ESTIMATE = 3;
private final ThemedBatteryDrawable mDrawable;
- private final String mSlotBattery;
private final ImageView mBatteryIconView;
private final CurrentUserTracker mUserTracker;
private TextView mBatteryPercentView;
@@ -93,9 +86,6 @@ public class BatteryMeterView extends LinearLayout implements
private int mLevel;
private int mShowPercentMode = MODE_DEFAULT;
private boolean mShowPercentAvailable;
- // Some places may need to show the battery conditionally, and not obey the tuner
- private boolean mIgnoreTunerUpdates;
- private boolean mIsSubscribedForTunerUpdates;
private boolean mCharging;
// Error state where we know nothing about the current battery state
private boolean mBatteryStateUnknown;
@@ -134,8 +124,6 @@ public class BatteryMeterView extends LinearLayout implements
setupLayoutTransition();
- mSlotBattery = context.getString(
- com.android.internal.R.string.status_bar_battery);
mBatteryIconView = new ImageView(context);
mBatteryIconView.setImageDrawable(mDrawable);
final MarginLayoutParams mlp = new MarginLayoutParams(
@@ -164,7 +152,6 @@ public class BatteryMeterView extends LinearLayout implements
setClipChildren(false);
setClipToPadding(false);
- Dependency.get(ConfigurationController.class).observe(viewAttachLifecycle(this), this);
}
private void setupLayoutTransition() {
@@ -201,44 +188,6 @@ public class BatteryMeterView extends LinearLayout implements
updateShowPercent();
}
- /**
- * Set {@code true} to turn off BatteryMeterView's subscribing to the tuner for updates, and
- * thus avoid it controlling its own visibility
- *
- * @param ignore whether to ignore the tuner or not
- */
- public void setIgnoreTunerUpdates(boolean ignore) {
- mIgnoreTunerUpdates = ignore;
- updateTunerSubscription();
- }
-
- private void updateTunerSubscription() {
- if (mIgnoreTunerUpdates) {
- unsubscribeFromTunerUpdates();
- } else {
- subscribeForTunerUpdates();
- }
- }
-
- private void subscribeForTunerUpdates() {
- if (mIsSubscribedForTunerUpdates || mIgnoreTunerUpdates) {
- return;
- }
-
- Dependency.get(TunerService.class)
- .addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
- mIsSubscribedForTunerUpdates = true;
- }
-
- private void unsubscribeFromTunerUpdates() {
- if (!mIsSubscribedForTunerUpdates) {
- return;
- }
-
- Dependency.get(TunerService.class).removeTunable(this);
- mIsSubscribedForTunerUpdates = false;
- }
-
public void setColorsFromContext(Context context) {
if (context == null) {
return;
@@ -253,15 +202,6 @@ public class BatteryMeterView extends LinearLayout implements
}
@Override
- public void onTuningChanged(String key, String newValue) {
- if (StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
- ArraySet<String> icons = StatusBarIconController.getIconHideList(
- getContext(), newValue);
- setVisibility(icons.contains(mSlotBattery) ? View.GONE : View.VISIBLE);
- }
- }
-
- @Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
mBatteryController = Dependency.get(BatteryController.class);
@@ -273,7 +213,6 @@ public class BatteryMeterView extends LinearLayout implements
Settings.Global.getUriFor(Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME),
false, mSettingObserver);
updateShowPercent();
- subscribeForTunerUpdates();
mUserTracker.startTracking();
}
@@ -283,7 +222,6 @@ public class BatteryMeterView extends LinearLayout implements
mUserTracker.stopTracking();
mBatteryController.removeCallback(this);
getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
- unsubscribeFromTunerUpdates();
}
@Override
@@ -395,11 +333,6 @@ public class BatteryMeterView extends LinearLayout implements
}
}
- @Override
- public void onDensityOrFontScaleChanged() {
- scaleBatteryMeterViews();
- }
-
private Drawable getUnknownStateDrawable() {
if (mUnknownStateDrawable == null) {
mUnknownStateDrawable = mContext.getDrawable(R.drawable.ic_battery_unknown);
@@ -429,7 +362,7 @@ public class BatteryMeterView extends LinearLayout implements
/**
* Looks up the scale factor for status bar icons and scales the battery view by that amount.
*/
- private void scaleBatteryMeterViews() {
+ void scaleBatteryMeterViews() {
Resources res = getContext().getResources();
TypedValue typedValue = new TypedValue();
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
new file mode 100644
index 000000000000..e2d88497a86b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.battery;
+
+import android.util.ArraySet;
+import android.view.View;
+
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.util.ViewController;
+
+import javax.inject.Inject;
+
+/** Controller for {@link BatteryMeterView}. **/
+public class BatteryMeterViewController extends ViewController<BatteryMeterView> {
+ private final ConfigurationController mConfigurationController;
+ private final TunerService mTunerService;
+
+ private final String mSlotBattery;
+
+ private final ConfigurationController.ConfigurationListener mConfigurationListener =
+ new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onDensityOrFontScaleChanged() {
+ mView.scaleBatteryMeterViews();
+ }
+ };
+
+ private final TunerService.Tunable mTunable = new TunerService.Tunable() {
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ if (StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
+ ArraySet<String> icons = StatusBarIconController.getIconHideList(
+ getContext(), newValue);
+ mView.setVisibility(icons.contains(mSlotBattery) ? View.GONE : View.VISIBLE);
+ }
+ }
+ };
+
+ // Some places may need to show the battery conditionally, and not obey the tuner
+ private boolean mIgnoreTunerUpdates;
+ private boolean mIsSubscribedForTunerUpdates;
+
+ @Inject
+ public BatteryMeterViewController(
+ BatteryMeterView view,
+ ConfigurationController configurationController,
+ TunerService tunerService) {
+ super(view);
+ mConfigurationController = configurationController;
+ mTunerService = tunerService;
+
+ mSlotBattery = getResources().getString(com.android.internal.R.string.status_bar_battery);
+ }
+
+ @Override
+ protected void onViewAttached() {
+ mConfigurationController.addCallback(mConfigurationListener);
+ subscribeForTunerUpdates();
+ }
+
+ @Override
+ protected void onViewDetached() {
+ destroy();
+ }
+
+ @Override
+ public void destroy() {
+ super.destroy();
+ mConfigurationController.removeCallback(mConfigurationListener);
+ unsubscribeFromTunerUpdates();
+ }
+
+ /**
+ * Turn off {@link BatteryMeterView}'s subscribing to the tuner for updates, and thus avoid it
+ * controlling its own visibility.
+ */
+ public void ignoreTunerUpdates() {
+ mIgnoreTunerUpdates = true;
+ unsubscribeFromTunerUpdates();
+ }
+
+ private void subscribeForTunerUpdates() {
+ if (mIsSubscribedForTunerUpdates || mIgnoreTunerUpdates) {
+ return;
+ }
+
+ mTunerService.addTunable(mTunable, StatusBarIconController.ICON_HIDE_LIST);
+ mIsSubscribedForTunerUpdates = true;
+ }
+
+ private void unsubscribeFromTunerUpdates() {
+ if (!mIsSubscribedForTunerUpdates) {
+ return;
+ }
+
+ mTunerService.removeTunable(mTunable);
+ mIsSubscribedForTunerUpdates = false;
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
index 205054d68280..ae3e94b9a1cb 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
@@ -44,11 +44,17 @@ public class AuthBiometricFaceToFingerprintView extends AuthBiometricFaceView {
private static final String TAG = "BiometricPrompt/AuthBiometricFaceToFingerprintView";
protected static class UdfpsIconController extends IconController {
+ @BiometricState private int mIconState = STATE_IDLE;
+
protected UdfpsIconController(
@NonNull Context context, @NonNull ImageView iconView, @NonNull TextView textView) {
super(context, iconView, textView);
}
+ void updateState(@BiometricState int newState) {
+ updateState(mIconState, newState);
+ }
+
@Override
protected void updateState(int lastState, int newState) {
final boolean lastStateIsErrorIcon =
@@ -86,6 +92,7 @@ public class AuthBiometricFaceToFingerprintView extends AuthBiometricFaceView {
}
mState = newState;
+ mIconState = newState;
}
}
@@ -93,6 +100,8 @@ public class AuthBiometricFaceToFingerprintView extends AuthBiometricFaceView {
@Nullable private ModalityListener mModalityListener;
@Nullable private FingerprintSensorPropertiesInternal mFingerprintSensorProps;
@Nullable private UdfpsDialogMeasureAdapter mUdfpsMeasureAdapter;
+ @Nullable @VisibleForTesting UdfpsIconController mUdfpsIconController;
+
public AuthBiometricFaceToFingerprintView(Context context) {
super(context);
@@ -107,6 +116,12 @@ public class AuthBiometricFaceToFingerprintView extends AuthBiometricFaceView {
super(context, attrs, injector);
}
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mUdfpsIconController = new UdfpsIconController(mContext, mIconView, mIndicatorView);
+ }
+
@Modality
int getActiveSensorType() {
return mActiveSensorType;
@@ -168,35 +183,26 @@ public class AuthBiometricFaceToFingerprintView extends AuthBiometricFaceView {
}
@Override
- @NonNull
- protected IconController getIconController() {
- if (mActiveSensorType == TYPE_FINGERPRINT) {
- if (!(mIconController instanceof UdfpsIconController)) {
- mIconController = createUdfpsIconController();
- }
- return mIconController;
- }
- return super.getIconController();
- }
-
- @NonNull
- protected IconController createUdfpsIconController() {
- return new UdfpsIconController(getContext(), mIconView, mIndicatorView);
- }
-
- @Override
public void updateState(@BiometricState int newState) {
- if (mState == STATE_HELP || mState == STATE_ERROR) {
- @Modality final int currentType = mActiveSensorType;
- mActiveSensorType = TYPE_FINGERPRINT;
+ if (mActiveSensorType == TYPE_FACE) {
+ if (newState == STATE_HELP || newState == STATE_ERROR) {
+ mActiveSensorType = TYPE_FINGERPRINT;
+
+ setRequireConfirmation(false);
+ mConfirmButton.setEnabled(false);
+ mConfirmButton.setVisibility(View.GONE);
- setRequireConfirmation(false);
- mConfirmButton.setEnabled(false);
- mConfirmButton.setVisibility(View.GONE);
+ if (mModalityListener != null) {
+ mModalityListener.onModalitySwitched(TYPE_FACE, mActiveSensorType);
+ }
- if (mModalityListener != null && currentType != mActiveSensorType) {
- mModalityListener.onModalitySwitched(currentType, mActiveSensorType);
+ // Deactivate the face icon controller so it stops drawing to the view
+ mFaceIconController.deactivate();
+ // Then, activate this icon controller. We need to start in the "idle" state
+ mUdfpsIconController.updateState(STATE_IDLE);
}
+ } else { // Fingerprint
+ mUdfpsIconController.updateState(newState);
}
super.updateState(newState);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
index e8da7c51bf0d..c32c1a2f3e53 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
@@ -49,6 +49,7 @@ public class AuthBiometricFaceView extends AuthBiometricView {
protected Handler mHandler;
protected boolean mLastPulseLightToDark; // false = dark to light, true = light to dark
protected @BiometricState int mState;
+ protected boolean mDeactivated;
protected IconController(Context context, ImageView iconView, TextView textView) {
mContext = context;
@@ -67,6 +68,11 @@ public class AuthBiometricFaceView extends AuthBiometricView {
}
protected void animateIcon(int iconRes, boolean repeat) {
+ Log.d(TAG, "animateIcon, state: " + mState + ", deactivated: " + mDeactivated);
+ if (mDeactivated) {
+ return;
+ }
+
final AnimatedVectorDrawable icon =
(AnimatedVectorDrawable) mContext.getDrawable(iconRes);
mIconView.setImageDrawable(icon);
@@ -92,12 +98,26 @@ public class AuthBiometricFaceView extends AuthBiometricView {
@Override
public void onAnimationEnd(Drawable drawable) {
super.onAnimationEnd(drawable);
+ Log.d(TAG, "onAnimationEnd, mState: " + mState + ", deactivated: " + mDeactivated);
+ if (mDeactivated) {
+ return;
+ }
+
if (mState == STATE_AUTHENTICATING || mState == STATE_HELP) {
pulseInNextDirection();
}
}
+ protected void deactivate() {
+ mDeactivated = true;
+ }
+
protected void updateState(int lastState, int newState) {
+ if (mDeactivated) {
+ Log.w(TAG, "Ignoring updateState when deactivated: " + newState);
+ return;
+ }
+
final boolean lastStateIsErrorIcon =
lastState == STATE_ERROR || lastState == STATE_HELP;
@@ -142,7 +162,7 @@ public class AuthBiometricFaceView extends AuthBiometricView {
}
}
- protected IconController mIconController;
+ @Nullable @VisibleForTesting IconController mFaceIconController;
public AuthBiometricFaceView(Context context) {
this(context, null);
@@ -158,6 +178,12 @@ public class AuthBiometricFaceView extends AuthBiometricView {
}
@Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mFaceIconController = new IconController(mContext, mIconView, mIndicatorView);
+ }
+
+ @Override
protected int getDelayAfterAuthenticatedDurationMs() {
return HIDE_DELAY_MS;
}
@@ -187,17 +213,9 @@ public class AuthBiometricFaceView extends AuthBiometricView {
return true;
}
- @NonNull
- protected IconController getIconController() {
- if (mIconController == null) {
- mIconController = new IconController(mContext, mIconView, mIndicatorView);
- }
- return mIconController;
- }
-
@Override
public void updateState(@BiometricState int newState) {
- getIconController().updateState(mState, newState);
+ mFaceIconController.updateState(mState, newState);
if (newState == STATE_AUTHENTICATING_ANIMATING_IN ||
(newState == STATE_AUTHENTICATING && getSize() == AuthDialog.SIZE_MEDIUM)) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index d122610c395d..d46426a03621 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -23,7 +23,6 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
@@ -68,8 +67,6 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
private float mBurnInProgress;
private float mInterpolatedDarkAmount;
- private ValueAnimator mHintAnimator;
-
public UdfpsKeyguardView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mFingerprintDrawable = new UdfpsFpDrawable(context);
@@ -94,9 +91,6 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
new KeyPath("**"), LottieProperty.COLOR_FILTER,
frameInfo -> new PorterDuffColorFilter(mTextColorPrimary, PorterDuff.Mode.SRC_ATOP)
);
-
- mHintAnimator = ObjectAnimator.ofFloat(mLockScreenFp, "progress", 1f, 0f, 1f);
- mHintAnimator.setDuration(4000);
}
@Override
@@ -183,19 +177,11 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
}
void onDozeAmountChanged(float linear, float eased) {
- mHintAnimator.cancel();
mInterpolatedDarkAmount = eased;
updateAlpha();
updateBurnInOffsets();
}
- void animateHint() {
- if (!isShadeLocked() && !mUdfpsRequested && mAlpha == 255
- && mLockScreenFp.isVisibleToUser()) {
- mHintAnimator.start();
- }
- }
-
/**
* Animates in the bg protection circle behind the fp icon to highlight the icon.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index 102dc414d08d..79a4a0bd51ab 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -20,14 +20,10 @@ import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import android.annotation.NonNull;
import android.content.res.Configuration;
-import android.hardware.biometrics.BiometricSourceType;
import android.util.MathUtils;
import android.view.MotionEvent;
-import androidx.annotation.Nullable;
-
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.R;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -47,14 +43,8 @@ import java.util.Optional;
/**
* Class that coordinates non-HBM animations during keyguard authentication.
- *
- * Highlights the udfps icon when:
- * - Face authentication has failed
- * - Face authentication has been run for > 2 seconds
*/
public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<UdfpsKeyguardView> {
- private static final long AFTER_FACE_AUTH_HINT_DELAY = 2000;
-
@NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager;
@NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@NonNull private final DelayableExecutor mExecutor;
@@ -63,12 +53,10 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
@NonNull private final ConfigurationController mConfigurationController;
@NonNull private final UdfpsController mUdfpsController;
- @Nullable private Runnable mCancelDelayedHintRunnable;
private boolean mShowingUdfpsBouncer;
private boolean mUdfpsRequested;
private boolean mQsExpanded;
private boolean mFaceDetectRunning;
- private boolean mHintShown;
private int mStatusBarState;
private float mTransitionToFullShadeProgress;
private float mLastDozeAmount;
@@ -111,10 +99,6 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
@Override
protected void onViewAttached() {
super.onViewAttached();
- mHintShown = false;
- mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
- updateFaceDetectRunning(mKeyguardUpdateMonitor.isFaceDetectionRunning());
-
final float dozeAmount = mStatusBarStateController.getDozeAmount();
mLastDozeAmount = dozeAmount;
mStateListener.onDozeAmountChanged(dozeAmount, dozeAmount);
@@ -137,7 +121,6 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
@Override
protected void onViewDetached() {
super.onViewDetached();
- mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
mFaceDetectRunning = false;
mStatusBarStateController.removeCallback(mStateListener);
@@ -147,11 +130,6 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
if (mLockScreenShadeTransitionController.getUdfpsKeyguardViewController() == this) {
mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(null);
}
-
- if (mCancelDelayedHintRunnable != null) {
- mCancelDelayedHintRunnable.run();
- mCancelDelayedHintRunnable = null;
- }
}
@Override
@@ -250,36 +228,6 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
}
}
- private void cancelDelayedHint() {
- if (mCancelDelayedHintRunnable != null) {
- mCancelDelayedHintRunnable.run();
- mCancelDelayedHintRunnable = null;
- }
- }
-
- private void updateFaceDetectRunning(boolean running) {
- if (mFaceDetectRunning == running) {
- return;
- }
-
- // show udfps hint a few seconds after face auth started running
- if (!mFaceDetectRunning && running && !mHintShown && mCancelDelayedHintRunnable == null) {
- // Face detect started running, show udfps hint after a delay
- mCancelDelayedHintRunnable = mExecutor.executeDelayed(() -> showHint(false),
- AFTER_FACE_AUTH_HINT_DELAY);
- }
-
- mFaceDetectRunning = running;
- }
-
- private void showHint(boolean forceShow) {
- cancelDelayedHint();
- if (!mHintShown || forceShow) {
- mHintShown = true;
- mView.animateHint();
- }
- }
-
/**
* Set the progress we're currently transitioning to the full shade. 0.0f means we're not
* transitioning yet, while 1.0f means we've fully dragged down.
@@ -319,39 +267,6 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
}
};
- private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
- new KeyguardUpdateMonitorCallback() {
- public void onBiometricRunningStateChanged(boolean running,
- BiometricSourceType biometricSourceType) {
- if (biometricSourceType == BiometricSourceType.FACE) {
- updateFaceDetectRunning(running);
- }
- }
-
- public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
- if (biometricSourceType == BiometricSourceType.FACE) {
- // show udfps hint when face auth fails
- showHint(true);
- }
- }
-
- public void onBiometricError(int msgId, String errString,
- BiometricSourceType biometricSourceType) {
- if (biometricSourceType == BiometricSourceType.FACE) {
- // show udfps hint when face auth fails
- showHint(true);
- }
- }
-
- public void onBiometricAuthenticated(int userId,
- BiometricSourceType biometricSourceType, boolean isStrongBiometric) {
- if (biometricSourceType == BiometricSourceType.FACE) {
- // cancel delayed hint if face auth succeeded
- cancelDelayedHint();
- }
- }
- };
-
private final StatusBarKeyguardViewManager.AlternateAuthInterceptor mAlternateAuthInterceptor =
new StatusBarKeyguardViewManager.AlternateAuthInterceptor() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index 239a77eb2f45..9cb9a362d460 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -39,6 +39,7 @@ 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.EnhancedEstimatesImpl;
+import com.android.systemui.power.dagger.PowerModule;
import com.android.systemui.qs.dagger.QSModule;
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
import com.android.systemui.recents.Recents;
@@ -80,6 +81,7 @@ import dagger.Provides;
*/
@Module(includes = {
MediaModule.class,
+ PowerModule.class,
QSModule.class
})
public abstract class SystemUIDefaultModule {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 556f95642deb..102fc40ef1ad 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -36,18 +36,17 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.demomode.dagger.DemoModeModule;
import com.android.systemui.doze.dagger.DozeComponent;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.log.dagger.LogModule;
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.BcSmartspaceDataPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.power.dagger.PowerModule;
import com.android.systemui.recents.Recents;
import com.android.systemui.screenshot.dagger.ScreenshotModule;
import com.android.systemui.settings.dagger.SettingsModule;
import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -102,7 +101,6 @@ import dagger.Provides;
FalsingModule.class,
LogModule.class,
PeopleHubModule.class,
- PowerModule.class,
PluginModule.class,
ScreenshotModule.class,
SensorModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 23c44131ab60..b2db86f16104 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -115,6 +115,7 @@ public class DozeSensors {
mSecureSettings = secureSettings;
mCallback = callback;
mProximitySensor = proximitySensor;
+ mProximitySensor.setTag(TAG);
mSelectivelyRegisterProxSensors = dozeParameters.getSelectivelyRegisterSensorsUsingProx();
mListeningProxSensors = !mSelectivelyRegisterProxSensors;
mScreenOffUdfpsEnabled =
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java
index 6fbf81c53c90..d4d01c8d97b5 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java
@@ -16,6 +16,7 @@
package com.android.systemui.flags;
+import android.content.Context;
import android.content.res.Resources;
import android.util.SparseArray;
@@ -25,7 +26,9 @@ import androidx.annotation.Nullable;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.plugins.FlagReaderPlugin;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.util.wrapper.BuildInfo;
import javax.inject.Inject;
@@ -55,18 +58,68 @@ import javax.inject.Inject;
public class FeatureFlagReader {
private final Resources mResources;
private final boolean mAreFlagsOverrideable;
+ private final PluginManager mPluginManager;
private final SystemPropertiesHelper mSystemPropertiesHelper;
private final SparseArray<CachedFlag> mCachedFlags = new SparseArray<>();
+ private FlagReaderPlugin mPlugin = new FlagReaderPlugin(){};
+
@Inject
public FeatureFlagReader(
@Main Resources resources,
BuildInfo build,
+ PluginManager pluginManager,
SystemPropertiesHelper systemPropertiesHelper) {
mResources = resources;
+ mPluginManager = pluginManager;
mSystemPropertiesHelper = systemPropertiesHelper;
mAreFlagsOverrideable =
build.isDebuggable() && mResources.getBoolean(R.bool.are_flags_overrideable);
+
+ mPluginManager.addPluginListener(mPluginListener, FlagReaderPlugin.class);
+ }
+
+ private final PluginListener<FlagReaderPlugin> mPluginListener =
+ new PluginListener<FlagReaderPlugin>() {
+ public void onPluginConnected(FlagReaderPlugin plugin, Context context) {
+ mPlugin = plugin;
+ }
+
+ public void onPluginDisconnected(FlagReaderPlugin plugin) {
+ mPlugin = new FlagReaderPlugin() {};
+ }
+ };
+
+ boolean isEnabled(BooleanFlag flag) {
+ return mPlugin.isEnabled(flag.getId(), flag.getDefault());
+ }
+
+ String getValue(StringFlag flag) {
+ return mPlugin.getValue(flag.getId(), flag.getDefault());
+ }
+
+ int getValue(IntFlag flag) {
+ return mPlugin.getValue(flag.getId(), flag.getDefault());
+ }
+
+ long getValue(LongFlag flag) {
+ return mPlugin.getValue(flag.getId(), flag.getDefault());
+ }
+
+ float getValue(FloatFlag flag) {
+ return mPlugin.getValue(flag.getId(), flag.getDefault());
+ }
+
+ double getValue(DoubleFlag flag) {
+ return mPlugin.getValue(flag.getId(), flag.getDefault());
+ }
+
+ void addListener(FlagReaderPlugin.Listener listener) {
+ mPlugin.addListener(listener);
+ }
+
+ void removeListener(FlagReaderPlugin.Listener listener) {
+ mPlugin.removeListener(listener);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
index b76cebf70bcc..e51f90f9c73b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,14 +14,20 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar;
+package com.android.systemui.flags;
import android.content.Context;
import android.util.FeatureFlagUtils;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.flags.FeatureFlagReader;
+import com.android.systemui.plugins.FlagReaderPlugin;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import javax.inject.Inject;
@@ -34,11 +40,88 @@ import javax.inject.Inject;
public class FeatureFlags {
private final FeatureFlagReader mFlagReader;
private final Context mContext;
+ private final Map<Integer, Flag<?>> mFlagMap = new HashMap<>();
+ private final Map<Integer, List<Listener>> mListeners = new HashMap<>();
@Inject
public FeatureFlags(FeatureFlagReader flagReader, Context context) {
mFlagReader = flagReader;
mContext = context;
+
+ flagReader.addListener(mListener);
+ }
+
+ private final FlagReaderPlugin.Listener mListener = id -> {
+ if (mListeners.containsKey(id) && mFlagMap.containsKey(id)) {
+ mListeners.get(id).forEach(listener -> listener.onFlagChanged(mFlagMap.get(id)));
+ }
+ };
+
+ @VisibleForTesting
+ void addFlag(Flag flag) {
+ mFlagMap.put(flag.getId(), flag);
+ }
+
+ /**
+ * @param flag The {@link BooleanFlag} of interest.
+ * @return The value of the flag.
+ */
+ public boolean isEnabled(BooleanFlag flag) {
+ return mFlagReader.isEnabled(flag);
+ }
+
+ /**
+ * @param flag The {@link StringFlag} of interest.
+ * @return The value of the flag.
+ */
+ public String getValue(StringFlag flag) {
+ return mFlagReader.getValue(flag);
+ }
+
+ /**
+ * @param flag The {@link IntFlag} of interest.
+ * @return The value of the flag.
+ */
+ public int getValue(IntFlag flag) {
+ return mFlagReader.getValue(flag);
+ }
+
+ /**
+ * @param flag The {@link LongFlag} of interest.
+ * @return The value of the flag.
+ */
+ public long getValue(LongFlag flag) {
+ return mFlagReader.getValue(flag);
+ }
+
+ /**
+ * @param flag The {@link FloatFlag} of interest.
+ * @return The value of the flag.
+ */
+ public float getValue(FloatFlag flag) {
+ return mFlagReader.getValue(flag);
+ }
+
+ /**
+ * @param flag The {@link DoubleFlag} of interest.
+ * @return The value of the flag.
+ */
+ public double getValue(DoubleFlag flag) {
+ return mFlagReader.getValue(flag);
+ }
+
+ /** Add a listener for a specific flag. */
+ public void addFlagListener(Flag<?> flag, Listener listener) {
+ mListeners.putIfAbsent(flag.getId(), new ArrayList<>());
+ mListeners.get(flag.getId()).add(listener);
+ mFlagMap.putIfAbsent(flag.getId(), flag);
+ }
+
+ /** Remove a listener for a specific flag. */
+ public void removeFlagListener(Flag<?> flag, Listener listener) {
+ if (mListeners.containsKey(flag.getId())) {
+ mListeners.get(flag.getId()).remove(listener);
+ }
}
public boolean isNewNotifPipelineEnabled() {
@@ -53,6 +136,7 @@ public class FeatureFlags {
return mFlagReader.isEnabled(R.bool.flag_keyguard_layout);
}
+ /** */
public boolean useNewLockscreenAnimations() {
return mFlagReader.isEnabled(R.bool.flag_lockscreen_animations);
}
@@ -107,4 +191,10 @@ public class FeatureFlags {
public static boolean isProviderModelSettingEnabled(Context context) {
return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL);
}
+
+ /** Simple interface for beinga alerted when a specific flag changes value. */
+ public interface Listener {
+ /** */
+ void onFlagChanged(Flag<?> flag);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 391e6defd7e8..0b8c63580234 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -20,6 +20,8 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
+import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
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;
@@ -28,8 +30,12 @@ import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALL
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OLD_NONE;
+import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.TransitionOldType;
import static android.view.WindowManager.TransitionType;
+import static android.window.TransitionInfo.FLAG_OCCLUDES_KEYGUARD;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
@@ -158,7 +164,7 @@ public class KeyguardService extends Service {
info.getChanges().size() - i,
new Point(), localBounds, new Rect(change.getEndAbsBounds()),
windowConfiguration, isNotInRecents, null /* startLeash */,
- change.getStartAbsBounds(), taskInfo));
+ change.getStartAbsBounds(), taskInfo, false /* allowEnterPip */));
}
return out.toArray(new RemoteAnimationTarget[out.size()]);
}
@@ -231,9 +237,42 @@ public class KeyguardService extends Service {
}
if (sEnableRemoteKeyguardOccludeAnimation) {
Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_(UN)OCCLUDE");
+ // Register for occluding
TransitionFilter f = new TransitionFilter();
- f.mTypeSet = new int[]{TRANSIT_KEYGUARD_OCCLUDE, TRANSIT_KEYGUARD_UNOCCLUDE};
- shellTransitions.registerRemote(f, wrap(mOccludeAnimationRunner));
+ f.mFlags = TRANSIT_FLAG_KEYGUARD_LOCKED;
+ f.mRequirements = new TransitionFilter.Requirement[]{
+ new TransitionFilter.Requirement(), new TransitionFilter.Requirement()};
+ // First require at-least one app showing that occludes.
+ f.mRequirements[0].mMustBeIndependent = false;
+ f.mRequirements[0].mFlags = FLAG_OCCLUDES_KEYGUARD;
+ f.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
+ // Then require that we aren't closing any occludes (because this would mean a
+ // regular task->task or activity->activity animation not involving keyguard).
+ f.mRequirements[1].mNot = true;
+ f.mRequirements[1].mMustBeIndependent = false;
+ f.mRequirements[1].mFlags = FLAG_OCCLUDES_KEYGUARD;
+ f.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK};
+ shellTransitions.registerRemote(f, mOccludeAnimation);
+
+ // Now register for un-occlude.
+ f = new TransitionFilter();
+ f.mFlags = TRANSIT_FLAG_KEYGUARD_LOCKED;
+ f.mRequirements = new TransitionFilter.Requirement[]{
+ new TransitionFilter.Requirement(), new TransitionFilter.Requirement()};
+ // First require at-least one app going-away (doesn't need occlude flag
+ // as that is implicit by it having been visible and we don't want to exclude
+ // cases where we are un-occluding because the app removed its showWhenLocked
+ // capability at runtime).
+ f.mRequirements[1].mMustBeIndependent = false;
+ f.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK};
+ f.mRequirements[1].mMustBeTask = true;
+ // Then require that we aren't opening any occludes (otherwise we'd remain
+ // occluded).
+ f.mRequirements[0].mNot = true;
+ f.mRequirements[0].mMustBeIndependent = false;
+ f.mRequirements[0].mFlags = FLAG_OCCLUDES_KEYGUARD;
+ f.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
+ shellTransitions.registerRemote(f, mUnoccludeAnimation);
}
} else {
RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
@@ -328,6 +367,40 @@ public class KeyguardService extends Service {
}
};
+ final IRemoteTransition mOccludeAnimation = new IRemoteTransition.Stub() {
+ @Override
+ public void startAnimation(IBinder transition, TransitionInfo info,
+ SurfaceControl.Transaction t, IRemoteTransitionFinishedCallback finishCallback)
+ throws RemoteException {
+ t.apply();
+ mBinder.setOccluded(true /* isOccluded */, true /* animate */);
+ finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ }
+
+ @Override
+ public void mergeAnimation(IBinder transition, TransitionInfo info,
+ SurfaceControl.Transaction t, IBinder mergeTarget,
+ IRemoteTransitionFinishedCallback finishCallback) {
+ }
+ };
+
+ final IRemoteTransition mUnoccludeAnimation = new IRemoteTransition.Stub() {
+ @Override
+ public void startAnimation(IBinder transition, TransitionInfo info,
+ SurfaceControl.Transaction t, IRemoteTransitionFinishedCallback finishCallback)
+ throws RemoteException {
+ t.apply();
+ mBinder.setOccluded(false /* isOccluded */, true /* animate */);
+ finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ }
+
+ @Override
+ public void mergeAnimation(IBinder transition, TransitionInfo info,
+ SurfaceControl.Transaction t, IBinder mergeTarget,
+ IRemoteTransitionFinishedCallback finishCallback) {
+ }
+ };
+
private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {
@Override // Binder interface
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index a5fe9015b74a..e51b60213446 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -31,7 +31,7 @@ import com.android.keyguard.KeyguardViewController
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.statusbar.policy.KeyguardStateController
import dagger.Lazy
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index b9834d402f2a..281771860cb7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2347,8 +2347,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
}
private Configuration.Builder createInteractionJankMonitorConf(String tag) {
- return new Configuration.Builder(CUJ_LOCKSCREEN_UNLOCK_ANIMATION)
- .setView(mKeyguardViewControllerLazy.get().getViewRootImpl().getView())
+ return Configuration.Builder.withView(CUJ_LOCKSCREEN_UNLOCK_ANIMATION,
+ mKeyguardViewControllerLazy.get().getViewRootImpl().getView())
.setTag(tag);
}
@@ -2603,7 +2603,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
if (mContext.getResources().getBoolean(
com.android.internal.R.bool.config_guestUserAutoCreated)) {
// TODO(b/191067027): Move post-boot guest creation to system_server
- mUserSwitcherController.guaranteeGuestPresent();
+ mUserSwitcherController.schedulePostBootGuestCreation();
}
mBootCompleted = true;
adjustStatusBarLocked(false, true);
@@ -2759,7 +2759,10 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
// Don't hide the keyguard due to a doze change if there's a lock pending, because we're
// just going to show it again.
- if (mShowing || !mPendingLock) {
+ // If the device is not capable of controlling the screen off animation, SysUI needs to
+ // update lock screen state in ATMS here, otherwise ATMS tries to resume activities when
+ // enabling doze state.
+ if (mShowing || !mPendingLock || !mDozeParameters.canControlUnlockedScreenOff()) {
setShowingLocked(mShowing);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 543004eecb8e..1ca2217638f7 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -116,7 +116,7 @@ public class NavigationBarController implements Callbacks,
private final TaskbarDelegate mTaskbarDelegate;
private final NotificationShadeDepthController mNotificationShadeDepthController;
private int mNavMode;
- private boolean mIsTablet;
+ @VisibleForTesting boolean mIsTablet;
private final UserTracker mUserTracker;
/** A displayId - nav bar maps. */
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index ce1066ee41c2..1bd36644bbc5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -268,7 +268,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
}
@Override
- public void setExpansion(float expansion) {
+ public void setExpansion(float expansion, float proposedTranslation) {
mLastExpansion = expansion;
updateSelected();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index e38bd4bd9a38..0e0681b94c62 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -35,11 +35,6 @@ public interface QSFooter {
void setExpanded(boolean expanded);
/**
- * Returns the full height of the footer.
- */
- int getHeight();
-
- /**
* Sets the percentage amount that the quick settings has been expanded.
*
* @param expansion A value from 1 to 0 that indicates how much the quick settings have been
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsController.kt b/packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsController.kt
new file mode 100644
index 000000000000..dbf62a436197
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsController.kt
@@ -0,0 +1,167 @@
+package com.android.systemui.qs
+
+import android.content.Intent
+import android.os.UserManager
+import android.provider.Settings
+import android.view.View
+import android.widget.Toast
+import androidx.annotation.VisibleForTesting
+import com.android.internal.jank.InteractionJankMonitor
+import com.android.internal.logging.MetricsLogger
+import com.android.internal.logging.UiEventLogger
+import com.android.internal.logging.nano.MetricsProto
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.R
+import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.globalactions.GlobalActionsDialogLite
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.qs.dagger.QSFlagsModule.PM_LITE_ENABLED
+import com.android.systemui.statusbar.phone.MultiUserSwitchController
+import com.android.systemui.statusbar.phone.SettingsButton
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.UserInfoController
+import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener
+import com.android.systemui.tuner.TunerService
+import com.android.systemui.util.ViewController
+import javax.inject.Inject
+import javax.inject.Named
+
+class QSFooterActionsController @Inject constructor(
+ view: QSFooterActionsView,
+ private val qsPanelController: QSPanelController,
+ private val activityStarter: ActivityStarter,
+ private val userManager: UserManager,
+ private val userInfoController: UserInfoController,
+ private val multiUserSwitchController: MultiUserSwitchController,
+ private val deviceProvisionedController: DeviceProvisionedController,
+ private val falsingManager: FalsingManager,
+ private val metricsLogger: MetricsLogger,
+ private val tunerService: TunerService,
+ private val globalActionsDialog: GlobalActionsDialogLite,
+ private val uiEventLogger: UiEventLogger,
+ @Named(PM_LITE_ENABLED) private val showPMLiteButton: Boolean
+) : ViewController<QSFooterActionsView>(view) {
+
+ private var listening: Boolean = false
+ var expanded = false
+ set(value) {
+ field = value
+ mView.setExpanded(value, isTunerEnabled(),
+ multiUserSwitchController.isMultiUserEnabled)
+ }
+
+ private val settingsButton: SettingsButton = view.findViewById(R.id.settings_button)
+ private val settingsButtonContainer: View? = view.findViewById(R.id.settings_button_container)
+ private val editButton: View = view.findViewById(android.R.id.edit)
+ private val powerMenuLite: View = view.findViewById(R.id.pm_lite)
+
+ private val onUserInfoChangedListener = OnUserInfoChangedListener { _, picture, _ ->
+ val isGuestUser: Boolean = userManager.isGuestUser(KeyguardUpdateMonitor.getCurrentUser())
+ mView.onUserInfoChanged(picture, isGuestUser)
+ }
+
+ private val onClickListener = View.OnClickListener { v ->
+ // Don't do anything until views are unhidden. Don't do anything if the tap looks
+ // suspicious.
+ if (!expanded || falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ return@OnClickListener
+ }
+ if (v === settingsButton) {
+ if (!deviceProvisionedController.isCurrentUserSetup) {
+ // If user isn't setup just unlock the device and dump them back at SUW.
+ activityStarter.postQSRunnableDismissingKeyguard {}
+ return@OnClickListener
+ }
+ metricsLogger.action(
+ if (expanded) MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH
+ else MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH)
+ if (settingsButton.isTunerClick) {
+ activityStarter.postQSRunnableDismissingKeyguard {
+ if (isTunerEnabled()) {
+ tunerService.showResetRequest {
+ // Relaunch settings so that the tuner disappears.
+ startSettingsActivity()
+ }
+ } else {
+ Toast.makeText(context, R.string.tuner_toast, Toast.LENGTH_LONG).show()
+ tunerService.isTunerEnabled = true
+ }
+ startSettingsActivity()
+ }
+ } else {
+ startSettingsActivity()
+ }
+ } else if (v === powerMenuLite) {
+ uiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS)
+ globalActionsDialog.showOrHideDialog(false, true)
+ }
+ }
+
+ override fun onInit() {
+ multiUserSwitchController.init()
+ }
+
+ private fun startSettingsActivity() {
+ val animationController = settingsButtonContainer?.let {
+ ActivityLaunchAnimator.Controller.fromView(
+ it,
+ InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON)
+ }
+ activityStarter.startActivity(Intent(Settings.ACTION_SETTINGS),
+ true /* dismissShade */, animationController)
+ }
+
+ @VisibleForTesting
+ public override fun onViewAttached() {
+ if (showPMLiteButton) {
+ powerMenuLite.visibility = View.VISIBLE
+ powerMenuLite.setOnClickListener(onClickListener)
+ } else {
+ powerMenuLite.visibility = View.GONE
+ }
+ settingsButton.setOnClickListener(onClickListener)
+ editButton.setOnClickListener(View.OnClickListener { view: View? ->
+ if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ return@OnClickListener
+ }
+ activityStarter.postQSRunnableDismissingKeyguard { qsPanelController.showEdit(view) }
+ })
+
+ mView.updateEverything(isTunerEnabled(), multiUserSwitchController.isMultiUserEnabled)
+ }
+
+ override fun onViewDetached() {
+ setListening(false)
+ }
+
+ fun setListening(listening: Boolean) {
+ if (this.listening == listening) {
+ return
+ }
+ this.listening = listening
+ if (this.listening) {
+ userInfoController.addCallback(onUserInfoChangedListener)
+ } else {
+ userInfoController.removeCallback(onUserInfoChangedListener)
+ }
+ }
+
+ fun disable(state2: Int) {
+ mView.disable(state2, isTunerEnabled(), multiUserSwitchController.isMultiUserEnabled)
+ }
+
+ fun setExpansion(headerExpansionFraction: Float) {
+ mView.setExpansion(headerExpansionFraction)
+ }
+
+ fun updateAnimator(width: Int, numTiles: Int) {
+ mView.updateAnimator(width, numTiles)
+ }
+
+ fun setKeyguardShowing() {
+ mView.setKeyguardShowing()
+ }
+
+ private fun isTunerEnabled() = tunerService.isTunerEnabled
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsView.kt b/packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsView.kt
new file mode 100644
index 000000000000..66a29a36f351
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsView.kt
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.qs
+
+import android.app.StatusBarManager
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.PorterDuff
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.RippleDrawable
+import android.os.UserManager
+import android.util.AttributeSet
+import android.view.View
+import android.widget.ImageView
+import android.widget.LinearLayout
+import com.android.settingslib.Utils
+import com.android.settingslib.drawable.UserIconDrawable
+import com.android.systemui.R
+import com.android.systemui.statusbar.phone.MultiUserSwitch
+import com.android.systemui.statusbar.phone.SettingsButton
+
+/**
+ * Quick Settings bottom buttons placed in footer (aka utility bar) - always visible in expanded QS,
+ * in split shade mode visible also in collapsed state. May contain up to 5 buttons: settings,
+ * edit tiles, power off and conditionally: user switch and tuner
+ */
+class QSFooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs) {
+ private lateinit var settingsContainer: View
+ private lateinit var settingsButton: SettingsButton
+ private lateinit var multiUserSwitch: MultiUserSwitch
+ private lateinit var multiUserAvatar: ImageView
+ private lateinit var tunerIcon: View
+ private lateinit var editTilesButton: View
+
+ private var settingsCogAnimator: TouchAnimator? = null
+
+ private var qsDisabled = false
+ private var isExpanded = false
+ private var expansionAmount = 0f
+
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+ editTilesButton = requireViewById(android.R.id.edit)
+ settingsButton = findViewById(R.id.settings_button)
+ settingsContainer = findViewById(R.id.settings_button_container)
+ multiUserSwitch = findViewById(R.id.multi_user_switch)
+ multiUserAvatar = multiUserSwitch.findViewById(R.id.multi_user_avatar)
+ tunerIcon = requireViewById(R.id.tuner_icon)
+
+ // RenderThread is doing more harm than good when touching the header (to expand quick
+ // settings), so disable it for this view
+ if (settingsButton.background is RippleDrawable) {
+ (settingsButton.background as RippleDrawable).setForceSoftware(true)
+ }
+ updateResources()
+ importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES
+ }
+
+ fun updateAnimator(width: Int, numTiles: Int) {
+ val size = (mContext.resources.getDimensionPixelSize(R.dimen.qs_quick_tile_size) -
+ mContext.resources.getDimensionPixelSize(R.dimen.qs_tile_padding))
+ val remaining = (width - numTiles * size) / (numTiles - 1)
+ val defSpace = mContext.resources.getDimensionPixelOffset(R.dimen.default_gear_space)
+ val translation = if (isLayoutRtl) (remaining - defSpace) else -(remaining - defSpace)
+ settingsCogAnimator = TouchAnimator.Builder()
+ .addFloat(settingsButton, "translationX", translation.toFloat(), 0f)
+ .addFloat(settingsButton, "rotation", -120f, 0f)
+ .build()
+ setExpansion(expansionAmount)
+ }
+
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ super.onConfigurationChanged(newConfig)
+ updateResources()
+ }
+
+ override fun onRtlPropertiesChanged(layoutDirection: Int) {
+ super.onRtlPropertiesChanged(layoutDirection)
+ updateResources()
+ }
+
+ private fun updateResources() {
+ val tunerIconTranslation = mContext.resources
+ .getDimensionPixelOffset(R.dimen.qs_footer_tuner_icon_translation).toFloat()
+ tunerIcon.translationX = if (isLayoutRtl) (-tunerIconTranslation) else tunerIconTranslation
+ }
+
+ fun setKeyguardShowing() {
+ setExpansion(expansionAmount)
+ }
+
+ fun setExpanded(expanded: Boolean, isTunerEnabled: Boolean, multiUserEnabled: Boolean) {
+ if (isExpanded == expanded) return
+ isExpanded = expanded
+ updateEverything(isTunerEnabled, multiUserEnabled)
+ }
+
+ fun setExpansion(headerExpansionFraction: Float) {
+ expansionAmount = headerExpansionFraction
+ if (settingsCogAnimator != null) settingsCogAnimator!!.setPosition(headerExpansionFraction)
+ }
+
+ fun disable(state2: Int, isTunerEnabled: Boolean, multiUserEnabled: Boolean) {
+ val disabled = state2 and StatusBarManager.DISABLE2_QUICK_SETTINGS != 0
+ if (disabled == qsDisabled) return
+ qsDisabled = disabled
+ updateEverything(isTunerEnabled, multiUserEnabled)
+ }
+
+ fun updateEverything(isTunerEnabled: Boolean, multiUserEnabled: Boolean) {
+ post {
+ updateVisibilities(isTunerEnabled, multiUserEnabled)
+ updateClickabilities()
+ isClickable = false
+ }
+ }
+
+ private fun updateClickabilities() {
+ multiUserSwitch.isClickable = multiUserSwitch.visibility == VISIBLE
+ editTilesButton.isClickable = editTilesButton.visibility == VISIBLE
+ settingsButton.isClickable = settingsButton.visibility == VISIBLE
+ }
+
+ private fun updateVisibilities(isTunerEnabled: Boolean, multiUserEnabled: Boolean) {
+ settingsContainer.visibility = if (qsDisabled) GONE else VISIBLE
+ tunerIcon.visibility = if (isTunerEnabled) VISIBLE else INVISIBLE
+ multiUserSwitch.visibility = if (showUserSwitcher(multiUserEnabled)) VISIBLE else GONE
+ val isDemo = UserManager.isDeviceInDemoMode(context)
+ settingsButton.visibility = if (isDemo || !isExpanded) INVISIBLE else VISIBLE
+ }
+
+ private fun showUserSwitcher(multiUserEnabled: Boolean): Boolean {
+ return isExpanded && multiUserEnabled
+ }
+
+ fun onUserInfoChanged(picture: Drawable?, isGuestUser: Boolean) {
+ var pictureToSet = picture
+ if (picture != null && isGuestUser && picture !is UserIconDrawable) {
+ pictureToSet = picture.constantState.newDrawable(resources).mutate()
+ pictureToSet.setColorFilter(
+ Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorForeground),
+ PorterDuff.Mode.SRC_IN)
+ }
+ multiUserAvatar.setImageDrawable(pictureToSet)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
index 57438d189b22..7db13bdb64bb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
@@ -21,60 +21,40 @@ import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
import android.content.Context;
import android.content.res.Configuration;
import android.database.ContentObserver;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.RippleDrawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
-import android.os.UserManager;
import android.provider.Settings;
import android.util.AttributeSet;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
-import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-import com.android.settingslib.Utils;
import com.android.settingslib.development.DevelopmentSettingsEnabler;
-import com.android.settingslib.drawable.UserIconDrawable;
import com.android.systemui.R;
-import com.android.systemui.qs.TouchAnimator.Builder;
-import com.android.systemui.statusbar.phone.MultiUserSwitch;
-import com.android.systemui.statusbar.phone.SettingsButton;
-/** */
+/**
+ * Footer of expanded Quick Settings, tiles page indicator, (optionally) build number and
+ * {@link QSFooterActionsView}
+ */
public class QSFooterView extends FrameLayout {
- private SettingsButton mSettingsButton;
- protected View mSettingsContainer;
private PageIndicator mPageIndicator;
private TextView mBuildText;
- private boolean mShouldShowBuildText;
+ private View mActionsContainer;
- private boolean mQsDisabled;
+ protected TouchAnimator mFooterAnimator;
+ private boolean mQsDisabled;
private boolean mExpanded;
-
- private boolean mListening;
-
- protected MultiUserSwitch mMultiUserSwitch;
- private ImageView mMultiUserAvatar;
-
- protected TouchAnimator mFooterAnimator;
private float mExpansionAmount;
- protected View mEdit;
- private TouchAnimator mSettingsCogAnimator;
-
- private View mActionsContainer;
- private View mTunerIcon;
- private int mTunerIconTranslation;
+ private boolean mShouldShowBuildText;
private OnClickListener mExpandClickListener;
@@ -94,27 +74,11 @@ public class QSFooterView extends FrameLayout {
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mEdit = requireViewById(android.R.id.edit);
-
mPageIndicator = findViewById(R.id.footer_page_indicator);
-
- mSettingsButton = findViewById(R.id.settings_button);
- mSettingsContainer = findViewById(R.id.settings_button_container);
-
- mMultiUserSwitch = findViewById(R.id.multi_user_switch);
- mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
-
mActionsContainer = requireViewById(R.id.qs_footer_actions_container);
mBuildText = findViewById(R.id.build);
- mTunerIcon = requireViewById(R.id.tuner_icon);
- // RenderThread is doing more harm than good when touching the header (to expand quick
- // settings), so disable it for this view
- if (mSettingsButton.getBackground() instanceof RippleDrawable) {
- ((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true);
- }
updateResources();
-
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
setBuildText();
}
@@ -137,18 +101,7 @@ public class QSFooterView extends FrameLayout {
}
}
- void updateAnimator(int width, int numTiles) {
- int size = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size)
- - mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_padding);
- int remaining = (width - numTiles * size) / (numTiles - 1);
- int defSpace = mContext.getResources().getDimensionPixelOffset(R.dimen.default_gear_space);
-
- mSettingsCogAnimator = new Builder()
- .addFloat(mSettingsButton, "translationX",
- isLayoutRtl() ? (remaining - defSpace) : -(remaining - defSpace), 0)
- .addFloat(mSettingsButton, "rotation", -120, 0)
- .build();
-
+ void updateExpansion() {
setExpansion(mExpansionAmount);
}
@@ -158,20 +111,11 @@ public class QSFooterView extends FrameLayout {
updateResources();
}
- @Override
- public void onRtlPropertiesChanged(int layoutDirection) {
- super.onRtlPropertiesChanged(layoutDirection);
- updateResources();
- }
-
private void updateResources() {
updateFooterAnimator();
MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
lp.bottomMargin = getResources().getDimensionPixelSize(R.dimen.qs_footers_margin_bottom);
setLayoutParams(lp);
- mTunerIconTranslation = mContext.getResources()
- .getDimensionPixelOffset(R.dimen.qs_footer_tuner_icon_translation);
- mTunerIcon.setTranslationX(isLayoutRtl() ? -mTunerIconTranslation : mTunerIconTranslation);
}
private void updateFooterAnimator() {
@@ -197,17 +141,15 @@ public class QSFooterView extends FrameLayout {
mExpandClickListener = onClickListener;
}
- void setExpanded(boolean expanded, boolean isTunerEnabled, boolean multiUserEnabled) {
+ void setExpanded(boolean expanded) {
if (mExpanded == expanded) return;
mExpanded = expanded;
- updateEverything(isTunerEnabled, multiUserEnabled);
+ updateEverything();
}
/** */
public void setExpansion(float headerExpansionFraction) {
mExpansionAmount = headerExpansionFraction;
- if (mSettingsCogAnimator != null) mSettingsCogAnimator.setPosition(headerExpansionFraction);
-
if (mFooterAnimator != null) {
mFooterAnimator.setPosition(headerExpansionFraction);
}
@@ -228,14 +170,6 @@ public class QSFooterView extends FrameLayout {
super.onDetachedFromWindow();
}
- /** */
- public void setListening(boolean listening) {
- if (listening == mListening) {
- return;
- }
- mListening = listening;
- }
-
@Override
public boolean performAccessibilityAction(int action, Bundle arguments) {
if (action == AccessibilityNodeInfo.ACTION_EXPAND) {
@@ -253,50 +187,26 @@ public class QSFooterView extends FrameLayout {
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
}
- void disable(int state2, boolean isTunerEnabled, boolean multiUserEnabled) {
+ void disable(int state2) {
final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
if (disabled == mQsDisabled) return;
mQsDisabled = disabled;
- updateEverything(isTunerEnabled, multiUserEnabled);
+ updateEverything();
}
- void updateEverything(boolean isTunerEnabled, boolean multiUserEnabled) {
+ void updateEverything() {
post(() -> {
- updateVisibilities(isTunerEnabled, multiUserEnabled);
+ updateVisibilities();
updateClickabilities();
setClickable(false);
});
}
private void updateClickabilities() {
- mMultiUserSwitch.setClickable(mMultiUserSwitch.getVisibility() == View.VISIBLE);
- mEdit.setClickable(mEdit.getVisibility() == View.VISIBLE);
- mSettingsButton.setClickable(mSettingsButton.getVisibility() == View.VISIBLE);
mBuildText.setLongClickable(mBuildText.getVisibility() == View.VISIBLE);
}
- private void updateVisibilities(boolean isTunerEnabled, boolean multiUserEnabled) {
- mSettingsContainer.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
- mTunerIcon.setVisibility(isTunerEnabled ? View.VISIBLE : View.INVISIBLE);
- final boolean isDemo = UserManager.isDeviceInDemoMode(mContext);
- mMultiUserSwitch.setVisibility(
- showUserSwitcher(multiUserEnabled) ? View.VISIBLE : View.GONE);
- mSettingsButton.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
-
+ private void updateVisibilities() {
mBuildText.setVisibility(mExpanded && mShouldShowBuildText ? View.VISIBLE : View.INVISIBLE);
}
-
- private boolean showUserSwitcher(boolean multiUserEnabled) {
- return mExpanded && multiUserEnabled;
- }
-
- void onUserInfoChanged(Drawable picture, boolean isGuestUser) {
- if (picture != null && isGuestUser && !(picture instanceof UserIconDrawable)) {
- picture = picture.getConstantState().newDrawable(getResources()).mutate();
- picture.setColorFilter(
- Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorForeground),
- Mode.SRC_IN);
- }
- mMultiUserAvatar.setImageDrawable(picture);
- }
-}
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
index 929aedae6706..c8ae5904e8e9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
@@ -16,39 +16,19 @@
package com.android.systemui.qs;
-import static com.android.systemui.qs.dagger.QSFlagsModule.PM_LITE_ENABLED;
-
import android.content.ClipData;
import android.content.ClipboardManager;
-import android.content.Intent;
-import android.graphics.drawable.Drawable;
-import android.os.UserManager;
import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
-import com.android.internal.jank.InteractionJankMonitor;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.nano.MetricsProto;
-import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
-import com.android.systemui.animation.ActivityLaunchAnimator;
-import com.android.systemui.globalactions.GlobalActionsDialogLite;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.phone.MultiUserSwitchController;
-import com.android.systemui.statusbar.phone.SettingsButton;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.UserInfoController;
-import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.ViewController;
import javax.inject.Inject;
-import javax.inject.Named;
/**
* Controller for {@link QSFooterView}.
@@ -56,137 +36,45 @@ import javax.inject.Named;
@QSScope
public class QSFooterViewController extends ViewController<QSFooterView> implements QSFooter {
- private final UserManager mUserManager;
- private final UserInfoController mUserInfoController;
- private final ActivityStarter mActivityStarter;
- private final DeviceProvisionedController mDeviceProvisionedController;
private final UserTracker mUserTracker;
private final QSPanelController mQsPanelController;
private final QuickQSPanelController mQuickQSPanelController;
- private final TunerService mTunerService;
- private final MetricsLogger mMetricsLogger;
- private final FalsingManager mFalsingManager;
- private final MultiUserSwitchController mMultiUserSwitchController;
- private final SettingsButton mSettingsButton;
- private final View mSettingsButtonContainer;
+ private final QSFooterActionsController mQsFooterActionsController;
private final TextView mBuildText;
- private final View mEdit;
private final PageIndicator mPageIndicator;
- private final View mPowerMenuLite;
- private final boolean mShowPMLiteButton;
- private final GlobalActionsDialogLite mGlobalActionsDialog;
- private final UiEventLogger mUiEventLogger;
-
- private final UserInfoController.OnUserInfoChangedListener mOnUserInfoChangedListener =
- new UserInfoController.OnUserInfoChangedListener() {
- @Override
- public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
- boolean isGuestUser = mUserManager.isGuestUser(KeyguardUpdateMonitor.getCurrentUser());
- mView.onUserInfoChanged(picture, isGuestUser);
- }
- };
-
- private final View.OnClickListener mSettingsOnClickListener = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // Don't do anything until views are unhidden. Don't do anything if the tap looks
- // suspicious.
- if (!mExpanded || mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
- return;
- }
-
- if (v == mSettingsButton) {
- if (!mDeviceProvisionedController.isCurrentUserSetup()) {
- // If user isn't setup just unlock the device and dump them back at SUW.
- mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
- });
- return;
- }
- mMetricsLogger.action(
- mExpanded ? MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH
- : MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH);
- if (mSettingsButton.isTunerClick()) {
- mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
- if (isTunerEnabled()) {
- mTunerService.showResetRequest(
- () -> {
- // Relaunch settings so that the tuner disappears.
- startSettingsActivity();
- });
- } else {
- Toast.makeText(getContext(), R.string.tuner_toast,
- Toast.LENGTH_LONG).show();
- mTunerService.setTunerEnabled(true);
- }
- startSettingsActivity();
-
- });
- } else {
- startSettingsActivity();
- }
- } else if (v == mPowerMenuLite) {
- mUiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS);
- mGlobalActionsDialog.showOrHideDialog(false, true);
- }
- }
- };
-
- private boolean mListening;
- private boolean mExpanded;
@Inject
- QSFooterViewController(QSFooterView view, UserManager userManager,
- UserInfoController userInfoController, ActivityStarter activityStarter,
- DeviceProvisionedController deviceProvisionedController, UserTracker userTracker,
+ QSFooterViewController(QSFooterView view,
+ UserTracker userTracker,
QSPanelController qsPanelController,
- MultiUserSwitchController multiUserSwitchController,
QuickQSPanelController quickQSPanelController,
- TunerService tunerService, MetricsLogger metricsLogger, FalsingManager falsingManager,
- @Named(PM_LITE_ENABLED) boolean showPMLiteButton,
- GlobalActionsDialogLite globalActionsDialog, UiEventLogger uiEventLogger) {
+ QSFooterActionsController qsFooterActionsController) {
super(view);
- mUserManager = userManager;
- mUserInfoController = userInfoController;
- mActivityStarter = activityStarter;
- mDeviceProvisionedController = deviceProvisionedController;
mUserTracker = userTracker;
mQsPanelController = qsPanelController;
mQuickQSPanelController = quickQSPanelController;
- mTunerService = tunerService;
- mMetricsLogger = metricsLogger;
- mFalsingManager = falsingManager;
- mMultiUserSwitchController = multiUserSwitchController;
+ mQsFooterActionsController = qsFooterActionsController;
- mSettingsButton = mView.findViewById(R.id.settings_button);
- mSettingsButtonContainer = mView.findViewById(R.id.settings_button_container);
mBuildText = mView.findViewById(R.id.build);
- mEdit = mView.findViewById(android.R.id.edit);
mPageIndicator = mView.findViewById(R.id.footer_page_indicator);
- mPowerMenuLite = mView.findViewById(R.id.pm_lite);
- mShowPMLiteButton = showPMLiteButton;
- mGlobalActionsDialog = globalActionsDialog;
- mUiEventLogger = uiEventLogger;
}
@Override
protected void onInit() {
super.onInit();
- mMultiUserSwitchController.init();
+ mQsFooterActionsController.init();
}
@Override
protected void onViewAttached() {
- if (mShowPMLiteButton) {
- mPowerMenuLite.setVisibility(View.VISIBLE);
- mPowerMenuLite.setOnClickListener(mSettingsOnClickListener);
- } else {
- mPowerMenuLite.setVisibility(View.GONE);
- }
mView.addOnLayoutChangeListener(
- (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
- mView.updateAnimator(
- right - left, mQuickQSPanelController.getNumQuickTiles()));
- mSettingsButton.setOnClickListener(mSettingsOnClickListener);
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+ mView.updateExpansion();
+ mQsFooterActionsController.updateAnimator(right - left,
+ mQuickQSPanelController.getNumQuickTiles());
+ }
+ );
+
mBuildText.setOnLongClickListener(view -> {
CharSequence buildText = mBuildText.getText();
if (!TextUtils.isEmpty(buildText)) {
@@ -200,17 +88,8 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
}
return false;
});
-
- mEdit.setOnClickListener(view -> {
- if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
- return;
- }
- mActivityStarter.postQSRunnableDismissingKeyguard(() ->
- mQsPanelController.showEdit(view));
- });
-
mQsPanelController.setFooterPageIndicator(mPageIndicator);
- mView.updateEverything(isTunerEnabled(), mMultiUserSwitchController.isMultiUserEnabled());
+ mView.updateEverything();
}
@Override
@@ -225,38 +104,25 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
@Override
public void setExpanded(boolean expanded) {
- mExpanded = expanded;
- mView.setExpanded(
- expanded, isTunerEnabled(), mMultiUserSwitchController.isMultiUserEnabled());
- }
-
- @Override
- public int getHeight() {
- return mView.getHeight();
+ mQsFooterActionsController.setExpanded(expanded);
+ mView.setExpanded(expanded);
}
@Override
public void setExpansion(float expansion) {
mView.setExpansion(expansion);
+ mQsFooterActionsController.setExpansion(expansion);
}
@Override
public void setListening(boolean listening) {
- if (mListening == listening) {
- return;
- }
-
- mListening = listening;
- if (mListening) {
- mUserInfoController.addCallback(mOnUserInfoChangedListener);
- } else {
- mUserInfoController.removeCallback(mOnUserInfoChangedListener);
- }
+ mQsFooterActionsController.setListening(listening);
}
@Override
public void setKeyguardShowing(boolean keyguardShowing) {
mView.setKeyguardShowing();
+ mQsFooterActionsController.setKeyguardShowing();
}
/** */
@@ -267,19 +133,7 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
@Override
public void disable(int state1, int state2, boolean animate) {
- mView.disable(state2, isTunerEnabled(), mMultiUserSwitchController.isMultiUserEnabled());
- }
-
- private void startSettingsActivity() {
- ActivityLaunchAnimator.Controller animationController =
- mSettingsButtonContainer != null ? ActivityLaunchAnimator.Controller.fromView(
- mSettingsButtonContainer,
- InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON) : null;
- mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS),
- true /* dismissShade */, animationController);
- }
-
- private boolean isTunerEnabled() {
- return mTunerService.isTunerEnabled();
+ mView.disable(state2);
+ mQsFooterActionsController.disable(state2);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 68206ca0eed8..4242e1bb666b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -411,6 +411,10 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
}
}
+ public QSPanelController getQSPanelController() {
+ return mQSPanelController;
+ }
+
public void setBrightnessMirrorController(
BrightnessMirrorController brightnessMirrorController) {
mQSPanelController.setBrightnessMirror(brightnessMirrorController);
@@ -506,11 +510,13 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
: headerTranslation);
}
int currentHeight = getView().getHeight();
- mLastHeaderTranslation = headerTranslation;
- if (expansion == mLastQSExpansion && mLastKeyguardAndExpanded == onKeyguardAndExpanded
- && mLastViewHeight == currentHeight) {
+ if (expansion == mLastQSExpansion
+ && mLastKeyguardAndExpanded == onKeyguardAndExpanded
+ && mLastViewHeight == currentHeight
+ && mLastHeaderTranslation == headerTranslation) {
return;
}
+ mLastHeaderTranslation = headerTranslation;
mLastQSExpansion = expansion;
mLastKeyguardAndExpanded = onKeyguardAndExpanded;
mLastViewHeight = currentHeight;
@@ -530,8 +536,8 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
}
mFooter.setExpansion(onKeyguardAndExpanded ? 1 : expansion);
mQSPanelController.setRevealExpansion(expansion);
- mQSPanelController.getTileLayout().setExpansion(expansion);
- mQuickQSPanelController.getTileLayout().setExpansion(expansion);
+ mQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation);
+ mQuickQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation);
mQSPanelScrollView.setTranslationY(translationScaleY * heightDiff);
if (fullyCollapsed) {
mQSPanelScrollView.setScrollY(0);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 0c655103d888..28aa884d6f9e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -27,12 +27,15 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
+import androidx.annotation.VisibleForTesting;
+
import com.android.internal.logging.UiEventLogger;
import com.android.internal.widget.RemeasuringLinearLayout;
import com.android.systemui.R;
@@ -386,13 +389,7 @@ public class QSPanel extends LinearLayout implements Tunable {
}
private void switchToParent(View child, ViewGroup parent, int index) {
- ViewGroup currentParent = (ViewGroup) child.getParent();
- if (currentParent != parent || currentParent.indexOfChild(child) != index) {
- if (currentParent != null) {
- currentParent.removeView(child);
- }
- parent.addView(child, index);
- }
+ switchToParent(child, parent, index, getDumpableTag());
}
/** Call when orientation has changed and MediaHost needs to be adjusted. */
@@ -739,7 +736,7 @@ public class QSPanel extends LinearLayout implements Tunable {
void setListening(boolean listening, UiEventLogger uiEventLogger);
/**
- * Set the minimum number of rows to show
+ * Sets the minimum number of rows to show
*
* @param minRows the minimum.
*/
@@ -748,7 +745,7 @@ public class QSPanel extends LinearLayout implements Tunable {
}
/**
- * Set the max number of columns to show
+ * Sets the max number of columns to show
*
* @param maxColumns the maximum
*
@@ -758,7 +755,10 @@ public class QSPanel extends LinearLayout implements Tunable {
return false;
}
- default void setExpansion(float expansion) {}
+ /**
+ * Sets the expansion value and proposedTranslation to panel.
+ */
+ default void setExpansion(float expansion, float proposedTranslation) {}
int getNumVisibleTiles();
}
@@ -766,4 +766,29 @@ public class QSPanel extends LinearLayout implements Tunable {
interface OnConfigurationChangedListener {
void onConfigurationChange(Configuration newConfig);
}
+
+ @VisibleForTesting
+ static void switchToParent(View child, ViewGroup parent, int index, String tag) {
+ if (parent == null) {
+ Log.w(tag, "Trying to move view to null parent",
+ new IllegalStateException());
+ return;
+ }
+ ViewGroup currentParent = (ViewGroup) child.getParent();
+ if (currentParent != parent) {
+ if (currentParent != null) {
+ currentParent.removeView(child);
+ }
+ parent.addView(child, index);
+ return;
+ }
+ // Same parent, we are just changing indices
+ int currentIndex = parent.indexOfChild(child);
+ if (currentIndex == index) {
+ // We want to be in the same place. Nothing to do here
+ return;
+ }
+ parent.removeView(child);
+ parent.addView(child, index);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 756ad9939886..ae3dde10756f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -39,6 +39,7 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.qs.QSFactory;
import com.android.systemui.plugins.qs.QSTile;
@@ -51,7 +52,6 @@ import com.android.systemui.qs.external.TileServices;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -512,33 +512,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
}
}
}
- // TODO(b/174753536): Move it into the config file.
- // Only do the below hacking when at least one of the below tiles exist
- // --InternetTile
- // --WiFiTile
- // --CellularTIle
- if (tiles.contains("internet") || tiles.contains("wifi") || tiles.contains("cell")) {
- if (FeatureFlags.isProviderModelSettingEnabled(context)) {
- if (!tiles.contains("internet")) {
- if (tiles.contains("wifi")) {
- // Replace the WiFi with Internet, and remove the Cell
- tiles.set(tiles.indexOf("wifi"), "internet");
- tiles.remove("cell");
- } else if (tiles.contains("cell")) {
- // Replace the Cell with Internet
- tiles.set(tiles.indexOf("cell"), "internet");
- }
- } else {
- tiles.remove("wifi");
- tiles.remove("cell");
- }
- } else {
- if (tiles.contains("internet")) {
- tiles.set(tiles.indexOf("internet"), "wifi");
- tiles.add("cell");
- }
- }
- }
return tiles;
}
@@ -558,14 +531,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
&& GarbageMonitor.ADD_MEMORY_TILE_TO_DEFAULT_ON_DEBUGGABLE_BUILDS) {
tiles.add(GarbageMonitor.MemoryTile.TILE_SPEC);
}
- // TODO(b/174753536): Change the config file directly.
- // Filter out unused tiles from the default QS config.
- if (FeatureFlags.isProviderModelSettingEnabled(context)) {
- tiles.remove("cell");
- tiles.remove("wifi");
- } else {
- tiles.remove("internet");
- }
return tiles;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index f1c1e12b9648..613e7f87371c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -171,6 +171,8 @@ public class QuickQSPanel extends QSPanel {
static class QQSSideLabelTileLayout extends SideLabelTileLayout {
+ private boolean mLastSelected;
+
QQSSideLabelTileLayout(Context context) {
super(context, null);
setClipChildren(false);
@@ -216,5 +218,29 @@ public class QuickQSPanel extends QSPanel {
}
}
}
+
+ @Override
+ public void setExpansion(float expansion, float proposedTranslation) {
+ if (expansion > 0f && expansion < 1f) {
+ return;
+ }
+ // The cases we must set select for marquee when QQS/QS collapsed, and QS full expanded.
+ // Expansion == 0f is when QQS is fully showing (as opposed to 1f, which is QS). At this
+ // point we want them to be selected so the tiles will marquee (but not at other points
+ // of expansion.
+ boolean selected = (expansion == 1f || proposedTranslation < 0f);
+ if (mLastSelected == selected) {
+ return;
+ }
+ // We set it as not important while we change this, so setting each tile as selected
+ // will not cause them to announce themselves until the user has actually selected the
+ // item.
+ setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+ for (int i = 0; i < getChildCount(); i++) {
+ getChildAt(i).setSelected(selected);
+ }
+ setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+ mLastSelected = selected;
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 34fc2c0515a5..9e6a8b86ebba 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -35,8 +35,8 @@ import android.widget.Space;
import androidx.annotation.NonNull;
import com.android.settingslib.Utils;
-import com.android.systemui.BatteryMeterView;
import com.android.systemui.R;
+import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.qs.QSDetail.Callback;
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
import com.android.systemui.statusbar.phone.StatusBarWindowView;
@@ -133,8 +133,6 @@ public class QuickStatusBarHeader extends FrameLayout {
updateResources();
- // Don't need to worry about tuner settings for this icon
- mBatteryRemainingIcon.setIgnoreTunerUpdates(true);
// QS will always show the estimate, and BatteryMeterView handles the case where
// it's unavailable or charging
mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index 98eb38139e0e..df601003f9da 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -25,9 +25,11 @@ import androidx.annotation.NonNull;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
+import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.privacy.OngoingPrivacyChip;
import com.android.systemui.privacy.PrivacyChipEvent;
@@ -37,7 +39,6 @@ import com.android.systemui.privacy.PrivacyItemController;
import com.android.systemui.privacy.logging.PrivacyLogger;
import com.android.systemui.qs.carrier.QSCarrierGroupController;
import com.android.systemui.qs.dagger.QSScope;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusIconContainer;
import com.android.systemui.statusbar.policy.Clock;
@@ -69,6 +70,7 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
private final PrivacyLogger mPrivacyLogger;
private final PrivacyDialogController mPrivacyDialogController;
private final QSExpansionPathInterpolator mQSExpansionPathInterpolator;
+ private final BatteryMeterViewController mBatteryMeterViewController;
private final FeatureFlags mFeatureFlags;
private boolean mListening;
@@ -134,6 +136,7 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
SysuiColorExtractor colorExtractor,
PrivacyDialogController privacyDialogController,
QSExpansionPathInterpolator qsExpansionPathInterpolator,
+ BatteryMeterViewController batteryMeterViewController,
FeatureFlags featureFlags) {
super(view);
mPrivacyItemController = privacyItemController;
@@ -145,6 +148,7 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
mPrivacyLogger = privacyLogger;
mPrivacyDialogController = privacyDialogController;
mQSExpansionPathInterpolator = qsExpansionPathInterpolator;
+ mBatteryMeterViewController = batteryMeterViewController;
mFeatureFlags = featureFlags;
mQSCarrierGroupController = qsCarrierGroupControllerBuilder
@@ -167,6 +171,14 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
mCameraSlot = getResources().getString(com.android.internal.R.string.status_bar_camera);
mMicSlot = getResources().getString(com.android.internal.R.string.status_bar_microphone);
mLocationSlot = getResources().getString(com.android.internal.R.string.status_bar_location);
+
+ // Don't need to worry about tuner settings for this icon
+ mBatteryMeterViewController.ignoreTunerUpdates();
+ }
+
+ @Override
+ protected void onInit() {
+ mBatteryMeterViewController.init();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
index 67c4d33d53d3..953f9fb10657 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
@@ -40,8 +40,8 @@ import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.util.CarrierConfigTracker;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 3cb715cee8e9..1c20a860a3cb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -34,6 +34,7 @@ import android.widget.Button;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTile.State;
import com.android.systemui.qs.QSTileHost;
@@ -41,7 +42,6 @@ import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.util.leak.GarbageMonitor;
import java.util.ArrayList;
@@ -63,7 +63,6 @@ public class TileQueryHelper {
private final Executor mBgExecutor;
private final Context mContext;
private final UserTracker mUserTracker;
- private final FeatureFlags mFeatureFlags;
private TileStateListener mListener;
private boolean mFinished;
@@ -73,14 +72,12 @@ public class TileQueryHelper {
Context context,
UserTracker userTracker,
@Main Executor mainExecutor,
- @Background Executor bgExecutor,
- FeatureFlags featureFlags
+ @Background Executor bgExecutor
) {
mContext = context;
mMainExecutor = mainExecutor;
mBgExecutor = bgExecutor;
mUserTracker = userTracker;
- mFeatureFlags = featureFlags;
}
public void setListener(TileStateListener listener) {
@@ -121,19 +118,11 @@ public class TileQueryHelper {
}
final ArrayList<QSTile> tilesToAdd = new ArrayList<>();
- // TODO(b/174753536): Move it into the config file.
- if (mFeatureFlags.isProviderModelSettingEnabled()) {
- possibleTiles.remove("cell");
- possibleTiles.remove("wifi");
- } else {
- possibleTiles.remove("internet");
- }
for (String spec : possibleTiles) {
// Only add current and stock tiles that can be created from QSFactoryImpl.
// Do not include CustomTile. Those will be created by `addPackageTiles`.
if (spec.startsWith(CustomTile.PREFIX)) continue;
- // TODO(b/174753536): Move it into the config file.
final QSTile tile = host.createTile(spec);
if (tile == null) {
continue;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
index 6fa44eb513e9..103ac656e846 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
@@ -20,7 +20,7 @@ import android.content.Context;
import android.hardware.display.ColorDisplayManager;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.util.settings.GlobalSettings;
import javax.inject.Named;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
index 36a1910c600a..2de2d040f6e3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
@@ -23,10 +23,12 @@ import android.view.LayoutInflater;
import android.view.View;
import com.android.systemui.R;
+import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.dagger.qualifiers.RootView;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qs.QSContainerImpl;
import com.android.systemui.qs.QSFooter;
+import com.android.systemui.qs.QSFooterActionsView;
import com.android.systemui.qs.QSFooterView;
import com.android.systemui.qs.QSFooterViewController;
import com.android.systemui.qs.QSFragment;
@@ -109,12 +111,24 @@ public interface QSFragmentModule {
/** */
@Provides
+ static BatteryMeterView providesBatteryMeterView(QuickStatusBarHeader quickStatusBarHeader) {
+ return quickStatusBarHeader.findViewById(R.id.batteryRemainingIcon);
+ }
+
+ /** */
+ @Provides
static QSFooterView providesQSFooterView(@RootView View view) {
return view.findViewById(R.id.qs_footer);
}
/** */
@Provides
+ static QSFooterActionsView providesQSFooterActionsView(@RootView View view) {
+ return view.findViewById(R.id.qs_footer_actions_container);
+ }
+
+ /** */
+ @Provides
@QSScope
static QSFooter providesQSFooter(QSFooterViewController qsFooterViewController) {
qsFooterViewController.init();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 70685a68e182..222539d49526 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -195,9 +195,6 @@ open class QSTileViewImpl @JvmOverloads constructor(
// sibling methods to have special behavior for labelContainer.
labelContainer.forceUnspecifiedMeasure = true
secondaryLabel.alpha = 0f
- // Do not marque in QQS
- label.ellipsize = TextUtils.TruncateAt.END
- secondaryLabel.ellipsize = TextUtils.TruncateAt.END
}
setLabelColor(getLabelColorForState(QSTile.State.DEFAULT_STATE))
setSecondaryLabelColor(getSecondaryLabelColorForState(QSTile.State.DEFAULT_STATE))
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index eb72296d5c5b..ad7c52212a71 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -427,6 +427,19 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
};
+ private final BroadcastReceiver mDebugAnyPackageChangedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String[] stringArrayExtra = intent.getStringArrayExtra(
+ Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
+ Log.e("b/188806432", intent.toString()
+ + (stringArrayExtra != null
+ ? ", EXTRA_CHANGED_COMPONENT_NAME_LIST: " + String.join(", ",
+ stringArrayExtra)
+ : ""));
+ }
+ };
+
private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
@@ -566,6 +579,13 @@ public class OverviewProxyService extends CurrentUserTracker implements
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
mContext.registerReceiver(mLauncherStateChangedReceiver, filter);
+ // b/188806432
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addDataScheme("package");
+ filter.addDataSchemeSpecificPart("", PatternMatcher.PATTERN_PREFIX);
+ mContext.registerReceiver(mDebugAnyPackageChangedReceiver, filter);
+
// Listen for status bar state changes
statusBarWinController.registerCallback(mStatusBarWindowCallback);
mScreenshotHelper = new ScreenshotHelper(context);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
index ce6e46937c25..93e5021fd6e0 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
@@ -45,9 +45,12 @@ import androidx.concurrent.futures.CallbackToFutureAdapter;
import androidx.concurrent.futures.CallbackToFutureAdapter.Completer;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.dagger.qualifiers.Background;
import com.google.common.util.concurrent.ListenableFuture;
+import java.util.concurrent.Executor;
+
import javax.inject.Inject;
/**
@@ -63,6 +66,8 @@ public class ScrollCaptureClient {
private static final String TAG = LogConfig.logTag(ScrollCaptureClient.class);
+ private final Executor mBgExecutor;
+
/**
* Represents the connection to a target window and provides a mechanism for requesting tiles.
*/
@@ -155,8 +160,10 @@ public class ScrollCaptureClient {
private IBinder mHostWindowToken;
@Inject
- public ScrollCaptureClient(@UiContext Context context, IWindowManager windowManagerService) {
+ public ScrollCaptureClient(IWindowManager windowManagerService,
+ @Background Executor bgExecutor, @UiContext Context context) {
requireNonNull(context.getDisplay(), "context must be associated with a Display!");
+ mBgExecutor = bgExecutor;
mWindowManagerService = windowManagerService;
}
@@ -220,21 +227,25 @@ public class ScrollCaptureClient {
return "";
}
SessionWrapper session = new SessionWrapper(connection, response.getWindowBounds(),
- response.getBoundsInWindow(), maxPages);
+ response.getBoundsInWindow(), maxPages, mBgExecutor);
session.start(completer);
return "IScrollCaptureCallbacks#onCaptureStarted";
});
}
private static class SessionWrapper extends IScrollCaptureCallbacks.Stub implements Session,
- IBinder.DeathRecipient {
+ IBinder.DeathRecipient, ImageReader.OnImageAvailableListener {
private IScrollCaptureConnection mConnection;
+ private final Executor mBgExecutor;
+ private final Object mLock = new Object();
private ImageReader mReader;
private final int mTileHeight;
private final int mTileWidth;
private Rect mRequestRect;
+ private Rect mCapturedArea;
+ private Image mCapturedImage;
private boolean mStarted;
private final int mTargetHeight;
@@ -247,7 +258,8 @@ public class ScrollCaptureClient {
private Completer<Void> mEndCompleter;
private SessionWrapper(IScrollCaptureConnection connection, Rect windowBounds,
- Rect boundsInWindow, float maxPages) throws RemoteException {
+ Rect boundsInWindow, float maxPages, Executor bgExecutor)
+ throws RemoteException {
mConnection = requireNonNull(connection);
mConnection.asBinder().linkToDeath(SessionWrapper.this, 0);
mWindowBounds = requireNonNull(windowBounds);
@@ -259,7 +271,7 @@ public class ScrollCaptureClient {
mTileWidth = mBoundsInWindow.width();
mTileHeight = pxPerTile / mBoundsInWindow.width();
mTargetHeight = (int) (mBoundsInWindow.height() * maxPages);
-
+ mBgExecutor = bgExecutor;
if (DEBUG_SCROLL) {
Log.d(TAG, "boundsInWindow: " + mBoundsInWindow);
Log.d(TAG, "tile size: " + mTileWidth + "x" + mTileHeight);
@@ -289,6 +301,7 @@ public class ScrollCaptureClient {
mReader = ImageReader.newInstance(mTileWidth, mTileHeight, PixelFormat.RGBA_8888,
MAX_TILES, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
mStartCompleter = completer;
+ mReader.setOnImageAvailableListenerWithExecutor(this, mBgExecutor);
try {
mCancellationSignal = mConnection.startCapture(mReader.getSurface(), this);
completer.addCancellationListener(() -> {
@@ -339,9 +352,34 @@ public class ScrollCaptureClient {
@BinderThread
@Override
- public void onImageRequestCompleted(int flags, Rect contentArea) {
- Image image = mReader.acquireLatestImage();
- mTileRequestCompleter.set(new CaptureResult(image, mRequestRect, contentArea));
+ public void onImageRequestCompleted(int flagsUnused, Rect contentArea) {
+ synchronized (mLock) {
+ mCapturedArea = contentArea;
+ if (mCapturedImage != null || (mCapturedArea == null || mCapturedArea.isEmpty())) {
+ completeCaptureRequest();
+ }
+ }
+ }
+
+ /** @see ImageReader.OnImageAvailableListener */
+ @Override
+ public void onImageAvailable(ImageReader reader) {
+ synchronized (mLock) {
+ mCapturedImage = mReader.acquireLatestImage();
+ if (mCapturedArea != null) {
+ completeCaptureRequest();
+ }
+ }
+ }
+
+ /** Produces a result for the caller as soon as both asynchronous results are received. */
+ private void completeCaptureRequest() {
+ CaptureResult result =
+ new CaptureResult(mCapturedImage, mRequestRect, mCapturedArea);
+ mCapturedImage = null;
+ mRequestRect = null;
+ mCapturedArea = null;
+ mTileRequestCompleter.set(result);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
index 185b8ef04c4c..acc6ee130539 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
@@ -30,7 +30,6 @@ import android.hardware.display.DisplayManager.DisplayListener;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
-import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -47,8 +46,8 @@ import com.android.internal.display.BrightnessSynchronizer;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.RestrictedLockUtilsInternal;
-import com.android.systemui.Dependency;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
@@ -288,12 +287,15 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig
}
};
- public BrightnessController(Context context, ToggleSlider control,
- BroadcastDispatcher broadcastDispatcher) {
+ public BrightnessController(
+ Context context,
+ ToggleSlider control,
+ BroadcastDispatcher broadcastDispatcher,
+ @Background Handler bgHandler) {
mContext = context;
mControl = control;
mControl.setMax(GAMMA_SPACE_MAX);
- mBackgroundHandler = new Handler((Looper) Dependency.get(Dependency.BG_LOOPER));
+ mBackgroundHandler = bgHandler;
mUserTracker = new CurrentUserTracker(broadcastDispatcher) {
@Override
public void onUserSwitched(int newUserId) {
@@ -464,16 +466,25 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig
public static class Factory {
private final Context mContext;
private final BroadcastDispatcher mBroadcastDispatcher;
+ private final Handler mBackgroundHandler;
@Inject
- public Factory(Context context, BroadcastDispatcher broadcastDispatcher) {
+ public Factory(
+ Context context,
+ BroadcastDispatcher broadcastDispatcher,
+ @Background Handler bgHandler) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
+ mBackgroundHandler = bgHandler;
}
/** Create a {@link BrightnessController} */
public BrightnessController create(ToggleSlider toggleSlider) {
- return new BrightnessController(mContext, toggleSlider, mBroadcastDispatcher);
+ return new BrightnessController(
+ mContext,
+ toggleSlider,
+ mBroadcastDispatcher,
+ mBackgroundHandler);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
index 0f97e43c466b..8fc831a7ce4d 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
@@ -21,6 +21,7 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import android.app.Activity;
import android.os.Bundle;
+import android.os.Handler;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
@@ -32,6 +33,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Background;
import javax.inject.Inject;
@@ -41,13 +43,16 @@ public class BrightnessDialog extends Activity {
private BrightnessController mBrightnessController;
private final BrightnessSlider.Factory mToggleSliderFactory;
private final BroadcastDispatcher mBroadcastDispatcher;
+ private final Handler mBackgroundHandler;
@Inject
public BrightnessDialog(
BroadcastDispatcher broadcastDispatcher,
- BrightnessSlider.Factory factory) {
+ BrightnessSlider.Factory factory,
+ @Background Handler bgHandler) {
mBroadcastDispatcher = broadcastDispatcher;
mToggleSliderFactory = factory;
+ mBackgroundHandler = bgHandler;
}
@@ -76,7 +81,8 @@ public class BrightnessDialog extends Activity {
controller.init();
frame.addView(controller.getRootView(), MATCH_PARENT, WRAP_CONTENT);
- mBrightnessController = new BrightnessController(this, controller, mBroadcastDispatcher);
+ mBrightnessController = new BrightnessController(
+ this, controller, mBroadcastDispatcher, mBackgroundHandler);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java
index 7dc9e8ba0edb..b0e320ad1e2f 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java
@@ -23,7 +23,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.SeekBar;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.settingslib.RestrictedLockUtils;
@@ -139,7 +138,7 @@ public class BrightnessSlider extends ViewController<BrightnessSliderView> imple
* @param c
*/
@Override
- public void setMirrorControllerAndMirror(@NonNull BrightnessMirrorController c) {
+ public void setMirrorControllerAndMirror(BrightnessMirrorController c) {
mMirrorController = c;
setMirror(c.getToggleSlider());
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSlider.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSlider.java
index 3ef4ad223120..5de22d43a21b 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSlider.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSlider.java
@@ -18,8 +18,6 @@ package com.android.systemui.settings.brightness;
import android.view.MotionEvent;
-import androidx.annotation.NonNull;
-
import com.android.settingslib.RestrictedLockUtils;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
@@ -29,7 +27,7 @@ public interface ToggleSlider {
}
void setEnforcedAdmin(RestrictedLockUtils.EnforcedAdmin admin);
- void setMirrorControllerAndMirror(@NonNull BrightnessMirrorController c);
+ void setMirrorControllerAndMirror(BrightnessMirrorController c);
boolean mirrorTouchEvent(MotionEvent ev);
void setOnChangedListener(Listener l);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
index acfd998ff6e4..8e6cf36f8e74 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
@@ -17,14 +17,10 @@
package com.android.systemui.statusbar;
import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
-import android.view.DisplayCutout;
import android.view.View;
import android.widget.TextView;
@@ -42,22 +38,14 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry.
public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
private static final String HEADS_UP_STATUS_BAR_VIEW_SUPER_PARCELABLE =
"heads_up_status_bar_view_super_parcelable";
- private static final String FIRST_LAYOUT = "first_layout";
private static final String VISIBILITY = "visibility";
private static final String ALPHA = "alpha";
- private int mAbsoluteStartPadding;
- private int mEndMargin;
+ private final Rect mLayoutedIconRect = new Rect();
+ private final int[] mTmpPosition = new int[2];
+ private final Rect mIconDrawingRect = new Rect();
private View mIconPlaceholder;
private TextView mTextView;
private NotificationEntry mShowingEntry;
- private Rect mLayoutedIconRect = new Rect();
- private int[] mTmpPosition = new int[2];
- private boolean mFirstLayout = true;
- private int mMaxWidth;
- private int mSysWinInset;
- private int mCutOutInset;
- private Rect mIconDrawingRect = new Rect();
- private Point mDisplaySize;
private Runnable mOnDrawingRectChangedListener;
public HeadsUpStatusBarView(Context context) {
@@ -75,40 +63,6 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
public HeadsUpStatusBarView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- Resources res = getResources();
- mAbsoluteStartPadding = res.getDimensionPixelSize(R.dimen.notification_side_paddings)
- + res.getDimensionPixelSize(
- com.android.internal.R.dimen.notification_content_margin_start);
- mEndMargin = res.getDimensionPixelSize(
- com.android.internal.R.dimen.notification_content_margin_end);
- setPaddingRelative(mAbsoluteStartPadding, 0, mEndMargin, 0);
- updateMaxWidth();
- }
-
- private void updateMaxWidth() {
- int maxWidth = getResources().getDimensionPixelSize(R.dimen.qs_panel_width);
- if (maxWidth != mMaxWidth) {
- // maxWidth doesn't work with fill_parent, let's manually make it at most as big as the
- // notification panel
- mMaxWidth = maxWidth;
- requestLayout();
- }
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- if (mMaxWidth > 0) {
- int newSize = Math.min(MeasureSpec.getSize(widthMeasureSpec), mMaxWidth);
- widthMeasureSpec = MeasureSpec.makeMeasureSpec(newSize,
- MeasureSpec.getMode(widthMeasureSpec));
- }
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- updateMaxWidth();
}
@Override
@@ -116,7 +70,6 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
Bundle bundle = new Bundle();
bundle.putParcelable(HEADS_UP_STATUS_BAR_VIEW_SUPER_PARCELABLE,
super.onSaveInstanceState());
- bundle.putBoolean(FIRST_LAYOUT, mFirstLayout);
bundle.putInt(VISIBILITY, getVisibility());
bundle.putFloat(ALPHA, getAlpha());
@@ -125,7 +78,7 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
@Override
public void onRestoreInstanceState(Parcelable state) {
- if (state == null || !(state instanceof Bundle)) {
+ if (!(state instanceof Bundle)) {
super.onRestoreInstanceState(state);
return;
}
@@ -133,7 +86,6 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
Bundle bundle = (Bundle) state;
Parcelable superState = bundle.getParcelable(HEADS_UP_STATUS_BAR_VIEW_SUPER_PARCELABLE);
super.onRestoreInstanceState(superState);
- mFirstLayout = bundle.getBoolean(FIRST_LAYOUT, true);
if (bundle.containsKey(VISIBILITY)) {
setVisibility(bundle.getInt(VISIBILITY));
}
@@ -185,70 +137,22 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
mIconPlaceholder.getLocationOnScreen(mTmpPosition);
- int left = (int) (mTmpPosition[0] - getTranslationX());
+ int left = mTmpPosition[0];
int top = mTmpPosition[1];
int right = left + mIconPlaceholder.getWidth();
int bottom = top + mIconPlaceholder.getHeight();
mLayoutedIconRect.set(left, top, right, bottom);
updateDrawingRect();
- int targetPadding = mAbsoluteStartPadding + mSysWinInset + mCutOutInset;
- boolean isRtl = isLayoutRtl();
- int start = isRtl ? (mDisplaySize.x - right) : left;
- if (start != targetPadding) {
- int newPadding = targetPadding - start + getPaddingStart();
- setPaddingRelative(newPadding, 0, mEndMargin, 0);
- }
- if (mFirstLayout) {
- // we need to do the padding calculation in the first frame, so the layout specified
- // our visibility to be INVISIBLE in the beginning. let's correct that and set it
- // to GONE.
- setVisibility(GONE);
- mFirstLayout = false;
- }
- }
-
- /** In order to do UI alignment, this view will be notified by
- * {@link com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout}.
- * After scroller laid out, the scroller will tell this view about scroller's getX()
- * @param translationX how to translate the horizontal position
- */
- public void setPanelTranslation(float translationX) {
- setTranslationX(translationX);
- updateDrawingRect();
}
private void updateDrawingRect() {
float oldLeft = mIconDrawingRect.left;
mIconDrawingRect.set(mLayoutedIconRect);
- mIconDrawingRect.offset((int) getTranslationX(), 0);
if (oldLeft != mIconDrawingRect.left && mOnDrawingRectChangedListener != null) {
mOnDrawingRectChangedListener.run();
}
}
- @Override
- protected boolean fitSystemWindows(Rect insets) {
- boolean isRtl = isLayoutRtl();
- mSysWinInset = isRtl ? insets.right : insets.left;
- DisplayCutout displayCutout = getRootWindowInsets().getDisplayCutout();
- mCutOutInset = (displayCutout != null)
- ? (isRtl ? displayCutout.getSafeInsetRight() : displayCutout.getSafeInsetLeft())
- : 0;
-
- getDisplaySize();
-
- // For Double Cut Out mode, the System window navigation bar is at the right
- // side of the left cut out. In this condition, mSysWinInset include the left cut
- // out width so we set mCutOutInset to be 0. For RTL, the condition is the same.
- // The navigation bar is at the left side of the right cut out and include the
- // right cut out width.
- if (mSysWinInset != 0) {
- mCutOutInset = 0;
- }
-
- return super.fitSystemWindows(insets);
- }
-
public NotificationEntry getShowingEntry() {
return mShowingEntry;
}
@@ -264,17 +168,4 @@ public class HeadsUpStatusBarView extends AlphaOptimizedLinearLayout {
public void setOnDrawingRectChangedListener(Runnable onDrawingRectChangedListener) {
mOnDrawingRectChangedListener = onDrawingRectChangedListener;
}
-
- private void getDisplaySize() {
- if (mDisplaySize == null) {
- mDisplaySize = new Point();
- }
- getDisplay().getRealSize(mDisplaySize);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- getDisplaySize();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 92922b634d64..503b5c0ee4b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -821,6 +821,20 @@ public class KeyguardIndicationController {
}
}
+ private void showTryFingerprintMsg() {
+ if (mKeyguardUpdateMonitor.isUdfpsAvailable()) {
+ // if udfps available, there will always be a tappable affordance to unlock
+ // For example, the lock icon
+ if (mKeyguardBypassController.getUserHasDeviceEntryIntent()) {
+ showTransientIndication(R.string.keyguard_unlock_press);
+ } else {
+ showTransientIndication(R.string.keyguard_face_failed_use_fp);
+ }
+ } else {
+ showTransientIndication(R.string.keyguard_try_fingerprint);
+ }
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("KeyguardIndicationController:");
pw.println(" mInitialTextColorState: " + mInitialTextColorState);
@@ -891,7 +905,7 @@ public class KeyguardIndicationController {
return;
}
- boolean showSwipeToUnlock =
+ boolean showActionToUnlock =
msgId == KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
mStatusBarKeyguardViewManager.showBouncerMessage(helpString,
@@ -899,13 +913,11 @@ public class KeyguardIndicationController {
} else if (mKeyguardUpdateMonitor.isScreenOn()) {
if (biometricSourceType == BiometricSourceType.FACE
&& shouldSuppressFaceMsgAndShowTryFingerprintMsg()) {
- // suggest trying fingerprint
- showTransientIndication(R.string.keyguard_try_fingerprint);
+ showTryFingerprintMsg();
return;
}
- showTransientIndication(helpString, false /* isError */, showSwipeToUnlock);
- }
- if (showSwipeToUnlock) {
+ showTransientIndication(helpString, false /* isError */, showActionToUnlock);
+ } else if (showActionToUnlock) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SHOW_ACTION_TO_UNLOCK),
TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
}
@@ -921,8 +933,7 @@ public class KeyguardIndicationController {
&& shouldSuppressFaceMsgAndShowTryFingerprintMsg()
&& !mStatusBarKeyguardViewManager.isBouncerShowing()
&& mKeyguardUpdateMonitor.isScreenOn()) {
- // suggest trying fingerprint
- showTransientIndication(R.string.keyguard_try_fingerprint);
+ showTryFingerprintMsg();
return;
}
if (msgId == FaceManager.FACE_ERROR_TIMEOUT) {
@@ -931,11 +942,10 @@ public class KeyguardIndicationController {
if (!mStatusBarKeyguardViewManager.isBouncerShowing()
&& mKeyguardUpdateMonitor.isUdfpsEnrolled()
&& mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) {
- // suggest trying fingerprint
- showTransientIndication(R.string.keyguard_try_fingerprint);
+ showTryFingerprintMsg();
} else if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) {
mStatusBarKeyguardViewManager.showBouncerMessage(
- mContext.getResources().getString(R.string.keyguard_try_fingerprint),
+ mContext.getResources().getString(R.string.keyguard_unlock_press),
mInitialTextColorState
);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 8969b4d1bcbc..36d2d866f74d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -52,6 +52,7 @@ import com.android.systemui.Dumpable;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.MediaData;
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.SmartspaceMediaData;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index db553e4b093b..002c9c7d2544 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -178,7 +178,8 @@ class NotificationShadeDepthController @Inject constructor(
blurUtils.minBlurRadius, blurUtils.maxBlurRadius)
var combinedBlur = (shadeSpring.radius * INTERACTION_BLUR_FRACTION +
normalizedBlurRadius * ANIMATION_BLUR_FRACTION).toInt()
- combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsPanelExpansion))
+ val qsExpandedRatio = qsPanelExpansion * shadeExpansion
+ combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsExpandedRatio))
combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(transitionToFullShadeProgress))
var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius).toFloat()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
index 22bbb81b44e6..d74297ee8b76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
@@ -29,7 +29,7 @@ import com.android.internal.logging.UiEvent
import com.android.internal.logging.UiEventLogger
import com.android.settingslib.Utils
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.policy.BatteryController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index a05e950240f7..f2cf93ed9dc8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -24,13 +24,13 @@ import android.os.Handler;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.carrier.QSCarrierGroupController;
import com.android.systemui.statusbar.ActionClickLogger;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.MediaArtworkProcessor;
import com.android.systemui.statusbar.NotificationClickNotifier;
import com.android.systemui.statusbar.NotificationListener;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index 71546ae07ffc..fdbe72879374 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -31,6 +31,8 @@ import android.os.Handler
import android.os.UserHandle
import android.provider.Settings
import android.view.View
+import android.view.View.GONE
+import android.view.View.VISIBLE
import android.view.ViewGroup
import com.android.settingslib.Utils
import com.android.systemui.R
@@ -43,15 +45,22 @@ import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.notification.AnimatableProperty
+import com.android.systemui.statusbar.notification.PropertyAnimator
+import com.android.systemui.statusbar.notification.stack.AnimationProperties
+import com.android.systemui.statusbar.notification.stack.StackStateAnimator
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.Execution
import com.android.systemui.util.settings.SecureSettings
-import java.lang.RuntimeException
import java.util.Optional
import java.util.concurrent.Executor
import javax.inject.Inject
+private val ANIMATION_PROPERTIES = AnimationProperties()
+ .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD.toLong())
+
/**
* Controller for managing the smartspace view on the lockscreen
*/
@@ -72,10 +81,15 @@ class LockscreenSmartspaceController @Inject constructor(
@Main private val handler: Handler,
optionalPlugin: Optional<BcSmartspaceDataPlugin>
) {
+
+ var splitShadeContainer: ViewGroup? = null
+ private var singlePaneContainer: ViewGroup? = null
+
private var session: SmartspaceSession? = null
private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null)
private lateinit var smartspaceView: SmartspaceView
+ // smartspace casted to View
lateinit var view: View
private set
@@ -83,12 +97,60 @@ class LockscreenSmartspaceController @Inject constructor(
private var showSensitiveContentForManagedUser = false
private var managedUserHandle: UserHandle? = null
- fun isEnabled(): Boolean {
+ private var isAod = false
+ private var isSplitShade = false
+
+ fun isSmartspaceEnabled(): Boolean {
execution.assertIsMainThread()
return featureFlags.isSmartspaceEnabled && plugin != null
}
+ fun setKeyguardStatusContainer(container: ViewGroup) {
+ singlePaneContainer = container
+ // reattach smartspace if necessary as this might be a new container
+ updateSmartSpaceContainer()
+ }
+
+ fun onSplitShadeChanged(splitShade: Boolean) {
+ isSplitShade = splitShade
+ updateSmartSpaceContainer()
+ }
+
+ private fun updateSmartSpaceContainer() {
+ if (!isSmartspaceEnabled()) return
+ // in AOD we always want to show smartspace on the left i.e. in singlePaneContainer
+ if (isSplitShade && !isAod) {
+ switchContainerVisibility(
+ newParent = splitShadeContainer,
+ oldParent = singlePaneContainer)
+ } else {
+ switchContainerVisibility(
+ newParent = singlePaneContainer,
+ oldParent = splitShadeContainer)
+ }
+ requestSmartspaceUpdate()
+ }
+
+ private fun switchContainerVisibility(newParent: ViewGroup?, oldParent: ViewGroup?) {
+ // it might be the case that smartspace was already attached and we just needed to update
+ // visibility, e.g. going from lockscreen -> unlocked -> lockscreen
+ if (newParent?.childCount == 0) {
+ oldParent?.removeAllViews()
+ newParent.addView(buildAndConnectView(newParent))
+ }
+ oldParent?.visibility = GONE
+ newParent?.visibility = VISIBLE
+ }
+
+ fun setSplitShadeSmartspaceAlpha(alpha: Float) {
+ // the other container's alpha is modified as a part of keyguard status view, so we don't
+ // have to do that here
+ if (splitShadeContainer?.visibility == VISIBLE) {
+ splitShadeContainer?.alpha = alpha
+ }
+ }
+
/**
* Constructs the smartspace view and connects it to the smartspace service. Subsequent calls
* are idempotent until [disconnect] is called.
@@ -96,7 +158,7 @@ class LockscreenSmartspaceController @Inject constructor(
fun buildAndConnectView(parent: ViewGroup): View {
execution.assertIsMainThread()
- if (!isEnabled()) {
+ if (!isSmartspaceEnabled()) {
throw RuntimeException("Cannot build view when not enabled")
}
@@ -182,7 +244,6 @@ class LockscreenSmartspaceController @Inject constructor(
userTracker.removeCallback(userTrackerCallback)
contentResolver.unregisterContentObserver(settingsObserver)
configurationController.removeCallback(configChangeListener)
- statusBarStateController.removeCallback(statusBarStateListener)
session = null
plugin?.onTargetsAvailable(emptyList())
@@ -198,6 +259,13 @@ class LockscreenSmartspaceController @Inject constructor(
plugin?.unregisterListener(listener)
}
+ fun shiftSplitShadeSmartspace(y: Int, animate: Boolean) {
+ if (splitShadeContainer?.visibility == VISIBLE) {
+ PropertyAnimator.setProperty(splitShadeContainer, AnimatableProperty.Y, y.toFloat(),
+ ANIMATION_PROPERTIES, animate)
+ }
+ }
+
private val sessionListener = SmartspaceSession.OnTargetsAvailableListener { targets ->
execution.assertIsMainThread()
val filteredTargets = targets.filter(::filterSmartspaceTarget)
@@ -233,6 +301,23 @@ class LockscreenSmartspaceController @Inject constructor(
execution.assertIsMainThread()
smartspaceView.setDozeAmount(eased)
}
+
+ override fun onDozingChanged(isDozing: Boolean) {
+ isAod = isDozing
+ updateSmartSpaceContainer()
+ }
+
+ override fun onStateChanged(newState: Int) {
+ if (newState == StatusBarState.KEYGUARD) {
+ if (isSmartspaceEnabled()) {
+ updateSmartSpaceContainer()
+ }
+ } else {
+ splitShadeContainer?.visibility = GONE
+ singlePaneContainer?.visibility = GONE
+ disconnect()
+ }
+ }
}
private fun filterSmartspaceTarget(t: SmartspaceTarget): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java
index 2537b19513d2..129fa5a7cc17 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java
@@ -20,6 +20,7 @@ import android.content.Intent;
import android.service.notification.StatusBarNotification;
import android.view.View;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
/**
@@ -37,6 +38,9 @@ public interface NotificationActivityStarter {
/** Called when the user clicks "Manage" or "History" in the Shade. */
void startHistoryIntent(View view, boolean showHistory);
+ /** Called when the user succeed to drop notification to proper target view. */
+ void onDragSuccess(NotificationEntry entry);
+
default boolean isCollapsingToShowActivityOverLockscreen() {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
index 0fb1c54bb150..da706215863e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
@@ -43,6 +43,14 @@ public final class NotificationClicker implements View.OnClickListener {
private final Optional<Bubbles> mBubblesOptional;
private final NotificationActivityStarter mNotificationActivityStarter;
+ private ExpandableNotificationRow.OnDragSuccessListener mOnDragSuccessListener =
+ new ExpandableNotificationRow.OnDragSuccessListener() {
+ @Override
+ public void onDragSuccess(NotificationEntry entry) {
+ mNotificationActivityStarter.onDragSuccess(entry);
+ }
+ };
+
private NotificationClicker(
NotificationClickerLogger logger,
Optional<StatusBar> statusBarOptional,
@@ -111,8 +119,10 @@ public final class NotificationClicker implements View.OnClickListener {
if (notification.contentIntent != null || notification.fullScreenIntent != null
|| row.getEntry().isBubble()) {
row.setOnClickListener(this);
+ row.setOnDragSuccessListener(mOnDragSuccessListener);
} else {
row.setOnClickListener(null);
+ row.setOnDragSuccessListener(null);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 1ab2a9e320b0..a65f3d5a20a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -37,7 +37,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dumpable;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index 8ae31cba4cfb..277b4acb3237 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -63,7 +63,7 @@ import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.dump.LogBufferEulogizer;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.notification.collection.coalescer.CoalescedEvent;
import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer;
import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer.BatchableNotificationHandler;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
index d80cc082aada..25b201926239 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
@@ -19,7 +19,7 @@ package com.android.systemui.statusbar.notification.collection.coordinator;
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java
index aec26474cf7d..518c3f1d1948 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/LowPriorityInflationHelper.java
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.notification.collection.inflation;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
index db49e4476a99..168e08603f3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
@@ -21,7 +21,7 @@ import android.util.Log;
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index f75811478195..55620b634008 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -30,11 +30,11 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.UserContextProvider;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index 32d90d3333d0..c5899ad0d1a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -20,7 +20,7 @@ import android.service.notification.StatusBarNotification
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.people.widget.PeopleSpaceWidgetManager
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.statusbar.NotificationListener
import com.android.systemui.statusbar.NotificationPresenter
import com.android.systemui.statusbar.notification.AnimatedImageNotificationManager
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 4f3406c405ad..acb0e82c24f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -21,6 +21,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.Point;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.MathUtils;
@@ -139,6 +140,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
private boolean mIsHeadsUpAnimation;
private int mHeadsUpAddStartLocation;
private float mHeadsUpLocation;
+ /* In order to track headsup longpress coorindate. */
+ protected Point mTargetPoint;
private boolean mIsAppearing;
private boolean mDismissed;
private boolean mRefocusOnDismiss;
@@ -521,8 +524,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
@Override
public void onAnimationStart(Animator animation) {
mWasCancelled = false;
- Configuration.Builder builder = new Configuration.Builder(getCujType(isAppearing))
- .setView(ActivatableNotificationView.this);
+ Configuration.Builder builder = Configuration.Builder
+ .withView(getCujType(isAppearing), ActivatableNotificationView.this);
InteractionJankMonitor.getInstance().begin(builder);
}
@@ -568,8 +571,19 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
final int actualHeight = getActualHeight();
float bottom = actualHeight * interpolatedFraction;
- setOutlineRect(0, mAppearAnimationTranslation, getWidth(),
- bottom + mAppearAnimationTranslation);
+ if (mTargetPoint != null) {
+ int width = getWidth();
+ float fraction = 1 - mAppearAnimationFraction;
+
+ setOutlineRect(mTargetPoint.x * fraction,
+ mAnimationTranslationY
+ + (mAnimationTranslationY - mTargetPoint.y) * fraction,
+ width - (width - mTargetPoint.x) * fraction,
+ actualHeight - (actualHeight - mTargetPoint.y) * fraction);
+ } else {
+ setOutlineRect(0, mAppearAnimationTranslation, getWidth(),
+ bottom + mAppearAnimationTranslation);
+ }
}
private float getInterpolatedAppearAnimationFraction() {
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 73bb6cd9ba1c..0d8e85094646 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
@@ -37,6 +37,7 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Path;
+import android.graphics.Point;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.ColorDrawable;
@@ -260,6 +261,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
// Use #setLongPressPosition to optionally assign positional data with the long press.
private LongPressListener mLongPressListener;
+ private ExpandableNotificationRowDragController mDragController;
+
private boolean mGroupExpansionChanging;
/**
@@ -331,6 +334,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
};
private OnClickListener mOnClickListener;
+ private OnDragSuccessListener mOnDragSuccessListener;
private boolean mHeadsupDisappearRunning;
private View mChildAfterViewWhenDismissed;
private View mGroupParentWhenDismissed;
@@ -1083,6 +1087,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mLongPressListener = longPressListener;
}
+ public void setDragController(ExpandableNotificationRowDragController dragController) {
+ mDragController = dragController;
+ }
+
@Override
public void setOnClickListener(@Nullable OnClickListener l) {
super.setOnClickListener(l);
@@ -1329,6 +1337,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
public void dismiss(boolean refocusOnDismiss) {
super.dismiss(refocusOnDismiss);
setLongPressListener(null);
+ setDragController(null);
mGroupParentWhenDismissed = mNotificationParent;
mChildAfterViewWhenDismissed = null;
mEntry.getIcons().getStatusBarIcon().setDismissed();
@@ -1637,6 +1646,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
onHeightReset();
requestLayout();
+
+ setTargetPoint(null);
}
public void showFeedbackIcon(boolean show, Pair<Integer, Integer> resIds) {
@@ -1727,6 +1738,29 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mTranslateableViews.remove(mGutsStub);
}
+ /**
+ * Called once when starting drag motion after opening notification guts,
+ * in case of notification that has {@link android.app.Notification#contentIntent}
+ * and it is to start an activity.
+ */
+ public void doDragCallback(float x, float y) {
+ if (mDragController != null) {
+ setTargetPoint(new Point((int) x, (int) y));
+ mDragController.startDragAndDrop(this);
+ }
+ }
+
+ public void setOnDragSuccessListener(OnDragSuccessListener listener) {
+ mOnDragSuccessListener = listener;
+ }
+
+ /**
+ * Called when a notification is dropped on proper target window.
+ */
+ public void dragAndDropSuccess() {
+ mOnDragSuccessListener.onDragSuccess(getEntry());
+ }
+
private void doLongClickCallback() {
doLongClickCallback(getWidth() / 2, getHeight() / 2);
}
@@ -3255,6 +3289,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
/**
+ * Called when notification drag and drop is finished successfully.
+ */
+ public interface OnDragSuccessListener {
+ /**
+ * @param entry NotificationEntry that succeed to drop on proper target window.
+ */
+ void onDragSuccess(NotificationEntry entry);
+ }
+
+ /**
* Equivalent to View.OnClickListener with coordinates
*/
public interface CoordinateOnClickListener {
@@ -3321,4 +3365,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
}
+
+ private void setTargetPoint(Point p) {
+ mTargetPoint = p;
+ }
+ public Point getTargetPoint() {
+ return mTargetPoint;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index c9fcdac8e45f..0662a1eba8b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -25,6 +25,7 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
+import com.android.systemui.R;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -85,6 +86,8 @@ public class ExpandableNotificationRowController implements NodeController {
private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
private final Optional<BubblesManager> mBubblesManagerOptional;
+ private final ExpandableNotificationRowDragController mDragController;
+
@Inject
public ExpandableNotificationRowController(
ExpandableNotificationRow view,
@@ -109,7 +112,8 @@ public class ExpandableNotificationRowController implements NodeController {
FalsingManager falsingManager,
FalsingCollector falsingCollector,
PeopleNotificationIdentifier peopleNotificationIdentifier,
- Optional<BubblesManager> bubblesManagerOptional) {
+ Optional<BubblesManager> bubblesManagerOptional,
+ ExpandableNotificationRowDragController dragController) {
mView = view;
mListContainer = listContainer;
mActivatableNotificationViewController = activatableNotificationViewController;
@@ -134,6 +138,7 @@ public class ExpandableNotificationRowController implements NodeController {
mFalsingCollector = falsingCollector;
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
mBubblesManagerOptional = bubblesManagerOptional;
+ mDragController = dragController;
}
/**
@@ -164,6 +169,10 @@ public class ExpandableNotificationRowController implements NodeController {
);
mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (mAllowLongPress) {
+ if (mView.getResources().getBoolean(R.bool.config_notificationToContents)) {
+ mView.setDragController(mDragController);
+ }
+
mView.setLongPressListener((v, x, y, item) -> {
if (mView.isSummaryWithChildren()) {
mView.expandNotification();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
new file mode 100644
index 000000000000..06b739b33e77
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.systemui.statusbar.notification.row;
+
+import android.annotation.NonNull;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+import android.view.DragEvent;
+import android.view.HapticFeedbackConstants;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+
+import javax.inject.Inject;
+
+/**
+ * Controller for Notification to window.
+ */
+public class ExpandableNotificationRowDragController {
+ private static final String TAG = ExpandableNotificationRowDragController.class.getSimpleName();
+ private int mIconSize;
+
+ private final Context mContext;
+ private final HeadsUpManager mHeadsUpManager;
+
+ @Inject
+ public ExpandableNotificationRowDragController(Context context,
+ HeadsUpManager headsUpManager) {
+ mContext = context;
+ mHeadsUpManager = headsUpManager;
+
+ init();
+ }
+
+ private void init() {
+ mIconSize = mContext.getResources().getDimensionPixelSize(R.dimen.drag_and_drop_icon_size);
+ }
+
+ /**
+ * Called when drag event beyond the touchslop,
+ * and start drag and drop.
+ *
+ * @param view notification that was long pressed and started to drag and drop.
+ */
+ @VisibleForTesting
+ public void startDragAndDrop(View view) {
+ ExpandableNotificationRow enr = null;
+ if (view instanceof ExpandableNotificationRow) {
+ enr = (ExpandableNotificationRow) view;
+ }
+
+ StatusBarNotification sn = enr.getEntry().getSbn();
+ Notification notification = sn.getNotification();
+ final PendingIntent contentIntent = notification.contentIntent != null
+ ? notification.contentIntent
+ : notification.fullScreenIntent;
+ Bitmap iconBitmap = getBitmapFromDrawable(
+ getPkgIcon(enr.getEntry().getSbn().getPackageName()));
+
+ final ImageView snapshot = new ImageView(mContext);
+ snapshot.setImageBitmap(iconBitmap);
+ snapshot.layout(0, 0, mIconSize, mIconSize);
+
+ ClipDescription clipDescription = new ClipDescription("Drag And Drop",
+ new String[]{ClipDescription.MIMETYPE_APPLICATION_ACTIVITY});
+ Intent dragIntent = new Intent();
+ dragIntent.putExtra("android.intent.extra.PENDING_INTENT", contentIntent);
+ dragIntent.putExtra(Intent.EXTRA_USER, android.os.Process.myUserHandle());
+ ClipData.Item item = new ClipData.Item(dragIntent);
+ ClipData dragData = new ClipData(clipDescription, item);
+ View.DragShadowBuilder myShadow = new View.DragShadowBuilder(snapshot);
+ view.setOnDragListener(getDraggedViewDragListener());
+ view.startDragAndDrop(dragData, myShadow, null, View.DRAG_FLAG_GLOBAL);
+ }
+
+
+ private Drawable getPkgIcon(String pkgName) {
+ Drawable pkgicon = null;
+ PackageManager pm = mContext.getPackageManager();
+ ApplicationInfo info;
+ try {
+ info = pm.getApplicationInfo(
+ pkgName,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE);
+ if (info != null) {
+ pkgicon = pm.getApplicationIcon(info);
+ } else {
+ Log.d(TAG, " application info is null ");
+ pkgicon = pm.getDefaultActivityIcon();
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.d(TAG, "can not find package with : " + pkgName);
+ pkgicon = pm.getDefaultActivityIcon();
+ }
+
+ return pkgicon;
+ }
+
+ private Bitmap getBitmapFromDrawable(@NonNull Drawable drawable) {
+ final Bitmap bmp = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
+ drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(bmp);
+ drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ drawable.draw(canvas);
+ return bmp;
+ }
+
+ private View.OnDragListener getDraggedViewDragListener() {
+ return (view, dragEvent) -> {
+ switch (dragEvent.getAction()) {
+ case DragEvent.ACTION_DRAG_STARTED:
+ view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow enr = (ExpandableNotificationRow) view;
+ if (enr.isPinned()) {
+ mHeadsUpManager.releaseAllImmediately();
+ } else {
+ Dependency.get(ShadeController.class).animateCollapsePanels(
+ CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
+ }
+ }
+ return true;
+ case DragEvent.ACTION_DRAG_ENDED:
+ if (dragEvent.getResult()) {
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow enr = (ExpandableNotificationRow) view;
+ enr.dragAndDropSuccess();
+ }
+ }
+ return true;
+ }
+ return false;
+ };
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 2033adf353d6..880e55847a46 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -81,7 +81,6 @@ import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.EmptyShadeView;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.StatusBarState;
@@ -408,6 +407,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private boolean mBackwardScrollable;
private NotificationShelf mShelf;
private int mMaxDisplayedNotifications = -1;
+ private float mKeyguardBottomPadding = -1;
private int mStatusBarHeight;
private int mMinInteractionHeight;
private final Rect mClipRect = new Rect();
@@ -743,6 +743,16 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mDebugPaint.setColor(Color.YELLOW);
canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
+ y = (int) mMaxLayoutHeight;
+ mDebugPaint.setColor(Color.MAGENTA);
+ canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
+
+ if (mKeyguardBottomPadding >= 0) {
+ y = getHeight() - (int) mKeyguardBottomPadding;
+ mDebugPaint.setColor(Color.GRAY);
+ canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
+ }
+
y = getHeight() - getEmptyBottomMargin();
mDebugPaint.setColor(Color.GREEN);
canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
@@ -4785,6 +4795,16 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
}
+ /**
+ * This is used for debugging only; it will be used to draw the otherwise invisible line which
+ * NotificationPanelViewController treats as the bottom when calculating how many notifications
+ * appear on the keyguard.
+ * Setting a negative number will disable rendering this line.
+ */
+ public void setKeyguardBottomPadding(float keyguardBottomPadding) {
+ mKeyguardBottomPadding = keyguardBottomPadding;
+ }
+
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setShouldShowShelfOnly(boolean shouldShowShelfOnly) {
mShouldShowShelfOnly = shouldShowShelfOnly;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index a160e1099dfd..04129b52b4ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -68,13 +68,13 @@ import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
@@ -183,6 +183,8 @@ public class NotificationStackScrollLayoutController {
private int mBarState;
private HeadsUpAppearanceController mHeadsUpAppearanceController;
+ private View mLongPressedView;
+
private final NotificationListContainerImpl mNotificationListContainer =
new NotificationListContainerImpl();
@@ -492,6 +494,11 @@ public class NotificationStackScrollLayoutController {
}
@Override
+ public void onLongPressSent(View v) {
+ mLongPressedView = v;
+ }
+
+ @Override
public void onBeginDrag(View v) {
mFalsingCollector.onNotificationStartDismissing();
mView.onSwipeBegin(v);
@@ -1218,6 +1225,16 @@ public class NotificationStackScrollLayoutController {
mNotificationListContainer.setMaxDisplayedNotifications(maxNotifications);
}
+ /**
+ * This is used for debugging only; it will be used to draw the otherwise invisible line which
+ * NotificationPanelViewController treats as the bottom when calculating how many notifications
+ * appear on the keyguard.
+ * Setting a negative number will disable rendering this line.
+ */
+ public void setKeyguardBottomPadding(float keyguardBottomPadding) {
+ mView.setKeyguardBottomPadding(keyguardBottomPadding);
+ }
+
public RemoteInputController.Delegate createDelegate() {
return new RemoteInputController.Delegate() {
public void setRemoteInputActive(NotificationEntry entry,
@@ -1425,6 +1442,10 @@ public class NotificationStackScrollLayoutController {
return mDynamicPrivacyController.isInLockedDownShade();
}
+ public boolean isLongPressInProgress() {
+ return mLongPressedView != null;
+ }
+
/**
* Set the dimmed state for all of the notification views.
*/
@@ -1462,6 +1483,11 @@ public class NotificationStackScrollLayoutController {
mView.setExtraTopInsetForFullShadeTransition(extraTopInset);
}
+ /** */
+ public void setWillExpand(boolean willExpand) {
+ mView.setWillExpand(willExpand);
+ }
+
/**
* Set a listener to when scrolling changes.
*/
@@ -1674,17 +1700,23 @@ public class NotificationStackScrollLayoutController {
mView.handleEmptySpaceClick(ev);
NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
+
+ boolean longPressWantsIt = false;
+ if (mLongPressedView != null) {
+ longPressWantsIt = mSwipeHelper.onInterceptTouchEvent(ev);
+ }
boolean expandWantsIt = false;
- if (!mSwipeHelper.isSwiping()
+ if (mLongPressedView == null && !mSwipeHelper.isSwiping()
&& !mView.getOnlyScrollingInThisMotion() && guts == null) {
expandWantsIt = mView.getExpandHelper().onInterceptTouchEvent(ev);
}
boolean scrollWantsIt = false;
- if (!mSwipeHelper.isSwiping() && !mView.isExpandingNotification()) {
+ if (mLongPressedView == null && !mSwipeHelper.isSwiping()
+ && !mView.isExpandingNotification()) {
scrollWantsIt = mView.onInterceptTouchEventScroll(ev);
}
boolean swipeWantsIt = false;
- if (!mView.isBeingDragged()
+ if (mLongPressedView == null && !mView.isBeingDragged()
&& !mView.isExpandingNotification()
&& !mView.getExpandedInThisMotion()
&& !mView.getOnlyScrollingInThisMotion()
@@ -1712,7 +1744,7 @@ public class NotificationStackScrollLayoutController {
InteractionJankMonitor.getInstance().begin(mView,
CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
}
- return swipeWantsIt || scrollWantsIt || expandWantsIt;
+ return swipeWantsIt || scrollWantsIt || expandWantsIt || longPressWantsIt;
}
@Override
@@ -1721,11 +1753,15 @@ public class NotificationStackScrollLayoutController {
boolean isCancelOrUp = ev.getActionMasked() == MotionEvent.ACTION_CANCEL
|| ev.getActionMasked() == MotionEvent.ACTION_UP;
mView.handleEmptySpaceClick(ev);
+ boolean longPressWantsIt = false;
+ if (guts != null && mLongPressedView != null) {
+ longPressWantsIt = mSwipeHelper.onTouchEvent(ev);
+ }
boolean expandWantsIt = false;
boolean onlyScrollingInThisMotion = mView.getOnlyScrollingInThisMotion();
boolean expandingNotification = mView.isExpandingNotification();
- if (mView.getIsExpanded() && !mSwipeHelper.isSwiping() && !onlyScrollingInThisMotion
- && guts == null) {
+ if (mLongPressedView == null && mView.getIsExpanded()
+ && !mSwipeHelper.isSwiping() && !onlyScrollingInThisMotion && guts == null) {
ExpandHelper expandHelper = mView.getExpandHelper();
if (isCancelOrUp) {
expandHelper.onlyObserveMovements(false);
@@ -1739,12 +1775,12 @@ public class NotificationStackScrollLayoutController {
}
}
boolean scrollerWantsIt = false;
- if (mView.isExpanded() && !mSwipeHelper.isSwiping() && !expandingNotification
- && !mView.getDisallowScrollingInThisMotion()) {
+ if (mLongPressedView == null && mView.isExpanded() && !mSwipeHelper.isSwiping()
+ && !expandingNotification && !mView.getDisallowScrollingInThisMotion()) {
scrollerWantsIt = mView.onScrollTouch(ev);
}
boolean horizontalSwipeWantsIt = false;
- if (!mView.isBeingDragged()
+ if (mLongPressedView == null && !mView.isBeingDragged()
&& !expandingNotification
&& !mView.getExpandedInThisMotion()
&& !onlyScrollingInThisMotion
@@ -1770,7 +1806,7 @@ public class NotificationStackScrollLayoutController {
mView.setCheckForLeaveBehind(true);
}
traceJankOnTouchEvent(ev.getActionMasked(), scrollerWantsIt);
- return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt;
+ return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt || longPressWantsIt;
}
private void traceJankOnTouchEvent(int action, boolean scrollerWantsIt) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 1b4ae9ea3f32..2c810c93b2ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -157,15 +157,13 @@ public class StackScrollAlgorithm {
// After the shelf has updated its yTranslation, explicitly set alpha=0 for view below shelf
// to skip rendering them in the hardware layer. We do not set them invisible because that
// runs invalidate & onDraw when these views return onscreen, which is more expensive.
+ if (shelf.getViewState().hidden) {
+ // When the shelf is hidden, it won't clip views, so we don't hide rows
+ return;
+ }
final float shelfTop = shelf.getViewState().yTranslation;
for (ExpandableView view : algorithmState.visibleChildren) {
- if (view instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- if (row.isHeadsUp() || row.isHeadsUpAnimatingAway()) {
- continue;
- }
- }
final float viewTop = view.getViewState().yTranslation;
if (viewTop >= shelfTop) {
view.getViewState().alpha = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index ee12b4b2d728..2702bf7d31da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -433,6 +433,7 @@ public class StackStateAnimator {
if (row.isDismissed()) {
needsAnimation = false;
}
+
NotificationEntry entry = row.getEntry();
StatusBarIconView icon = entry.getIcons().getStatusBarIcon();
final StatusBarIconView centeredIcon = entry.getIcons().getCenteredIcon();
@@ -442,7 +443,8 @@ public class StackStateAnimator {
if (icon.getParent() != null) {
icon.getLocationOnScreen(mTmpLocation);
float iconPosition = mTmpLocation[0] - icon.getTranslationX()
- + ViewState.getFinalTranslationX(icon) + icon.getWidth() * 0.25f;
+ + ViewState.getFinalTranslationX(icon)
+ + icon.getWidth() * 0.25f;
mHostLayout.getLocationOnScreen(mTmpLocation);
targetLocation = iconPosition - mTmpLocation[0];
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 00341b500b58..7610e6138ebb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -39,9 +39,9 @@ import android.widget.LinearLayout;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index b4f8126042ce..908cd34d7cad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -29,9 +29,9 @@ import android.widget.LinearLayout;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.R;
import com.android.systemui.demomode.DemoMode;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarMobileView;
import com.android.systemui.statusbar.StatusBarWifiView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 68024726c5de..7908d84bcd70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -33,7 +33,7 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.doze.DozeScreenState;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.tuner.TunerService;
@@ -231,7 +231,9 @@ public class DozeParameters implements TunerService.Tunable,
* possible if AOD isn't even enabled or if the flag is disabled.
*/
public boolean canControlUnlockedScreenOff() {
- return getAlwaysOn() && mFeatureFlags.useNewLockscreenAnimations();
+ return getAlwaysOn()
+ && mFeatureFlags.useNewLockscreenAnimations()
+ && !getDisplayNeedsBlanking();
}
private boolean getBoolean(String propName, int resId) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index f4830fbb0028..878fbbf39627 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -18,9 +18,7 @@ package com.android.systemui.statusbar.phone;
import android.graphics.Point;
import android.graphics.Rect;
-import android.view.DisplayCutout;
import android.view.View;
-import android.view.WindowInsets;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.ViewClippingUtil;
@@ -61,7 +59,6 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
private final NotificationPanelViewController mNotificationPanelViewController;
private final Consumer<ExpandableNotificationRow>
mSetTrackingHeadsUp = this::setTrackingHeadsUp;
- private final Runnable mUpdatePanelTranslation = this::updatePanelTranslation;
private final BiConsumer<Float, Float> mSetExpandedHeight = this::setAppearFraction;
private final KeyguardBypassController mBypassController;
private final StatusBarStateController mStatusBarStateController;
@@ -75,9 +72,6 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
float mAppearFraction;
private ExpandableNotificationRow mTrackedChild;
private boolean mShown;
- private final View.OnLayoutChangeListener mStackScrollLayoutChangeListener =
- (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
- -> updatePanelTranslation();
private final ViewClippingUtil.ClippingParameters mParentClippingParams =
new ViewClippingUtil.ClippingParameters() {
@Override
@@ -134,10 +128,8 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
mStackScrollerController = stackScrollerController;
mNotificationPanelViewController = notificationPanelViewController;
notificationPanelViewController.addTrackingHeadsUpListener(mSetTrackingHeadsUp);
- notificationPanelViewController.setVerticalTranslationListener(mUpdatePanelTranslation);
notificationPanelViewController.setHeadsUpAppearanceController(this);
mStackScrollerController.addOnExpandedHeightChangedListener(mSetExpandedHeight);
- mStackScrollerController.addOnLayoutChangeListener(mStackScrollLayoutChangeListener);
mStackScrollerController.setHeadsUpAppearanceController(this);
mClockView = clockView;
mOperatorNameView = operatorNameView;
@@ -174,7 +166,6 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
mNotificationPanelViewController.setVerticalTranslationListener(null);
mNotificationPanelViewController.setHeadsUpAppearanceController(null);
mStackScrollerController.removeOnExpandedHeightChangedListener(mSetExpandedHeight);
- mStackScrollerController.removeOnLayoutChangeListener(mStackScrollLayoutChangeListener);
mDarkIconDispatcher.removeDarkReceiver(this);
}
@@ -189,63 +180,6 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener,
updateHeader(entry);
}
- /** To count the distance from the window right boundary to scroller right boundary. The
- * distance formula is the following:
- * Y = screenSize - (SystemWindow's width + Scroller.getRight())
- * There are four modes MUST to be considered in Cut Out of RTL.
- * No Cut Out:
- * Scroller + NB
- * NB + Scroller
- * => SystemWindow = NavigationBar's width
- * => Y = screenSize - (SystemWindow's width + Scroller.getRight())
- * Corner Cut Out or Tall Cut Out:
- * cut out + Scroller + NB
- * NB + Scroller + cut out
- * => SystemWindow = NavigationBar's width
- * => Y = screenSize - (SystemWindow's width + Scroller.getRight())
- * Double Cut Out:
- * cut out left + Scroller + (NB + cut out right)
- * SystemWindow = NavigationBar's width + cut out right width
- * => Y = screenSize - (SystemWindow's width + Scroller.getRight())
- * (cut out left + NB) + Scroller + cut out right
- * SystemWindow = NavigationBar's width + cut out left width
- * => Y = screenSize - (SystemWindow's width + Scroller.getRight())
- * @return the translation X value for RTL. In theory, it should be negative. i.e. -Y
- */
- private int getRtlTranslation() {
- if (mPoint == null) {
- mPoint = new Point();
- }
-
- int realDisplaySize = 0;
- if (mStackScrollerController.getDisplay() != null) {
- mStackScrollerController.getDisplay().getRealSize(mPoint);
- realDisplaySize = mPoint.x;
- }
-
- WindowInsets windowInset = mStackScrollerController.getRootWindowInsets();
- DisplayCutout cutout = (windowInset != null) ? windowInset.getDisplayCutout() : null;
- int sysWinLeft = (windowInset != null) ? windowInset.getStableInsetLeft() : 0;
- int sysWinRight = (windowInset != null) ? windowInset.getStableInsetRight() : 0;
- int cutoutLeft = (cutout != null) ? cutout.getSafeInsetLeft() : 0;
- int cutoutRight = (cutout != null) ? cutout.getSafeInsetRight() : 0;
- int leftInset = Math.max(sysWinLeft, cutoutLeft);
- int rightInset = Math.max(sysWinRight, cutoutRight);
-
- return leftInset + mStackScrollerController.getRight() + rightInset - realDisplaySize;
- }
-
- public void updatePanelTranslation() {
- float newTranslation;
- if (mStackScrollerController.isLayoutRtl()) {
- newTranslation = getRtlTranslation();
- } else {
- newTranslation = mStackScrollerController.getLeft();
- }
- newTranslation += mStackScrollerController.getTranslationX();
- mHeadsUpStatusBarView.setPanelTranslation(newTranslation);
- }
-
private void updateTopEntry() {
NotificationEntry newEntry = null;
if (shouldBeVisible()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index f77c0520cdb1..19c258558a7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -33,23 +33,11 @@ import com.android.systemui.statusbar.policy.KeyguardUserSwitcherListView;
*/
public class KeyguardClockPositionAlgorithm {
/**
- * How much the clock height influences the shade position.
- * 0 means nothing, 1 means move the shade up by the height of the clock
- * 0.5f means move the shade up by half of the size of the clock.
- */
- private static float CLOCK_HEIGHT_WEIGHT = 0.7f;
-
- /**
* Margin between the bottom of the status view and the notification shade.
*/
private int mStatusViewBottomMargin;
/**
- * Height of the parent view - display size in px.
- */
- private int mHeight;
-
- /**
* Height of {@link KeyguardStatusView}.
*/
private int mKeyguardStatusHeight;
@@ -68,21 +56,6 @@ public class KeyguardClockPositionAlgorithm {
private int mUserSwitchPreferredY;
/**
- * Whether or not there is a custom clock face on keyguard.
- */
- private boolean mHasCustomClock;
-
- /**
- * Whether or not the NSSL contains any visible notifications.
- */
- private boolean mHasVisibleNotifs;
-
- /**
- * Height of notification stack: Sum of height of each notification.
- */
- private int mNotificationStackHeight;
-
- /**
* Minimum top margin to avoid overlap with status bar, lock icon, or multi-user switcher
* avatar.
*/
@@ -148,6 +121,7 @@ public class KeyguardClockPositionAlgorithm {
private int mUnlockedStackScrollerPadding;
private boolean mIsSplitShade;
+ private int mSplitShadeSmartspaceHeight;
/**
* Refreshes the dimension values.
@@ -170,28 +144,25 @@ public class KeyguardClockPositionAlgorithm {
* Sets up algorithm values.
*/
public void setup(int keyguardStatusBarHeaderHeight, int maxShadeBottom,
- int notificationStackHeight, float panelExpansion, int parentHeight,
- int keyguardStatusHeight, int userSwitchHeight, int userSwitchPreferredY,
- boolean hasCustomClock, boolean hasVisibleNotifs, float dark,
+ float panelExpansion,
+ int keyguardStatusHeight, int userSwitchHeight, int userSwitchPreferredY, float dark,
float overStrechAmount, boolean bypassEnabled, int unlockedStackScrollerPadding,
- float qsExpansion, int cutoutTopInset, boolean isSplitShade) {
+ float qsExpansion, int cutoutTopInset, int splitShadeSmartspaceHeight,
+ boolean isSplitShade) {
mMinTopMargin = keyguardStatusBarHeaderHeight + Math.max(mContainerTopPadding,
userSwitchHeight);
mMaxShadeBottom = maxShadeBottom;
- mNotificationStackHeight = notificationStackHeight;
mPanelExpansion = panelExpansion;
- mHeight = parentHeight;
mKeyguardStatusHeight = keyguardStatusHeight + mStatusViewBottomMargin;
mUserSwitchHeight = userSwitchHeight;
mUserSwitchPreferredY = userSwitchPreferredY;
- mHasCustomClock = hasCustomClock;
- mHasVisibleNotifs = hasVisibleNotifs;
mDarkAmount = dark;
mOverStretchAmount = overStrechAmount;
mBypassEnabled = bypassEnabled;
mUnlockedStackScrollerPadding = unlockedStackScrollerPadding;
mQsExpansion = qsExpansion;
mCutoutTopInset = cutoutTopInset;
+ mSplitShadeSmartspaceHeight = splitShadeSmartspaceHeight;
mIsSplitShade = isSplitShade;
}
@@ -213,7 +184,7 @@ public class KeyguardClockPositionAlgorithm {
if (mBypassEnabled) {
return (int) (mUnlockedStackScrollerPadding + mOverStretchAmount);
} else if (mIsSplitShade) {
- return clockYPosition;
+ return clockYPosition + mSplitShadeSmartspaceHeight;
} else {
return clockYPosition + mKeyguardStatusHeight;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 222ed631fd65..a73cad7d2c6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -42,9 +42,9 @@ import android.widget.RelativeLayout;
import android.widget.TextView;
import com.android.settingslib.Utils;
-import com.android.systemui.BatteryMeterView;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
+import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import java.io.FileDescriptor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 5d8d36e5caf6..8770e86df735 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -26,6 +26,7 @@ import androidx.annotation.NonNull;
import com.android.keyguard.CarrierTextController;
import com.android.systemui.R;
+import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -50,6 +51,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
private final UserInfoController mUserInfoController;
private final StatusBarIconController mStatusBarIconController;
private final StatusBarIconController.TintedIconManager.Factory mTintedIconManagerFactory;
+ private final BatteryMeterViewController mBatteryMeterViewController;
private final ConfigurationController.ConfigurationListener mConfigurationListener =
new ConfigurationController.ConfigurationListener() {
@@ -115,7 +117,8 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
BatteryController batteryController,
UserInfoController userInfoController,
StatusBarIconController statusBarIconController,
- StatusBarIconController.TintedIconManager.Factory tintedIconManagerFactory) {
+ StatusBarIconController.TintedIconManager.Factory tintedIconManagerFactory,
+ BatteryMeterViewController batteryMeterViewController) {
super(view);
mCarrierTextController = carrierTextController;
mConfigurationController = configurationController;
@@ -124,6 +127,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
mUserInfoController = userInfoController;
mStatusBarIconController = statusBarIconController;
mTintedIconManagerFactory = tintedIconManagerFactory;
+ mBatteryMeterViewController = batteryMeterViewController;
Resources r = getResources();
mBlockedIcons = Collections.unmodifiableList(Arrays.asList(
@@ -136,6 +140,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
protected void onInit() {
super.onInit();
mCarrierTextController.init();
+ mBatteryMeterViewController.init();
}
@Override
@@ -154,10 +159,16 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
@Override
protected void onViewDetached() {
+ destroy();
+ }
+
+ @Override
+ public void destroy() {
// Don't receive future #onViewAttached calls so that we don't accidentally have two
// controllers registered for the same view.
// TODO(b/194181195): This shouldn't be necessary.
- destroy();
+ super.destroy();
+ mBatteryMeterViewController.destroy();
mConfigurationController.removeCallback(mConfigurationListener);
mAnimationScheduler.removeCallback(mAnimationCallback);
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 3b65ce06da99..30cb1dc9bd16 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -138,6 +138,7 @@ import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.events.PrivacyDotViewController;
+import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.ConversationNotificationManager;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
@@ -229,6 +230,7 @@ public class NotificationPanelViewController extends PanelViewController {
private final HeightListener mHeightListener = new HeightListener();
private final ConfigurationListener mConfigurationListener = new ConfigurationListener();
private final SettingsChangeObserver mSettingsChangeObserver;
+ private final LockscreenSmartspaceController mLockscreenSmartspaceController;
@VisibleForTesting final StatusBarStateListener mStatusBarStateListener =
new StatusBarStateListener();
@@ -338,6 +340,8 @@ public class NotificationPanelViewController extends PanelViewController {
private final SplitShadeHeaderController mSplitShadeHeaderController;
private final RecordingController mRecordingController;
private boolean mShouldUseSplitNotificationShade;
+ // The bottom padding reserved for elements of the keyguard measuring notifications
+ private float mKeyguardNotificationBottomPadding;
// Current max allowed keyguard notifications determined by measuring the panel
private int mMaxAllowedKeyguardNotifications;
@@ -353,6 +357,8 @@ public class NotificationPanelViewController extends PanelViewController {
private KeyguardStatusViewController mKeyguardStatusViewController;
private LockIconViewController mLockIconViewController;
private NotificationsQuickSettingsContainer mNotificationContainerParent;
+ private FrameLayout mSplitShadeSmartspaceContainer;
+
private boolean mAnimateNextPositionUpdate;
private float mQuickQsOffsetHeight;
private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@@ -734,6 +740,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Main Executor uiExecutor,
SecureSettings secureSettings,
SplitShadeHeaderController splitShadeHeaderController,
+ LockscreenSmartspaceController lockscreenSmartspaceController,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
NotificationRemoteInputManager remoteInputManager,
ControlsComponent controlsComponent) {
@@ -765,6 +772,7 @@ public class NotificationPanelViewController extends PanelViewController {
mQSDetailDisplayer = qsDetailDisplayer;
mFragmentService = fragmentService;
mSettingsChangeObserver = new SettingsChangeObserver(handler);
+ mLockscreenSmartspaceController = lockscreenSmartspaceController;
mShouldUseSplitNotificationShade =
Utils.shouldUseSplitNotificationShade(mResources);
mView.setWillNotDraw(!DEBUG);
@@ -859,6 +867,9 @@ public class NotificationPanelViewController extends PanelViewController {
loadDimens();
mKeyguardStatusBar = mView.findViewById(R.id.keyguard_header);
mBigClockContainer = mView.findViewById(R.id.big_clock_container);
+ mSplitShadeSmartspaceContainer = mView.findViewById(R.id.split_shade_smartspace_container);
+ mLockscreenSmartspaceController.setSplitShadeContainer(mSplitShadeSmartspaceContainer);
+ mLockscreenSmartspaceController.onSplitShadeChanged(mShouldUseSplitNotificationShade);
UserAvatarView userAvatarView = null;
KeyguardUserSwitcherView keyguardUserSwitcherView = null;
@@ -980,7 +991,7 @@ public class NotificationPanelViewController extends PanelViewController {
mKeyguardStatusBarViewComponentFactory.build(keyguardStatusBarView);
if (mKeyguardStatusBarViewController != null) {
// TODO(b/194181195): This shouldn't be necessary.
- mKeyguardStatusBarViewController.onViewDetached();
+ mKeyguardStatusBarViewController.destroy();
}
mKeyguardStatusBarViewController =
statusBarViewComponent.getKeyguardStatusBarViewController();
@@ -1071,7 +1082,7 @@ public class NotificationPanelViewController extends PanelViewController {
mNotificationContainerParent.setSplitShadeEnabled(mShouldUseSplitNotificationShade);
updateKeyguardStatusViewAlignment(false /* animate */);
-
+ mLockscreenSmartspaceController.onSplitShadeChanged(mShouldUseSplitNotificationShade);
mKeyguardMediaController.refreshMediaPosition();
}
@@ -1206,9 +1217,12 @@ public class NotificationPanelViewController extends PanelViewController {
if (mKeyguardShowing && !mKeyguardBypassController.getBypassEnabled()) {
mNotificationStackScrollLayoutController.setMaxDisplayedNotifications(
mMaxAllowedKeyguardNotifications);
+ mNotificationStackScrollLayoutController.setKeyguardBottomPadding(
+ mKeyguardNotificationBottomPadding);
} else {
// no max when not on the keyguard
mNotificationStackScrollLayoutController.setMaxDisplayedNotifications(-1);
+ mNotificationStackScrollLayoutController.setKeyguardBottomPadding(-1f);
}
}
@@ -1331,16 +1345,15 @@ public class NotificationPanelViewController extends PanelViewController {
? 1.0f : mInterpolatedDarkAmount;
mClockPositionAlgorithm.setup(mStatusBarHeaderHeightKeyguard,
totalHeight - bottomPadding,
- mNotificationStackScrollLayoutController.getIntrinsicContentHeight(),
expandedFraction,
- totalHeight,
mKeyguardStatusViewController.getLockscreenHeight(),
userIconHeight,
- userSwitcherPreferredY, hasCustomClock(),
- hasVisibleNotifications, darkamount, mOverStretchAmount,
+ userSwitcherPreferredY,
+ darkamount, mOverStretchAmount,
bypassEnabled, getUnlockedStackScrollerPadding(),
computeQsExpansionFraction(),
mDisplayTopInset,
+ mSplitShadeSmartspaceContainer.getHeight(),
mShouldUseSplitNotificationShade);
mClockPositionAlgorithm.run(mClockPositionResult);
boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
@@ -1360,6 +1373,9 @@ public class NotificationPanelViewController extends PanelViewController {
mClockPositionResult.userSwitchY,
animateClock);
}
+ // no need to translate in X axis - horizontal position is determined by constraints
+ mLockscreenSmartspaceController
+ .shiftSplitShadeSmartspace(mClockPositionResult.clockY, animateClock);
updateNotificationTranslucency();
updateClock();
}
@@ -1411,6 +1427,7 @@ public class NotificationPanelViewController extends PanelViewController {
float bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);
bottomPadding = Math.max(lockIconPadding, bottomPadding);
+ mKeyguardNotificationBottomPadding = bottomPadding;
float availableSpace =
mNotificationStackScrollLayoutController.getHeight()
@@ -1526,6 +1543,7 @@ public class NotificationPanelViewController extends PanelViewController {
if (mKeyguardUserSwitcherController != null) {
mKeyguardUserSwitcherController.setAlpha(alpha);
}
+ mLockscreenSmartspaceController.setSplitShadeSmartspaceAlpha(alpha);
}
public void animateToFullShade(long delay) {
@@ -3707,6 +3725,7 @@ public class NotificationPanelViewController extends PanelViewController {
public void dozeTimeTick() {
mKeyguardBottomArea.dozeTimeTick();
mKeyguardStatusViewController.dozeTimeTick();
+ mLockscreenSmartspaceController.requestSmartspaceUpdate();
if (mInterpolatedDarkAmount > 0) {
positionClockAndNotifications();
}
@@ -3928,7 +3947,9 @@ public class NotificationPanelViewController extends PanelViewController {
if (mStatusBar.isBouncerShowing()) {
return true;
}
- if (mBar.panelEnabled() && mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
+ if (mBar.panelEnabled()
+ && !mNotificationStackScrollLayoutController.isLongPressInProgress()
+ && mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
mMetricsLogger.count(COUNTER_PANEL_OPEN, 1);
mMetricsLogger.count(COUNTER_PANEL_OPEN_PEEK, 1);
return true;
@@ -3980,6 +4001,7 @@ public class NotificationPanelViewController extends PanelViewController {
return true;
}
if (mListenForHeadsUp && !mHeadsUpTouchHelper.isTrackingHeadsUp()
+ && !mNotificationStackScrollLayoutController.isLongPressInProgress()
&& mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
mMetricsLogger.count(COUNTER_PANEL_OPEN_PEEK, 1);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index 1a404dc8d758..d2a4a00c03bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -296,8 +296,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
if (mKeyguardPreferredRefreshRate > 0) {
boolean onKeyguard = state.mStatusBarState == StatusBarState.KEYGUARD
- && !state.mKeyguardFadingAway && !state.mKeyguardGoingAway
- && !state.mDozing;
+ && !state.mKeyguardFadingAway && !state.mKeyguardGoingAway;
if (onKeyguard
&& mAuthController.isUdfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser())) {
mLpChanged.preferredMaxDisplayRefreshRate = mKeyguardPreferredRefreshRate;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 323a1128d3bb..27f08a860f28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -1397,8 +1397,7 @@ public abstract class PanelViewController {
private void beginJankMonitoring(int cuj) {
InteractionJankMonitor.Configuration.Builder builder =
- new InteractionJankMonitor.Configuration.Builder(cuj)
- .setView(mView)
+ InteractionJankMonitor.Configuration.Builder.withView(cuj, mView)
.setTag(isFullyCollapsed() ? "Expand" : "Collapse");
InteractionJankMonitor.getInstance().begin(builder);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index c300b11b9a34..70a46b25c1eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -27,6 +27,7 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.EventLog;
+import android.util.Log;
import android.util.Pair;
import android.view.DisplayCutout;
import android.view.Gravity;
@@ -42,7 +43,6 @@ import com.android.systemui.EventLogTags;
import com.android.systemui.R;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.util.leak.RotationUtils;
import java.util.List;
@@ -52,7 +52,6 @@ public class PhoneStatusBarView extends PanelBar {
private static final String TAG = "PhoneStatusBarView";
private static final boolean DEBUG = StatusBar.DEBUG;
private static final boolean DEBUG_GESTURES = false;
- private final CommandQueue mCommandQueue;
private final StatusBarContentInsetsProvider mContentInsetsProvider;
StatusBar mBar;
@@ -81,6 +80,8 @@ public class PhoneStatusBarView extends PanelBar {
@Nullable
private List<StatusBar.ExpansionChangedListener> mExpansionChangedListeners;
+ private PanelEnabledProvider mPanelEnabledProvider;
+
/**
* Draw this many pixels into the left/right side of the cutout to optimally use the space
*/
@@ -89,7 +90,6 @@ public class PhoneStatusBarView extends PanelBar {
public PhoneStatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
- mCommandQueue = Dependency.get(CommandQueue.class);
mContentInsetsProvider = Dependency.get(StatusBarContentInsetsProvider.class);
}
@@ -177,7 +177,11 @@ public class PhoneStatusBarView extends PanelBar {
@Override
public boolean panelEnabled() {
- return mCommandQueue.panelsEnabled();
+ if (mPanelEnabledProvider == null) {
+ Log.e(TAG, "panelEnabledProvider is null; defaulting to super class.");
+ return super.panelEnabled();
+ }
+ return mPanelEnabledProvider.panelEnabled();
}
@Override
@@ -294,6 +298,11 @@ public class PhoneStatusBarView extends PanelBar {
}
}
+ /** Set the {@link PanelEnabledProvider} to use. */
+ public void setPanelEnabledProvider(PanelEnabledProvider panelEnabledProvider) {
+ mPanelEnabledProvider = panelEnabledProvider;
+ }
+
private void updateScrimFraction() {
float scrimFraction = mPanelFraction;
if (mMinFraction < 1.0f) {
@@ -391,4 +400,10 @@ public class PhoneStatusBarView extends PanelBar {
protected boolean shouldPanelBeVisible() {
return mHeadsUpVisible || super.shouldPanelBeVisible();
}
+
+ /** An interface that will provide whether panel is enabled. */
+ interface PanelEnabledProvider {
+ /** Returns true if the panel is enabled and false otherwise. */
+ boolean panelEnabled();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.java
new file mode 100644
index 000000000000..b36b67dc02c0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.util.ViewController;
+
+/** Controller for {@link PhoneStatusBarView}. */
+public class PhoneStatusBarViewController extends ViewController<PhoneStatusBarView> {
+
+ protected PhoneStatusBarViewController(
+ PhoneStatusBarView view,
+ CommandQueue commandQueue) {
+ super(view);
+ mView.setPanelEnabledProvider(commandQueue::panelsEnabled);
+ }
+
+ @Override
+ protected void onViewAttached() {
+ }
+
+ @Override
+ protected void onViewDetached() {
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 9d2f1f871708..43a8630e2791 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -480,8 +480,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
boolean relevantState = (mState == ScrimState.UNLOCKED
|| mState == ScrimState.KEYGUARD
|| mState == ScrimState.SHADE_LOCKED
- || mState == ScrimState.PULSING
- || mState == ScrimState.BUBBLE_EXPANDED);
+ || mState == ScrimState.PULSING);
if (!(relevantState && mExpansionAffectsAlpha)) {
return;
}
@@ -548,8 +547,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
mQsBottomVisible = qsBottomVisible;
boolean relevantState = (mState == ScrimState.SHADE_LOCKED
|| mState == ScrimState.KEYGUARD
- || mState == ScrimState.PULSING
- || mState == ScrimState.BUBBLE_EXPANDED);
+ || mState == ScrimState.PULSING);
if (!(relevantState && mExpansionAffectsAlpha)) {
return;
}
@@ -622,7 +620,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
return;
}
- if (mState == ScrimState.UNLOCKED || mState == ScrimState.BUBBLE_EXPANDED) {
+ if (mState == ScrimState.UNLOCKED) {
// Darken scrim as you pull down the shade when unlocked, unless the shade is expanding
// because we're doing the screen off animation.
if (!mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 0297384de715..e33c9f84aa73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -250,23 +250,6 @@ public enum ScrimState {
updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
}
}
- },
-
- /**
- * Unlocked with a bubble expanded.
- */
- BUBBLE_EXPANDED {
- @Override
- public void prepare(ScrimState previousState) {
- mFrontTint = Color.TRANSPARENT;
- mBehindTint = Color.TRANSPARENT;
-
- mFrontAlpha = 0f;
- mBehindAlpha = mDefaultScrimAlpha;
-
- mAnimationDuration = ScrimController.ANIMATION_DURATION;
- mBlankScreen = false;
- }
};
boolean mBlankScreen = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
index 70f3436cc783..4b7fe4e7ea29 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
@@ -17,10 +17,11 @@
package com.android.systemui.statusbar.phone
import android.view.View
-import com.android.systemui.BatteryMeterView
import com.android.systemui.R
+import com.android.systemui.battery.BatteryMeterView
+import com.android.systemui.battery.BatteryMeterViewController
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.qs.carrier.QSCarrierGroupController
-import com.android.systemui.statusbar.FeatureFlags
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope
import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.SPLIT_SHADE_HEADER
import javax.inject.Inject
@@ -31,7 +32,8 @@ class SplitShadeHeaderController @Inject constructor(
@Named(SPLIT_SHADE_HEADER) private val statusBar: View,
private val statusBarIconController: StatusBarIconController,
qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder,
- featureFlags: FeatureFlags
+ featureFlags: FeatureFlags,
+ batteryMeterViewController: BatteryMeterViewController
) {
// TODO(b/194178072) Handle RSSI hiding when multi carrier
@@ -52,9 +54,11 @@ class SplitShadeHeaderController @Inject constructor(
}
init {
+ batteryMeterViewController.init()
val batteryIcon: BatteryMeterView = statusBar.findViewById(R.id.batteryRemainingIcon)
+
// battery settings same as in QS icons
- batteryIcon.setIgnoreTunerUpdates(true)
+ batteryMeterViewController.ignoreTunerUpdates()
batteryIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE)
val iconContainer: StatusIconContainer = statusBar.findViewById(R.id.statusIcons)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index ef122d2e47b9..bc549326d6bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -18,7 +18,6 @@ package com.android.systemui.statusbar.phone;
import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
-import static android.app.StatusBarManager.WindowType;
import static android.app.StatusBarManager.WindowVisibleState;
import static android.app.StatusBarManager.windowStateToString;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
@@ -32,8 +31,6 @@ import static androidx.lifecycle.Lifecycle.State.RESUMED;
import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
import static com.android.systemui.charging.WirelessChargingLayout.UNKNOWN_BATTERY_LEVEL;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
-import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
-import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
@@ -69,13 +66,10 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
-import android.media.AudioAttributes;
import android.metrics.LogMaker;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -87,8 +81,6 @@ import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
-import android.os.VibrationEffect;
-import android.os.Vibrator;
import android.provider.Settings;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
@@ -103,8 +95,6 @@ import android.util.Slog;
import android.view.Display;
import android.view.IRemoteAnimationRunner;
import android.view.IWindowManager;
-import android.view.InsetsState.InternalInsetsType;
-import android.view.InsetsVisibilities;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.RemoteAnimationAdapter;
@@ -112,7 +102,6 @@ import android.view.ThreadedRenderer;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsetsController.Appearance;
-import android.view.WindowInsetsController.Behavior;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
@@ -132,7 +121,6 @@ import com.android.internal.logging.UiEventLoggerImpl;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.RegisterStatusBarResult;
-import com.android.internal.view.AppearanceRegion;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.ViewMediatorCallback;
@@ -145,10 +133,10 @@ import com.android.systemui.InitController;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
-import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.DelegateLaunchAnimatorController;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.biometrics.AuthRippleController;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.camera.CameraIntents;
@@ -158,9 +146,9 @@ import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.emergency.EmergencyGesture;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.fragments.ExtensionFragmentListener;
import com.android.systemui.fragments.FragmentHostManager;
-import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.KeyguardService;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -187,7 +175,6 @@ import com.android.systemui.statusbar.AutoHideUiElement;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CircleReveal;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyboardShortcuts;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -207,14 +194,11 @@ import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.charging.WiredChargingRippleController;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
@@ -237,10 +221,10 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceP
import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
+import com.android.systemui.tuner.TunerService;
import com.android.systemui.volume.VolumeComponent;
import com.android.systemui.wmshell.BubblesManager;
import com.android.unfold.config.UnfoldTransitionConfig;
@@ -266,8 +250,7 @@ import dagger.Lazy;
/** */
public class StatusBar extends SystemUI implements
ActivityStarter,
- CommandQueue.Callbacks,
- ColorExtractor.OnColorsChangedListener, ConfigurationListener,
+ ConfigurationListener,
StatusBarStateController.StateListener,
LifecycleOwner, BatteryController.BatteryStateChangeCallback,
ActivityLaunchAnimator.Callback {
@@ -280,7 +263,6 @@ public class StatusBar extends SystemUI implements
protected static final int MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU = 1027;
// Should match the values in PhoneWindowManager
- public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
static public final String SYSTEM_DIALOG_REASON_SCREENSHOT = "screenshot";
@@ -312,7 +294,7 @@ public class StatusBar extends SystemUI implements
// 1020-1040 reserved for BaseStatusBar
// Time after we abort the launch transition.
- private static final long LAUNCH_TRANSITION_TIMEOUT_MS = 5000;
+ static final long LAUNCH_TRANSITION_TIMEOUT_MS = 5000;
protected static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
@@ -321,11 +303,6 @@ public class StatusBar extends SystemUI implements
*/
private static final int HINT_RESET_DELAY_MS = 1200;
- private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
- .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
- .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
- .build();
-
public static final int FADE_KEYGUARD_START_DELAY = 100;
public static final int FADE_KEYGUARD_DURATION = 300;
public static final int FADE_KEYGUARD_DURATION_PULSING = 96;
@@ -351,14 +328,113 @@ public class StatusBar extends SystemUI implements
try {
IPackageManager packageManager =
IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
- onlyCoreApps = packageManager.isOnlyCoreApps();
+ onlyCoreApps = packageManager != null && packageManager.isOnlyCoreApps();
} catch (RemoteException e) {
onlyCoreApps = false;
}
ONLY_CORE_APPS = onlyCoreApps;
}
- private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ private StatusBarCommandQueueCallbacks mCommandQueueCallbacks;
+
+ void setWindowState(int state) {
+ mStatusBarWindowState = state;
+ mStatusBarWindowHidden = state == WINDOW_STATE_HIDDEN;
+ }
+
+ void acquireGestureWakeLock(long time) {
+ mGestureWakeLock.acquire(time);
+ }
+
+ boolean setAppearance(int appearance) {
+ if (mAppearance != appearance) {
+ mAppearance = appearance;
+ return updateBarMode(barMode(isTransientShown(), appearance));
+ }
+
+ return false;
+ }
+
+ int getBarMode() {
+ return mStatusBarMode;
+ }
+
+ boolean getWereIconsJustHidden() {
+ return mWereIconsJustHidden;
+ }
+
+ void setWereIconsJustHidden(boolean justHidden) {
+ mWereIconsJustHidden = justHidden;
+ }
+
+ void resetHandlerMsg(int msg) {
+ mHandler.removeMessages(msg);
+ mHandler.sendEmptyMessage(msg);
+ }
+
+ Handler getHandler() {
+ return mHandler;
+ }
+
+ int getDisabled1() {
+ return mDisabled1;
+ }
+
+ void setDisabled1(int disabled) {
+ mDisabled1 = disabled;
+ }
+
+ int getDisabled2() {
+ return mDisabled2;
+ }
+
+ void setDisabled2(int disabled) {
+ mDisabled2 = disabled;
+ }
+
+ void setLastCameraLaunchSource(int source) {
+ mLastCameraLaunchSource = source;
+ }
+
+ void setLaunchCameraOnFinishedGoingToSleep(boolean launch) {
+ mLaunchCameraOnFinishedGoingToSleep = launch;
+ }
+
+ void setLaunchCameraOnFinishedWaking(boolean launch) {
+ mLaunchCameraWhenFinishedWaking = launch;
+ }
+
+ void setLaunchEmergencyActionOnFinishedGoingToSleep(boolean launch) {
+ mLaunchEmergencyActionOnFinishedGoingToSleep = launch;
+ }
+
+ void setLaunchEmergencyActionOnFinishedWaking(boolean launch) {
+ mLaunchEmergencyActionWhenFinishedWaking = launch;
+ }
+
+ void setTopHidesStatusBar(boolean hides) {
+ mTopHidesStatusBar = hides;
+ }
+
+ QSPanelController getQSPanelController() {
+ return mQSPanelController;
+ }
+
+ /** */
+ public void animateExpandNotificationsPanel() {
+ mCommandQueueCallbacks.animateExpandNotificationsPanel();
+ }
+
+ /** */
+ public void animateExpandSettingsPanel(@Nullable String subpanel) {
+ mCommandQueueCallbacks.animateExpandSettingsPanel(subpanel);
+ }
+
+ /** */
+ public void animateCollapsePanels(int flags, boolean force) {
+ mCommandQueueCallbacks.animateCollapsePanels(flags, force);
+ }
public interface ExpansionChangedListener {
void onExpansionChanged(float expansion, boolean expanded);
@@ -370,8 +446,7 @@ public class StatusBar extends SystemUI implements
protected int mState; // TODO: remove this. Just use StatusBarStateController
protected boolean mBouncerShowing;
- private PhoneStatusBarPolicy mIconPolicy;
- private StatusBarSignalPolicy mSignalPolicy;
+ private final PhoneStatusBarPolicy mIconPolicy;
private final VolumeComponent mVolumeComponent;
private BrightnessMirrorController mBrightnessMirrorController;
@@ -382,14 +457,13 @@ public class StatusBar extends SystemUI implements
@Nullable
protected LockscreenWallpaper mLockscreenWallpaper;
private final AutoHideController mAutoHideController;
- @Nullable
- private final KeyguardLiftController mKeyguardLiftController;
private final Point mCurrentDisplaySize = new Point();
protected NotificationShadeWindowView mNotificationShadeWindowView;
protected StatusBarWindowView mPhoneStatusBarWindow;
protected PhoneStatusBarView mStatusBarView;
+ private PhoneStatusBarViewController mPhoneStatusBarViewController;
private AuthRippleController mAuthRippleController;
private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
protected NotificationShadeWindowController mNotificationShadeWindowController;
@@ -400,7 +474,6 @@ public class StatusBar extends SystemUI implements
private boolean mWakeUpComingFromTouch;
private PointF mWakeUpTouchLocation;
private LightRevealScrim mLightRevealScrim;
- private WiredChargingRippleController mChargingRippleAnimationController;
private PowerButtonReveal mPowerButtonReveal;
private final Object mQueueLock = new Object();
@@ -434,9 +507,8 @@ public class StatusBar extends SystemUI implements
private final KeyguardDismissUtil mKeyguardDismissUtil;
private final ExtensionController mExtensionController;
private final UserInfoControllerImpl mUserInfoControllerImpl;
- private final DismissCallbackRegistry mDismissCallbackRegistry;
private final DemoModeController mDemoModeController;
- private NotificationsController mNotificationsController;
+ private final NotificationsController mNotificationsController;
private final OngoingCallController mOngoingCallController;
private final SystemStatusAnimationScheduler mAnimationScheduler;
private final StatusBarLocationPublisher mStatusBarLocationPublisher;
@@ -451,8 +523,6 @@ public class StatusBar extends SystemUI implements
KeyguardIndicationController mKeyguardIndicationController;
- private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
-
private View mReportRejectedTouch;
private boolean mExpandedVisible;
@@ -469,15 +539,18 @@ public class StatusBar extends SystemUI implements
private final UnfoldTransitionConfig mUnfoldTransitionConfig;
private final Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealOverlayAnimation;
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ private final WallpaperManager mWallpaperManager;
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+ private final TunerService mTunerService;
private final List<ExpansionChangedListener> mExpansionChangedListeners;
- // for disabling the status bar
+ // Flags for disabling the status bar
+ // Two variables becaseu the first one evidently ran out of room for new flags.
private int mDisabled1 = 0;
private int mDisabled2 = 0;
- /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int) */
+ /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int, int) */
private @Appearance int mAppearance;
private boolean mTransientShown;
@@ -563,7 +636,7 @@ public class StatusBar extends SystemUI implements
private int mInteractingWindows;
private @TransitionMode int mStatusBarMode;
- private ViewMediatorCallback mKeyguardViewMediatorCallback;
+ private final ViewMediatorCallback mKeyguardViewMediatorCallback;
private final ScrimController mScrimController;
protected DozeScrimController mDozeScrimController;
private final Executor mUiBgExecutor;
@@ -583,8 +656,7 @@ public class StatusBar extends SystemUI implements
Log.wtf(TAG, "WallpaperManager not supported");
return;
}
- WallpaperManager wallpaperManager = context.getSystemService(WallpaperManager.class);
- WallpaperInfo info = wallpaperManager.getWallpaperInfo(UserHandle.USER_CURRENT);
+ WallpaperInfo info = mWallpaperManager.getWallpaperInfo(UserHandle.USER_CURRENT);
final boolean deviceSupportsAodWallpaper = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_dozeSupportsAodWallpaper);
// If WallpaperInfo is null, it must be ImageWallpaper.
@@ -599,22 +671,17 @@ public class StatusBar extends SystemUI implements
BroadcastReceiver mTaskbarChangeReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (mBubblesOptional.isPresent()) {
- mBubblesOptional.get().onTaskbarChanged(intent.getExtras());
- }
+ mBubblesOptional.ifPresent(bubbles -> bubbles.onTaskbarChanged(intent.getExtras()));
}
};
private Runnable mLaunchTransitionEndRunnable;
- private NotificationEntry mDraggedDownEntry;
private boolean mLaunchCameraWhenFinishedWaking;
private boolean mLaunchCameraOnFinishedGoingToSleep;
private boolean mLaunchEmergencyActionWhenFinishedWaking;
private boolean mLaunchEmergencyActionOnFinishedGoingToSleep;
private int mLastCameraLaunchSource;
protected PowerManager.WakeLock mGestureWakeLock;
- private Vibrator mVibrator;
- private VibrationEffect mCameraLaunchGestureVibrationEffect;
private final int[] mTmpInt2 = new int[2];
@@ -698,20 +765,22 @@ public class StatusBar extends SystemUI implements
private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
private HeadsUpAppearanceController mHeadsUpAppearanceController;
- private boolean mVibrateOnOpening;
- private final VibratorHelper mVibratorHelper;
private ActivityLaunchAnimator mActivityLaunchAnimator;
private NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
protected StatusBarNotificationPresenter mPresenter;
private NotificationActivityStarter mNotificationActivityStarter;
- private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
+ private final Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
private final Optional<BubblesManager> mBubblesManagerOptional;
private final Optional<Bubbles> mBubblesOptional;
private final Bubbles.BubbleExpandListener mBubbleExpandListener;
private final Optional<StartingSurface> mStartingSurfaceOptional;
- private ActivityIntentHelper mActivityIntentHelper;
+ private final ActivityIntentHelper mActivityIntentHelper;
private NotificationStackScrollLayoutController mStackScrollerController;
+ private BatteryMeterViewController mBatteryMeterViewController;
+
+ private final ColorExtractor.OnColorsChangedListener mOnColorsChangedListener =
+ (extractor, which) -> updateTheme();
/**
* Public constructor for StatusBar.
@@ -726,7 +795,6 @@ public class StatusBar extends SystemUI implements
LightBarController lightBarController,
AutoHideController autoHideController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- StatusBarSignalPolicy signalPolicy,
PulseExpansionHandler pulseExpansionHandler,
NotificationWakeUpCoordinator notificationWakeUpCoordinator,
KeyguardBypassController keyguardBypassController,
@@ -737,7 +805,6 @@ public class StatusBar extends SystemUI implements
FalsingManager falsingManager,
FalsingCollector falsingCollector,
BroadcastDispatcher broadcastDispatcher,
- RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
NotificationInterruptStateProvider notificationInterruptStateProvider,
@@ -756,19 +823,16 @@ public class StatusBar extends SystemUI implements
ScreenLifecycle screenLifecycle,
WakefulnessLifecycle wakefulnessLifecycle,
SysuiStatusBarStateController statusBarStateController,
- VibratorHelper vibratorHelper,
Optional<BubblesManager> bubblesManagerOptional,
Optional<Bubbles> bubblesOptional,
VisualStabilityManager visualStabilityManager,
DeviceProvisionedController deviceProvisionedController,
NavigationBarController navigationBarController,
- AccessibilityFloatingMenuController accessibilityFloatingMenuController,
Lazy<AssistManager> assistManagerLazy,
ConfigurationController configurationController,
NotificationShadeWindowController notificationShadeWindowController,
DozeParameters dozeParameters,
ScrimController scrimController,
- @Nullable KeyguardLiftController keyguardLiftController,
Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
DozeServiceHost dozeServiceHost,
@@ -795,13 +859,11 @@ public class StatusBar extends SystemUI implements
UserInfoControllerImpl userInfoControllerImpl,
PhoneStatusBarPolicy phoneStatusBarPolicy,
KeyguardIndicationController keyguardIndicationController,
- DismissCallbackRegistry dismissCallbackRegistry,
DemoModeController demoModeController,
Lazy<NotificationShadeDepthController> notificationShadeDepthControllerLazy,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
NotificationIconAreaController notificationIconAreaController,
BrightnessSlider.Factory brightnessSliderFactory,
- WiredChargingRippleController chargingRippleAnimationController,
UnfoldTransitionConfig unfoldTransitionConfig,
Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation,
OngoingCallController ongoingCallController,
@@ -811,14 +873,15 @@ public class StatusBar extends SystemUI implements
LockscreenShadeTransitionController lockscreenShadeTransitionController,
FeatureFlags featureFlags,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
+ WallpaperManager wallpaperManager,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
- Optional<StartingSurface> startingSurfaceOptional) {
+ Optional<StartingSurface> startingSurfaceOptional,
+ TunerService tunerService) {
super(context);
mNotificationsController = notificationsController;
mLightBarController = lightBarController;
mAutoHideController = autoHideController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mSignalPolicy = signalPolicy;
mPulseExpansionHandler = pulseExpansionHandler;
mWakeUpCoordinator = notificationWakeUpCoordinator;
mKeyguardBypassController = keyguardBypassController;
@@ -831,7 +894,6 @@ public class StatusBar extends SystemUI implements
mFalsingCollector = falsingCollector;
mFalsingManager = falsingManager;
mBroadcastDispatcher = broadcastDispatcher;
- mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler;
mGutsManager = notificationGutsManager;
mNotificationLogger = notificationLogger;
mNotificationInterruptStateProvider = notificationInterruptStateProvider;
@@ -850,7 +912,6 @@ public class StatusBar extends SystemUI implements
mScreenLifecycle = screenLifecycle;
mWakefulnessLifecycle = wakefulnessLifecycle;
mStatusBarStateController = statusBarStateController;
- mVibratorHelper = vibratorHelper;
mBubblesManagerOptional = bubblesManagerOptional;
mBubblesOptional = bubblesOptional;
mVisualStabilityManager = visualStabilityManager;
@@ -863,7 +924,6 @@ public class StatusBar extends SystemUI implements
mPowerManager = powerManager;
mDozeParameters = dozeParameters;
mScrimController = scrimController;
- mKeyguardLiftController = keyguardLiftController;
mLockscreenWallpaperLazy = lockscreenWallpaperLazy;
mScreenPinningRequest = screenPinningRequest;
mDozeScrimController = dozeScrimController;
@@ -886,11 +946,9 @@ public class StatusBar extends SystemUI implements
mExtensionController = extensionController;
mUserInfoControllerImpl = userInfoControllerImpl;
mIconPolicy = phoneStatusBarPolicy;
- mDismissCallbackRegistry = dismissCallbackRegistry;
mDemoModeController = demoModeController;
mNotificationIconAreaController = notificationIconAreaController;
mBrightnessSliderFactory = brightnessSliderFactory;
- mChargingRippleAnimationController = chargingRippleAnimationController;
mUnfoldTransitionConfig = unfoldTransitionConfig;
mUnfoldLightRevealOverlayAnimation = unfoldLightRevealOverlayAnimation;
mOngoingCallController = ongoingCallController;
@@ -899,7 +957,9 @@ public class StatusBar extends SystemUI implements
mStatusBarIconController = statusBarIconController;
mFeatureFlags = featureFlags;
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
+ mWallpaperManager = wallpaperManager;
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
+ mTunerService = tunerService;
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
mStartingSurfaceOptional = startingSurfaceOptional;
@@ -908,12 +968,10 @@ public class StatusBar extends SystemUI implements
mExpansionChangedListeners = new ArrayList<>();
mBubbleExpandListener =
- (isExpanding, key) -> {
- mContext.getMainExecutor().execute(() -> {
- mNotificationsController.requestNotificationUpdate("onBubbleExpandChanged");
- updateScrimController();
- });
- };
+ (isExpanding, key) -> mContext.getMainExecutor().execute(() -> {
+ mNotificationsController.requestNotificationUpdate("onBubbleExpandChanged");
+ updateScrimController();
+ });
mActivityIntentHelper = new ActivityIntentHelper(mContext);
DateTimeView.setReceiverHandler(timeTickHandler);
@@ -933,7 +991,7 @@ public class StatusBar extends SystemUI implements
mKeyguardIndicationController.init();
- mColorExtractor.addOnColorsChangedListener(this);
+ mColorExtractor.addOnColorsChangedListener(mOnColorsChangedListener);
mStatusBarStateController.addCallback(this,
SysuiStatusBarStateController.RANK_STATUS_BAR);
@@ -941,13 +999,10 @@ public class StatusBar extends SystemUI implements
mDreamManager = IDreamManager.Stub.asInterface(
ServiceManager.checkService(DreamService.DREAM_SERVICE));
- mDisplay = mWindowManager.getDefaultDisplay();
+ mDisplay = mContext.getDisplay();
mDisplayId = mDisplay.getDisplayId();
updateDisplaySize();
- mVibrateOnOpening = mContext.getResources().getBoolean(
- R.bool.config_vibrateOnIconAnimation);
-
// start old BaseStatusBar.start().
mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
@@ -961,12 +1016,7 @@ public class StatusBar extends SystemUI implements
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
- mWallpaperSupported =
- mContext.getSystemService(WallpaperManager.class).isWallpaperSupported();
-
- // Connect in to the status bar manager service
- mCommandQueue.addCallback(this);
-
+ mWallpaperSupported = mWallpaperManager.isWallpaperSupported();
RegisterStatusBarResult result = null;
try {
@@ -993,13 +1043,13 @@ public class StatusBar extends SystemUI implements
if (containsType(result.mTransientBarTypes, ITYPE_STATUS_BAR)) {
showTransientUnchecked();
}
- onSystemBarAttributesChanged(mDisplayId, result.mAppearance, result.mAppearanceRegions,
- result.mNavbarColorManagedByIme, result.mBehavior, result.mRequestedVisibilities,
- result.mPackageName);
+ mCommandQueueCallbacks.onSystemBarAttributesChanged(mDisplayId, result.mAppearance,
+ result.mAppearanceRegions, result.mNavbarColorManagedByIme, result.mBehavior,
+ result.mRequestedVisibilities, result.mPackageName);
// StatusBarManagerService has a back up of IME token and it's restored here.
- setImeWindowStatus(mDisplayId, result.mImeToken, result.mImeWindowVis,
- result.mImeBackDisposition, result.mShowImeSwitcher);
+ mCommandQueueCallbacks.setImeWindowStatus(mDisplayId, result.mImeToken,
+ result.mImeWindowVis, result.mImeBackDisposition, result.mShowImeSwitcher);
// Set up the initial icon state
int numIcons = result.mIcons.size();
@@ -1075,7 +1125,7 @@ public class StatusBar extends SystemUI implements
mPluginManager.addPluginListener(
new PluginListener<OverlayPlugin>() {
- private ArraySet<OverlayPlugin> mOverlays = new ArraySet<>();
+ private final ArraySet<OverlayPlugin> mOverlays = new ArraySet<>();
@Override
public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
@@ -1124,7 +1174,6 @@ public class StatusBar extends SystemUI implements
// Constructing the view
// ================================================================================
protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {
- final Context context = mContext;
updateDisplaySize(); // populates mDisplayMetrics
updateResources();
updateTheme();
@@ -1162,6 +1211,16 @@ public class StatusBar extends SystemUI implements
mStatusBarView.setPanel(mNotificationPanelViewController);
mStatusBarView.setScrimController(mScrimController);
mStatusBarView.setExpansionChangedListeners(mExpansionChangedListeners);
+ mPhoneStatusBarViewController =
+ new PhoneStatusBarViewController(mStatusBarView, mCommandQueue);
+ mPhoneStatusBarViewController.init();
+
+ mBatteryMeterViewController = new BatteryMeterViewController(
+ mStatusBarView.findViewById(R.id.battery),
+ mConfigurationController,
+ mTunerService
+ );
+ mBatteryMeterViewController.init();
// CollapsedStatusBarFragment re-inflated PhoneStatusBarView and both of
// mStatusBarView.mExpanded and mStatusBarView.mBouncerShowing are false.
@@ -1315,6 +1374,7 @@ public class StatusBar extends SystemUI implements
fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> {
QS qs = (QS) f;
if (qs instanceof QSFragment) {
+ mQSPanelController = ((QSFragment) qs).getQSPanelController();
((QSFragment) qs).setBrightnessMirrorController(mBrightnessMirrorController);
}
});
@@ -1346,14 +1406,11 @@ public class StatusBar extends SystemUI implements
});
}
- if (!mPowerManager.isScreenOn()) {
+ if (!mPowerManager.isInteractive()) {
mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
}
mGestureWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
- "GestureWakeLock");
- mVibrator = mContext.getSystemService(Vibrator.class);
- mCameraLaunchGestureVibrationEffect = getCameraGestureVibrationEffect(
- mVibrator, context.getResources());
+ "sysui:GestureWakeLock");
// receive broadcasts
registerBroadcastReceiver();
@@ -1362,7 +1419,7 @@ public class StatusBar extends SystemUI implements
if (DEBUG_MEDIA_FAKE_ARTWORK) {
demoFilter.addAction(ACTION_FAKE_ARTWORK);
}
- context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
+ mContext.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
android.Manifest.permission.DUMP, null);
// listen for USER_SETUP_COMPLETE setting (per-user)
@@ -1599,8 +1656,17 @@ public class StatusBar extends SystemUI implements
mHeadsUpManager.addListener(statusBarComponent.getStatusBarHeadsUpChangeListener());
+ mHeadsUpManager.addListener(statusBarComponent.getStatusBarHeadsUpChangeListener());
+
// Listen for demo mode changes
mDemoModeController.addCallback(statusBarComponent.getStatusBarDemoMode());
+
+ if (mCommandQueueCallbacks != null) {
+ mCommandQueue.removeCallback(mCommandQueueCallbacks);
+ }
+ mCommandQueueCallbacks = statusBarComponent.getStatusBarCommandQueueCallbacks();
+ // Connect in to the status bar manager service
+ mCommandQueue.addCallback(mCommandQueueCallbacks);
}
protected void startKeyguard() {
@@ -1650,7 +1716,7 @@ public class StatusBar extends SystemUI implements
Trace.endSection();
}
- protected View getStatusBarView() {
+ protected PhoneStatusBarView getStatusBarView() {
return mStatusBarView;
}
@@ -1712,7 +1778,7 @@ public class StatusBar extends SystemUI implements
* If the user switcher is simple then disable QS during setup because
* the user intends to use the lock screen user switcher, QS in not needed.
*/
- private void updateQsExpansionEnabled() {
+ void updateQsExpansionEnabled() {
final boolean expandEnabled = mDeviceProvisionedController.isDeviceProvisioned()
&& (mUserSetup || mUserSwitcherController == null
|| !mUserSwitcherController.isSimpleUserSwitcher())
@@ -1728,22 +1794,6 @@ public class StatusBar extends SystemUI implements
return (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0;
}
- public void addQsTile(ComponentName tile) {
- if (mQSPanelController != null && mQSPanelController.getHost() != null) {
- mQSPanelController.getHost().addTile(tile);
- }
- }
-
- public void remQsTile(ComponentName tile) {
- if (mQSPanelController != null && mQSPanelController.getHost() != null) {
- mQSPanelController.getHost().removeTile(tile);
- }
- }
-
- public void clickTile(ComponentName tile) {
- mQSPanelController.clickTile(tile);
- }
-
/**
* Request a notification update
* @param reason why we're requesting a notification update
@@ -1769,94 +1819,6 @@ public class StatusBar extends SystemUI implements
&& mFalsingCollector.isReportingEnabled() ? View.VISIBLE : View.INVISIBLE);
}
- /**
- * State is one or more of the DISABLE constants from StatusBarManager.
- */
- @Override
- public void disable(int displayId, int state1, int state2, boolean animate) {
- if (displayId != mDisplayId) {
- return;
- }
- state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2);
-
- animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN;
- final int old1 = mDisabled1;
- final int diff1 = state1 ^ old1;
- mDisabled1 = state1;
-
- final int old2 = mDisabled2;
- final int diff2 = state2 ^ old2;
- mDisabled2 = state2;
-
- if (DEBUG) {
- Log.d(TAG, String.format("disable1: 0x%08x -> 0x%08x (diff1: 0x%08x)",
- old1, state1, diff1));
- Log.d(TAG, String.format("disable2: 0x%08x -> 0x%08x (diff2: 0x%08x)",
- old2, state2, diff2));
- }
-
- StringBuilder flagdbg = new StringBuilder();
- flagdbg.append("disable<");
- flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_EXPAND)) ? 'E' : 'e');
- flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_EXPAND)) ? '!' : ' ');
- flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS)) ? 'I' : 'i');
- flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS)) ? '!' : ' ');
- flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS)) ? 'A' : 'a');
- flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS)) ? '!' : ' ');
- flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO)) ? 'S' : 's');
- flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_SYSTEM_INFO)) ? '!' : ' ');
- flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_BACK)) ? 'B' : 'b');
- flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_BACK)) ? '!' : ' ');
- flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_HOME)) ? 'H' : 'h');
- flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_HOME)) ? '!' : ' ');
- flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_RECENT)) ? 'R' : 'r');
- flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_RECENT)) ? '!' : ' ');
- flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_CLOCK)) ? 'C' : 'c');
- flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_CLOCK)) ? '!' : ' ');
- flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SEARCH)) ? 'S' : 's');
- flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_SEARCH)) ? '!' : ' ');
- flagdbg.append("> disable2<");
- flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS)) ? 'Q' : 'q');
- flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS)) ? '!' : ' ');
- flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_SYSTEM_ICONS)) ? 'I' : 'i');
- flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_SYSTEM_ICONS)) ? '!' : ' ');
- flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE)) ? 'N' : 'n');
- flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE)) ? '!' : ' ');
- flagdbg.append('>');
- Log.d(TAG, flagdbg.toString());
-
- if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) {
- if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) {
- mShadeController.animateCollapsePanels();
- }
- }
-
- if ((diff1 & StatusBarManager.DISABLE_RECENT) != 0) {
- if ((state1 & StatusBarManager.DISABLE_RECENT) != 0) {
- // close recents if it's visible
- mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
- mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
- }
- }
-
- if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
- if (areNotificationAlertsDisabled()) {
- mHeadsUpManager.releaseAllImmediately();
- }
- }
-
- if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) {
- updateQsExpansionEnabled();
- }
-
- if ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
- updateQsExpansionEnabled();
- if ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
- mShadeController.animateCollapsePanels();
- }
- }
- }
-
boolean areNotificationAlertsDisabled() {
return (mDisabled1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
}
@@ -1953,11 +1915,6 @@ public class StatusBar extends SystemUI implements
return mNotificationPanelViewController.hideStatusBarIconsWhenExpanded();
}
- @Override
- public void onColorsChanged(ColorExtractor extractor, int which) {
- updateTheme();
- }
-
@Nullable
public View getAmbientIndicationContainer() {
return mAmbientIndicationContainer;
@@ -1993,7 +1950,7 @@ public class StatusBar extends SystemUI implements
*
* @param animate should the change of the icons be animated.
*/
- private void updateHideIconsForBouncer(boolean animate) {
+ void updateHideIconsForBouncer(boolean animate) {
boolean hideBecauseApp = mTopHidesStatusBar && mIsOccluded
&& (mStatusBarWindowHidden || mBouncerShowing);
boolean hideBecauseKeyguard = !mPanelExpanded && !mIsOccluded && mBouncerShowing;
@@ -2107,15 +2064,14 @@ public class StatusBar extends SystemUI implements
mState = state;
}
- @VisibleForTesting
- void setUserSetupForTest(boolean userSetup) {
- mUserSetup = userSetup;
- }
-
/**
* All changes to the status bar and notifications funnel through here and are batched.
*/
protected class H extends Handler {
+ H() {
+ super(Looper.myLooper());
+ }
+
@Override
public void handleMessage(Message m) {
switch (m.what) {
@@ -2127,10 +2083,10 @@ public class StatusBar extends SystemUI implements
break;
// End old BaseStatusBar.H handling.
case MSG_OPEN_NOTIFICATION_PANEL:
- animateExpandNotificationsPanel();
+ mCommandQueueCallbacks.animateExpandNotificationsPanel();
break;
case MSG_OPEN_SETTINGS_PANEL:
- animateExpandSettingsPanel((String) m.obj);
+ mCommandQueueCallbacks.animateExpandSettingsPanel((String) m.obj);
break;
case MSG_CLOSE_PANELS:
mShadeController.animateCollapsePanels();
@@ -2162,59 +2118,6 @@ public class StatusBar extends SystemUI implements
mHeadsUpManager.releaseAllImmediately();
}
- /**
- * Called for system navigation gestures. First action opens the panel, second opens
- * settings. Down action closes the entire panel.
- */
- @Override
- public void handleSystemKey(int key) {
- if (SPEW) Log.d(TAG, "handleNavigationKey: " + key);
- if (!mCommandQueue.panelsEnabled() || !mKeyguardUpdateMonitor.isDeviceInteractive()
- || mKeyguardStateController.isShowing() && !mKeyguardStateController.isOccluded()) {
- return;
- }
-
- // Panels are not available in setup
- if (!mUserSetup) return;
-
- if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP == key) {
- mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_UP);
- mNotificationPanelViewController.collapse(
- false /* delayed */, 1.0f /* speedUpFactor */);
- } else if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN == key) {
- mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_DOWN);
- if (mNotificationPanelViewController.isFullyCollapsed()) {
- if (mVibrateOnOpening) {
- mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
- }
- mNotificationPanelViewController.expand(true /* animate */);
- mStackScroller.setWillExpand(true);
- mHeadsUpManager.unpinAll(true /* userUnpinned */);
- mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN, 1);
- } else if (!mNotificationPanelViewController.isInSettings()
- && !mNotificationPanelViewController.isExpanding()) {
- mNotificationPanelViewController.flingSettings(0 /* velocity */,
- NotificationPanelView.FLING_EXPAND);
- mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN_QS, 1);
- }
- }
-
- }
-
- @Override
- public void showPinningEnterExitToast(boolean entering) {
- if (getNavigationBarView() != null) {
- getNavigationBarView().showPinningEnterExitToast(entering);
- }
- }
-
- @Override
- public void showPinningEscapeToast() {
- if (getNavigationBarView() != null) {
- getNavigationBarView().showPinningEscapeToast();
- }
- }
-
void makeExpandedVisible(boolean force) {
if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
if (!force && (mExpandedVisible || !mCommandQueue.panelsEnabled())) {
@@ -2245,21 +2148,6 @@ public class StatusBar extends SystemUI implements
mHandler.sendEmptyMessage(MSG_OPEN_SETTINGS_PANEL);
}
- @Override
- public void togglePanel() {
- if (mPanelExpanded) {
- mShadeController.animateCollapsePanels();
- } else {
- animateExpandNotificationsPanel();
- }
- }
-
- @Override
- public void animateCollapsePanels(int flags, boolean force) {
- mShadeController.animateCollapsePanels(flags, force, false /* delayed */,
- 1.0f /* speedUpFactor */);
- }
-
/**
* Called by {@link ShadeController} when it calls
* {@link ShadeController#animateCollapsePanels(int, boolean, boolean, float)}.
@@ -2294,36 +2182,6 @@ public class StatusBar extends SystemUI implements
}
}
- @Override
- public void animateExpandNotificationsPanel() {
- if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
- if (!mCommandQueue.panelsEnabled()) {
- return ;
- }
-
- mNotificationPanelViewController.expandWithoutQs();
-
- if (false) postStartTracing();
- }
-
- @Override
- public void animateExpandSettingsPanel(@Nullable String subPanel) {
- if (SPEW) Log.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
- if (!mCommandQueue.panelsEnabled()) {
- return;
- }
-
- // Settings are not available in setup
- if (!mUserSetup) return;
-
- if (subPanel != null) {
- mQSPanelController.openDetails(subPanel);
- }
- mNotificationPanelViewController.expandWithQs();
-
- if (false) postStartTracing();
- }
-
public void animateCollapseQuickSettings() {
if (mState == StatusBarState.SHADE) {
mStatusBarView.collapsePanel(true, false /* delayed */, 1.0f /* speedUpFactor */);
@@ -2403,11 +2261,7 @@ public class StatusBar extends SystemUI implements
final boolean upOrCancel =
event.getAction() == MotionEvent.ACTION_UP ||
event.getAction() == MotionEvent.ACTION_CANCEL;
- if (upOrCancel && !mExpandedVisible) {
- setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
- } else {
- setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
- }
+ setInteracting(StatusBarManager.WINDOW_STATUS_BAR, !upOrCancel || mExpandedVisible);
}
return false;
}
@@ -2424,63 +2278,7 @@ public class StatusBar extends SystemUI implements
return mBiometricUnlockController;
}
- @Override // CommandQueue
- public void setWindowState(
- int displayId, @WindowType int window, @WindowVisibleState int state) {
- if (displayId != mDisplayId) {
- return;
- }
- boolean showing = state == WINDOW_STATE_SHOWING;
- if (mNotificationShadeWindowView != null
- && window == StatusBarManager.WINDOW_STATUS_BAR
- && mStatusBarWindowState != state) {
- mStatusBarWindowState = state;
- if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state));
- if (mStatusBarView != null) {
- if (!showing && mState == StatusBarState.SHADE) {
- mStatusBarView.collapsePanel(false /* animate */, false /* delayed */,
- 1.0f /* speedUpFactor */);
- }
- mStatusBarWindowHidden = state == WINDOW_STATE_HIDDEN;
- updateHideIconsForBouncer(false /* animate */);
- }
- }
-
- updateBubblesVisibility();
- }
-
- @Override
- public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
- AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
- @Behavior int behavior, InsetsVisibilities requestedVisibilities, String packageName) {
- if (displayId != mDisplayId) {
- return;
- }
- boolean barModeChanged = false;
- if (mAppearance != appearance) {
- mAppearance = appearance;
- barModeChanged = updateBarMode(barMode(mTransientShown, appearance));
- }
- mLightBarController.onStatusBarAppearanceChanged(appearanceRegions, barModeChanged,
- mStatusBarMode, navbarColorManagedByIme);
-
- updateBubblesVisibility();
- mStatusBarStateController.setSystemBarAttributes(
- appearance, behavior, requestedVisibilities, packageName);
- }
-
- @Override
- public void showTransient(int displayId, @InternalInsetsType int[] types) {
- if (displayId != mDisplayId) {
- return;
- }
- if (!containsType(types, ITYPE_STATUS_BAR)) {
- return;
- }
- showTransientUnchecked();
- }
-
- private void showTransientUnchecked() {
+ void showTransientUnchecked() {
if (!mTransientShown) {
mTransientShown = true;
mNoAnimationOnNextBarModeChange = true;
@@ -2488,18 +2286,8 @@ public class StatusBar extends SystemUI implements
}
}
- @Override
- public void abortTransient(int displayId, @InternalInsetsType int[] types) {
- if (displayId != mDisplayId) {
- return;
- }
- if (!containsType(types, ITYPE_STATUS_BAR)) {
- return;
- }
- clearTransient();
- }
- private void clearTransient() {
+ void clearTransient() {
if (mTransientShown) {
mTransientShown = false;
handleTransientChanged();
@@ -2541,8 +2329,7 @@ public class StatusBar extends SystemUI implements
}
}
- @Override
- public void showWirelessChargingAnimation(int batteryLevel) {
+ protected void showWirelessChargingAnimation(int batteryLevel) {
showChargingAnimation(batteryLevel, UNKNOWN_BATTERY_LEVEL, 0);
}
@@ -2563,11 +2350,6 @@ public class StatusBar extends SystemUI implements
}, false, sUiEventLogger).show(animationDelay);
}
- @Override
- public void onRecentsAnimationStateChanged(boolean running) {
- setInteracting(StatusBarManager.WINDOW_NAVIGATION_BAR, running);
- }
-
protected BarTransitions getStatusBarTransitions() {
return mNotificationShadeWindowViewController.getBarTransitions();
}
@@ -2587,13 +2369,11 @@ public class StatusBar extends SystemUI implements
}
/** Temporarily hides Bubbles if the status bar is hidden. */
- private void updateBubblesVisibility() {
- if (mBubblesOptional.isPresent()) {
- mBubblesOptional.get().onStatusBarVisibilityChanged(
- mStatusBarMode != MODE_LIGHTS_OUT
- && mStatusBarMode != MODE_LIGHTS_OUT_TRANSPARENT
- && !mStatusBarWindowHidden);
- }
+ void updateBubblesVisibility() {
+ mBubblesOptional.ifPresent(bubbles -> bubbles.onStatusBarVisibilityChanged(
+ mStatusBarMode != MODE_LIGHTS_OUT
+ && mStatusBarMode != MODE_LIGHTS_OUT_TRANSPARENT
+ && !mStatusBarWindowHidden));
}
void checkBarMode(@TransitionMode int mode, @WindowVisibleState int windowState,
@@ -2677,7 +2457,7 @@ public class StatusBar extends SystemUI implements
mNotificationPanelViewController.dump(fd, pw, args);
}
pw.println(" mStackScroller: ");
- if (mStackScroller instanceof Dumpable) {
+ if (mStackScroller != null) {
pw.print (" ");
((Dumpable) mStackScroller).dump(fd, pw, args);
}
@@ -2710,19 +2490,6 @@ public class StatusBar extends SystemUI implements
mNotificationsController.dump(fd, pw, args, DUMPTRUCK);
- if (DUMPTRUCK) {
- if (false) {
- pw.println("see the logcat for a dump of the views we have created.");
- // must happen on ui thread
- mHandler.post(() -> {
- mStatusBarView.getLocationOnScreen(mAbsPos);
- Log.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] +
- ") " + mStatusBarView.getWidth() + "x" + getStatusBarHeight());
- mStatusBarView.debug();
- });
- }
- }
-
if (DEBUG_GESTURES) {
pw.print(" status bar gestures: ");
mGestureRec.dump(fd, pw, args);
@@ -2753,7 +2520,7 @@ public class StatusBar extends SystemUI implements
pw.println(" Insecure camera: " + CameraIntents.getInsecureCameraIntent(mContext));
pw.println(" Secure camera: " + CameraIntents.getSecureCameraIntent(mContext));
pw.println(" Override package: "
- + String.valueOf(CameraIntents.getOverrideCameraPackage(mContext)));
+ + CameraIntents.getOverrideCameraPackage(mContext));
}
public static void dumpBarTransitions(
@@ -2814,7 +2581,7 @@ public class StatusBar extends SystemUI implements
startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, 0);
}
- private void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
+ void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
final boolean dismissShade, final boolean disallowEnterPictureInPictureWhileLaunching,
final Callback callback, int flags,
@Nullable ActivityLaunchAnimator.Controller animationController) {
@@ -2859,7 +2626,7 @@ public class StatusBar extends SystemUI implements
options.setRotationAnimationHint(
WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS);
}
- if (intent.getAction() == Settings.Panel.ACTION_VOLUME) {
+ if (intent.getAction().equals(Settings.Panel.ACTION_VOLUME)) {
// Settings Panel is implemented as activity(not a dialog), so
// underlying app is paused and may enter picture-in-picture mode
// as a result.
@@ -2958,7 +2725,7 @@ public class StatusBar extends SystemUI implements
&& mStatusBarKeyguardViewManager.isOccluded()) {
mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
} else {
- AsyncTask.execute(runnable);
+ mHandler.post(runnable);
}
}
if (dismissShade) {
@@ -3241,37 +3008,6 @@ public class StatusBar extends SystemUI implements
| ((currentlyInsecure ? 1 : 0) << 12);
}
- //
- // tracing
- //
-
- void postStartTracing() {
- mHandler.postDelayed(mStartTracing, 3000);
- }
-
- void vibrate() {
- android.os.Vibrator vib = (android.os.Vibrator)mContext.getSystemService(
- Context.VIBRATOR_SERVICE);
- vib.vibrate(250, VIBRATION_ATTRIBUTES);
- }
-
- final Runnable mStartTracing = new Runnable() {
- @Override
- public void run() {
- vibrate();
- SystemClock.sleep(250);
- Log.d(TAG, "startTracing");
- android.os.Debug.startMethodTracing("/data/statusbar-traces/trace");
- mHandler.postDelayed(mStopTracing, 10000);
- }
- };
-
- final Runnable mStopTracing = () -> {
- android.os.Debug.stopMethodTracing();
- Log.d(TAG, "stopTracing");
- vibrate();
- };
-
@Override
public void postQSRunnableDismissingKeyguard(final Runnable runnable) {
mHandler.post(() -> {
@@ -3452,7 +3188,7 @@ public class StatusBar extends SystemUI implements
*/
public void animateKeyguardUnoccluding() {
mNotificationPanelViewController.setExpandedFraction(0f);
- animateExpandNotificationsPanel();
+ mCommandQueueCallbacks.animateExpandNotificationsPanel();
}
/**
@@ -3623,7 +3359,7 @@ public class StatusBar extends SystemUI implements
/**
* While IME is active and a BACK event is detected, check with
- * {@link StatusBarKeyguardViewManager#dispatchBackKeyEventPreIme(KeyEvent)} to see if the event
+ * {@link StatusBarKeyguardViewManager#dispatchBackKeyEventPreIme()} to see if the event
* should be handled before routing to IME, in order to prevent the user having to hit back
* twice to exit bouncer.
*/
@@ -3949,7 +3685,8 @@ public class StatusBar extends SystemUI implements
// This gets executed before we will show Keyguard, so post it in order that the state
// is correct.
- mHandler.post(() -> onCameraLaunchGestureDetected(mLastCameraLaunchSource));
+ mHandler.post(() -> mCommandQueueCallbacks.onCameraLaunchGestureDetected(
+ mLastCameraLaunchSource));
}
if (mLaunchEmergencyActionOnFinishedGoingToSleep) {
@@ -3957,7 +3694,8 @@ public class StatusBar extends SystemUI implements
// This gets executed before we will show Keyguard, so post it in order that the
// state is correct.
- mHandler.post(() -> onEmergencyActionLaunchGestureDetected());
+ mHandler.post(
+ () -> mCommandQueueCallbacks.onEmergencyActionLaunchGestureDetected());
}
updateIsKeyguard();
}
@@ -4070,36 +3808,6 @@ public class StatusBar extends SystemUI implements
return mWakefulnessLifecycle.getWakefulness();
}
- private void vibrateForCameraGesture() {
- // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
- mVibrator.vibrate(mCameraLaunchGestureVibrationEffect, VIBRATION_ATTRIBUTES);
- }
-
- private static VibrationEffect getCameraGestureVibrationEffect(Vibrator vibrator,
- Resources resources) {
- if (vibrator.areAllPrimitivesSupported(
- VibrationEffect.Composition.PRIMITIVE_QUICK_RISE,
- VibrationEffect.Composition.PRIMITIVE_CLICK)) {
- return VibrationEffect.startComposition()
- .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_RISE)
- .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 50)
- .compose();
- }
- if (vibrator.hasAmplitudeControl()) {
- return VibrationEffect.createWaveform(
- CAMERA_LAUNCH_GESTURE_VIBRATION_TIMINGS,
- CAMERA_LAUNCH_GESTURE_VIBRATION_AMPLITUDES,
- /* repeat= */ -1);
- }
-
- int[] pattern = resources.getIntArray(R.array.config_cameraLaunchGestureVibePattern);
- long[] timings = new long[pattern.length];
- for (int i = 0; i < pattern.length; i++) {
- timings[i] = pattern[i];
- }
- return VibrationEffect.createWaveform(timings, /* repeat= */ -1);
- }
-
/**
* @return true if the screen is currently fully off, i.e. has finished turning off and has
* since not started turning on.
@@ -4108,139 +3816,11 @@ public class StatusBar extends SystemUI implements
return mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_OFF;
}
- @Override
- public void showScreenPinningRequest(int taskId) {
- if (mKeyguardStateController.isShowing()) {
- // Don't allow apps to trigger this from keyguard.
- return;
- }
- // Show screen pinning request, since this comes from an app, show 'no thanks', button.
- showScreenPinningRequest(taskId, true);
- }
-
public void showScreenPinningRequest(int taskId, boolean allowCancel) {
mScreenPinningRequest.showPrompt(taskId, allowCancel);
}
- @Override
- public void appTransitionCancelled(int displayId) {
- if (displayId == mDisplayId) {
- mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.onAppTransitionFinished());
- }
- }
-
- @Override
- public void appTransitionFinished(int displayId) {
- if (displayId == mDisplayId) {
- mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.onAppTransitionFinished());
- }
- }
-
- @Override
- public void onCameraLaunchGestureDetected(int source) {
- mLastCameraLaunchSource = source;
- if (isGoingToSleep()) {
- if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Finish going to sleep before launching camera");
- mLaunchCameraOnFinishedGoingToSleep = true;
- return;
- }
- if (!mNotificationPanelViewController.canCameraGestureBeLaunched()) {
- if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Can't launch camera right now");
- return;
- }
- if (!mDeviceInteractive) {
- mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_CAMERA_LAUNCH,
- "com.android.systemui:CAMERA_GESTURE");
- }
- vibrateForCameraGesture();
-
- if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) {
- Log.v(TAG, "Camera launch");
- mKeyguardUpdateMonitor.onCameraLaunched();
- }
-
- if (!mStatusBarKeyguardViewManager.isShowing()) {
- final Intent cameraIntent = CameraIntents.getInsecureCameraIntent(mContext);
- startActivityDismissingKeyguard(cameraIntent,
- false /* onlyProvisioned */, true /* dismissShade */,
- true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
- null /* animationController */);
- } else {
- if (!mDeviceInteractive) {
- // Avoid flickering of the scrim when we instant launch the camera and the bouncer
- // comes on.
- mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
- }
- if (isWakingUpOrAwake()) {
- if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Launching camera");
- if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
- mStatusBarKeyguardViewManager.reset(true /* hide */);
- }
- mNotificationPanelViewController.launchCamera(
- mDeviceInteractive /* animate */, source);
- updateScrimController();
- } else {
- // We need to defer the camera launch until the screen comes on, since otherwise
- // we will dismiss us too early since we are waiting on an activity to be drawn and
- // incorrectly get notified because of the screen on event (which resumes and pauses
- // some activities)
- if (DEBUG_CAMERA_LIFT) Slog.d(TAG, "Deferring until screen turns on");
- mLaunchCameraWhenFinishedWaking = true;
- }
- }
- }
-
- @Override
- public void onEmergencyActionLaunchGestureDetected() {
- Intent emergencyIntent = getEmergencyActionIntent();
-
- if (emergencyIntent == null) {
- Log.wtf(TAG, "Couldn't find an app to process the emergency intent.");
- return;
- }
-
- if (isGoingToSleep()) {
- mLaunchEmergencyActionOnFinishedGoingToSleep = true;
- return;
- }
-
- if (!mDeviceInteractive) {
- mPowerManager.wakeUp(SystemClock.uptimeMillis(),
- PowerManager.WAKE_REASON_GESTURE,
- "com.android.systemui:EMERGENCY_GESTURE");
- }
- // TODO(b/169087248) Possibly add haptics here for emergency action. Currently disabled for
- // app-side haptic experimentation.
-
- if (!mStatusBarKeyguardViewManager.isShowing()) {
- startActivityDismissingKeyguard(emergencyIntent,
- false /* onlyProvisioned */, true /* dismissShade */,
- true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
- null /* animationController */);
- return;
- }
-
- if (!mDeviceInteractive) {
- // Avoid flickering of the scrim when we instant launch the camera and the bouncer
- // comes on.
- mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
- }
-
- if (isWakingUpOrAwake()) {
- if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
- mStatusBarKeyguardViewManager.reset(true /* hide */);
- }
- mContext.startActivityAsUser(emergencyIntent, UserHandle.CURRENT);
- return;
- }
- // We need to defer the emergency action launch until the screen comes on, since otherwise
- // we will dismiss us too early since we are waiting on an activity to be drawn and
- // incorrectly get notified because of the screen on event (which resumes and pauses
- // some activities)
- mLaunchEmergencyActionWhenFinishedWaking = true;
- }
-
- private @Nullable Intent getEmergencyActionIntent() {
+ @Nullable Intent getEmergencyActionIntent() {
Intent emergencyIntent = new Intent(EmergencyGesture.ACTION_LAUNCH_EMERGENCY);
PackageManager pm = mContext.getPackageManager();
List<ResolveInfo> emergencyActivities = pm.queryIntentActivities(emergencyIntent,
@@ -4298,16 +3878,11 @@ public class StatusBar extends SystemUI implements
return true;
}
- private boolean isGoingToSleep() {
+ boolean isGoingToSleep() {
return mWakefulnessLifecycle.getWakefulness()
== WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP;
}
- private boolean isWakingUpOrAwake() {
- return mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_AWAKE
- || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_WAKING;
- }
-
public void notifyBiometricAuthModeChanged() {
mDozeServiceHost.updateDozing();
updateScrimController();
@@ -4362,8 +3937,6 @@ public class StatusBar extends SystemUI implements
mScrimController.transitionTo(ScrimState.AOD);
} else if (mIsKeyguard && !unlocking) {
mScrimController.transitionTo(ScrimState.KEYGUARD);
- } else if (mBubblesOptional.isPresent() && mBubblesOptional.get().isStackExpanded()) {
- mScrimController.transitionTo(ScrimState.BUBBLE_EXPANDED, mUnlockScrimCallback);
} else {
mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
}
@@ -4460,10 +4033,6 @@ public class StatusBar extends SystemUI implements
mNotificationsController.setNotificationSnoozed(sbn, snoozeOption);
}
- @Override
- public void toggleSplitScreen() {
- toggleSplitScreenMode(-1 /* metricsDockAction */, -1 /* metricsUndockAction */);
- }
public void awakenDreams() {
mUiBgExecutor.execute(() -> {
@@ -4475,46 +4044,6 @@ public class StatusBar extends SystemUI implements
});
}
- @Override
- public void preloadRecentApps() {
- int msg = MSG_PRELOAD_RECENT_APPS;
- mHandler.removeMessages(msg);
- mHandler.sendEmptyMessage(msg);
- }
-
- @Override
- public void cancelPreloadRecentApps() {
- int msg = MSG_CANCEL_PRELOAD_RECENT_APPS;
- mHandler.removeMessages(msg);
- mHandler.sendEmptyMessage(msg);
- }
-
- @Override
- public void dismissKeyboardShortcutsMenu() {
- int msg = MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU;
- mHandler.removeMessages(msg);
- mHandler.sendEmptyMessage(msg);
- }
-
- @Override
- public void toggleKeyboardShortcutsMenu(int deviceId) {
- int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
- mHandler.removeMessages(msg);
- mHandler.obtainMessage(msg, deviceId, 0).sendToTarget();
- }
-
- @Override
- public void setTopAppHidesStatusBar(boolean topAppHidesStatusBar) {
- mTopHidesStatusBar = topAppHidesStatusBar;
- if (!topAppHidesStatusBar && mWereIconsJustHidden) {
- // Immediately update the icon hidden state, since that should only apply if we're
- // staying fullscreen.
- mWereIconsJustHidden = false;
- mCommandQueue.recomputeDisableFlags(mDisplayId, true);
- }
- updateHideIconsForBouncer(true /* animate */);
- }
-
protected void toggleKeyboardShortcuts(int deviceId) {
KeyboardShortcuts.toggle(mContext, deviceId);
}
@@ -4776,34 +4305,19 @@ public class StatusBar extends SystemUI implements
}
return mStatusBarKeyguardViewManager.isSecure();
}
-
- @Override
- public void showAssistDisclosure() {
- mAssistManagerLazy.get().showDisclosure();
- }
-
public NotificationPanelViewController getPanelController() {
return mNotificationPanelViewController;
}
-
- @Override
- public void startAssist(Bundle args) {
- mAssistManagerLazy.get().startAssist(args);
- }
// End Extra BaseStatusBarMethods.
public NotificationGutsManager getGutsManager() {
return mGutsManager;
}
- private boolean isTransientShown() {
+ boolean isTransientShown() {
return mTransientShown;
}
- @Override
- public void suppressAmbientDisplay(boolean suppressed) {
- mDozeServiceHost.setDozeSuppressed(suppressed);
- }
public void addExpansionChangedListener(@NonNull ExpansionChangedListener listener) {
mExpansionChangedListeners.add(listener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
new file mode 100644
index 000000000000..95f2d0a868c6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
@@ -0,0 +1,690 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
+import static android.app.StatusBarManager.windowStateToString;
+import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.InsetsState.containsType;
+
+import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
+import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
+
+import android.annotation.Nullable;
+import android.app.StatusBarManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.media.AudioAttributes;
+import android.os.Bundle;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.util.Log;
+import android.util.Slog;
+import android.view.InsetsState.InternalInsetsType;
+import android.view.InsetsVisibilities;
+import android.view.KeyEvent;
+import android.view.WindowInsetsController.Appearance;
+import android.view.WindowInsetsController.Behavior;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.view.AppearanceRegion;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.R;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.camera.CameraIntents;
+import com.android.systemui.dagger.qualifiers.DisplayId;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.qs.QSPanelController;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
+import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
+
+import java.util.Optional;
+
+import javax.inject.Inject;
+
+/** */
+@StatusBarComponent.StatusBarScope
+public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks {
+ private final StatusBar mStatusBar;
+ private final Context mContext;
+ private final ShadeController mShadeController;
+ private final CommandQueue mCommandQueue;
+ private final NotificationPanelViewController mNotificationPanelViewController;
+ private final Optional<LegacySplitScreen> mSplitScreenOptional;
+ private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
+ private final MetricsLogger mMetricsLogger;
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final KeyguardStateController mKeyguardStateController;
+ private final HeadsUpManager mHeadsUpManager;
+ private final WakefulnessLifecycle mWakefulnessLifecycle;
+ private final DeviceProvisionedController mDeviceProvisionedController;
+ private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ private final AssistManager mAssistManager;
+ private final DozeServiceHost mDozeServiceHost;
+ private final SysuiStatusBarStateController mStatusBarStateController;
+ private final NotificationShadeWindowView mNotificationShadeWindowView;
+ private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
+ private final PowerManager mPowerManager;
+ private final VibratorHelper mVibratorHelper;
+ private final Optional<Vibrator> mVibratorOptional;
+ private final LightBarController mLightBarController;
+ private final int mDisplayId;
+ private final boolean mVibrateOnOpening;
+ private final VibrationEffect mCameraLaunchGestureVibrationEffect;
+
+
+ private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+ .build();
+
+ @Inject
+ StatusBarCommandQueueCallbacks(
+ StatusBar statusBar,
+ Context context,
+ @Main Resources resources,
+ ShadeController shadeController,
+ CommandQueue commandQueue,
+ NotificationPanelViewController notificationPanelViewController,
+ Optional<LegacySplitScreen> splitScreenOptional,
+ RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
+ MetricsLogger metricsLogger,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ KeyguardStateController keyguardStateController,
+ HeadsUpManager headsUpManager,
+ WakefulnessLifecycle wakefulnessLifecycle,
+ DeviceProvisionedController deviceProvisionedController,
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+ AssistManager assistManager,
+ DozeServiceHost dozeServiceHost,
+ SysuiStatusBarStateController statusBarStateController,
+ NotificationShadeWindowView notificationShadeWindowView,
+ NotificationStackScrollLayoutController notificationStackScrollLayoutController,
+ PowerManager powerManager,
+ VibratorHelper vibratorHelper,
+ Optional<Vibrator> vibratorOptional,
+ LightBarController lightBarController,
+ @DisplayId int displayId) {
+
+ mStatusBar = statusBar;
+ mContext = context;
+ mShadeController = shadeController;
+ mCommandQueue = commandQueue;
+ mNotificationPanelViewController = notificationPanelViewController;
+ mSplitScreenOptional = splitScreenOptional;
+ mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler;
+ mMetricsLogger = metricsLogger;
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mKeyguardStateController = keyguardStateController;
+ mHeadsUpManager = headsUpManager;
+ mWakefulnessLifecycle = wakefulnessLifecycle;
+ mDeviceProvisionedController = deviceProvisionedController;
+ mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+ mAssistManager = assistManager;
+ mDozeServiceHost = dozeServiceHost;
+ mStatusBarStateController = statusBarStateController;
+ mNotificationShadeWindowView = notificationShadeWindowView;
+ mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
+ mPowerManager = powerManager;
+ mVibratorHelper = vibratorHelper;
+ mVibratorOptional = vibratorOptional;
+ mLightBarController = lightBarController;
+ mDisplayId = displayId;
+
+ mVibrateOnOpening = resources.getBoolean(R.bool.config_vibrateOnIconAnimation);
+ mCameraLaunchGestureVibrationEffect = getCameraGestureVibrationEffect(
+ mVibratorOptional, resources);
+ }
+
+ @Override
+ public void abortTransient(int displayId, @InternalInsetsType int[] types) {
+ if (displayId != mDisplayId) {
+ return;
+ }
+ if (!containsType(types, ITYPE_STATUS_BAR)) {
+ return;
+ }
+ mStatusBar.clearTransient();
+ }
+
+ @Override
+ public void addQsTile(ComponentName tile) {
+ QSPanelController qsPanelController = mStatusBar.getQSPanelController();
+ if (qsPanelController != null && qsPanelController.getHost() != null) {
+ qsPanelController.getHost().addTile(tile);
+ }
+ }
+
+ @Override
+ public void remQsTile(ComponentName tile) {
+ QSPanelController qsPanelController = mStatusBar.getQSPanelController();
+ if (qsPanelController != null && qsPanelController.getHost() != null) {
+ qsPanelController.getHost().removeTile(tile);
+ }
+ }
+
+ @Override
+ public void clickTile(ComponentName tile) {
+ QSPanelController qsPanelController = mStatusBar.getQSPanelController();
+ if (qsPanelController != null) {
+ qsPanelController.clickTile(tile);
+ }
+ }
+
+ @Override
+ public void animateCollapsePanels(int flags, boolean force) {
+ mShadeController.animateCollapsePanels(flags, force, false /* delayed */,
+ 1.0f /* speedUpFactor */);
+ }
+
+ @Override
+ public void animateExpandNotificationsPanel() {
+ if (StatusBar.SPEW) {
+ Log.d(StatusBar.TAG,
+ "animateExpand: mExpandedVisible=" + mStatusBar.isExpandedVisible());
+ }
+ if (!mCommandQueue.panelsEnabled()) {
+ return;
+ }
+
+ mNotificationPanelViewController.expandWithoutQs();
+ }
+
+ @Override
+ public void animateExpandSettingsPanel(@Nullable String subPanel) {
+ if (StatusBar.SPEW) {
+ Log.d(StatusBar.TAG,
+ "animateExpand: mExpandedVisible=" + mStatusBar.isExpandedVisible());
+ }
+ if (!mCommandQueue.panelsEnabled()) {
+ return;
+ }
+
+ // Settings are not available in setup
+ if (!mDeviceProvisionedController.isCurrentUserSetup()) return;
+
+
+ QSPanelController qsPanelController = mStatusBar.getQSPanelController();
+ if (subPanel != null && qsPanelController != null) {
+ qsPanelController.openDetails(subPanel);
+ }
+ mNotificationPanelViewController.expandWithQs();
+ }
+
+ @Override
+ public void appTransitionCancelled(int displayId) {
+ if (displayId == mDisplayId) {
+ mSplitScreenOptional.ifPresent(LegacySplitScreen::onAppTransitionFinished);
+ }
+ }
+
+ @Override
+ public void appTransitionFinished(int displayId) {
+ if (displayId == mDisplayId) {
+ mSplitScreenOptional.ifPresent(LegacySplitScreen::onAppTransitionFinished);
+ }
+ }
+
+ @Override
+ public void preloadRecentApps() {
+ mStatusBar.resetHandlerMsg(StatusBar.MSG_PRELOAD_RECENT_APPS);
+ }
+
+ @Override
+ public void cancelPreloadRecentApps() {
+ mStatusBar.resetHandlerMsg(StatusBar.MSG_CANCEL_PRELOAD_RECENT_APPS);
+ }
+
+ @Override
+ public void dismissKeyboardShortcutsMenu() {
+ mStatusBar.resetHandlerMsg(StatusBar.MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU);
+ }
+ /**
+ * State is one or more of the DISABLE constants from StatusBarManager.
+ */
+ @Override
+ public void disable(int displayId, int state1, int state2, boolean animate) {
+ if (displayId != mDisplayId) {
+ return;
+ }
+ state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2);
+
+ final int old1 = mStatusBar.getDisabled1();
+ final int diff1 = state1 ^ old1;
+ mStatusBar.setDisabled1(state1);
+
+ final int old2 = mStatusBar.getDisabled2();
+ final int diff2 = state2 ^ old2;
+ mStatusBar.setDisabled2(state2);
+
+ if (StatusBar.DEBUG) {
+ Log.d(StatusBar.TAG, String.format("disable1: 0x%08x -> 0x%08x (diff1: 0x%08x)",
+ old1, state1, diff1));
+ Log.d(StatusBar.TAG, String.format("disable2: 0x%08x -> 0x%08x (diff2: 0x%08x)",
+ old2, state2, diff2));
+ }
+
+ StringBuilder flagdbg = new StringBuilder();
+ flagdbg.append("disable<");
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_EXPAND)) ? 'E' : 'e');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_EXPAND)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS)) ? 'I' : 'i');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS)) ? 'A' : 'a');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO)) ? 'S' : 's');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_SYSTEM_INFO)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_BACK)) ? 'B' : 'b');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_BACK)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_HOME)) ? 'H' : 'h');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_HOME)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_RECENT)) ? 'R' : 'r');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_RECENT)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_CLOCK)) ? 'C' : 'c');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_CLOCK)) ? '!' : ' ');
+ flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SEARCH)) ? 'S' : 's');
+ flagdbg.append(0 != ((diff1 & StatusBarManager.DISABLE_SEARCH)) ? '!' : ' ');
+ flagdbg.append("> disable2<");
+ flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS)) ? 'Q' : 'q');
+ flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS)) ? '!' : ' ');
+ flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_SYSTEM_ICONS)) ? 'I' : 'i');
+ flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_SYSTEM_ICONS)) ? '!' : ' ');
+ flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE)) ? 'N' : 'n');
+ flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE)) ? '!' : ' ');
+ flagdbg.append('>');
+ Log.d(StatusBar.TAG, flagdbg.toString());
+
+ if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) {
+ if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) {
+ mShadeController.animateCollapsePanels();
+ }
+ }
+
+ if ((diff1 & StatusBarManager.DISABLE_RECENT) != 0) {
+ if ((state1 & StatusBarManager.DISABLE_RECENT) != 0) {
+ // close recents if it's visible
+ mStatusBar.resetHandlerMsg(StatusBar.MSG_HIDE_RECENT_APPS);
+ }
+ }
+
+ if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
+ if (mStatusBar.areNotificationAlertsDisabled()) {
+ mHeadsUpManager.releaseAllImmediately();
+ }
+ }
+
+ if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) {
+ mStatusBar.updateQsExpansionEnabled();
+ }
+
+ if ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
+ mStatusBar.updateQsExpansionEnabled();
+ if ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
+ mShadeController.animateCollapsePanels();
+ }
+ }
+ }
+
+ /**
+ * Called for system navigation gestures. First action opens the panel, second opens
+ * settings. Down action closes the entire panel.
+ */
+ @Override
+ public void handleSystemKey(int key) {
+ if (StatusBar.SPEW) {
+ Log.d(StatusBar.TAG, "handleNavigationKey: " + key);
+ }
+ if (!mCommandQueue.panelsEnabled() || !mKeyguardUpdateMonitor.isDeviceInteractive()
+ || mKeyguardStateController.isShowing() && !mKeyguardStateController.isOccluded()) {
+ return;
+ }
+
+ // Panels are not available in setup
+ if (!mDeviceProvisionedController.isCurrentUserSetup()) return;
+
+ if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP == key) {
+ mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_UP);
+ mNotificationPanelViewController.collapse(
+ false /* delayed */, 1.0f /* speedUpFactor */);
+ } else if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN == key) {
+ mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_DOWN);
+ if (mNotificationPanelViewController.isFullyCollapsed()) {
+ if (mVibrateOnOpening) {
+ mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
+ }
+ mNotificationPanelViewController.expand(true /* animate */);
+ mNotificationStackScrollLayoutController.setWillExpand(true);
+ mHeadsUpManager.unpinAll(true /* userUnpinned */);
+ mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN, 1);
+ } else if (!mNotificationPanelViewController.isInSettings()
+ && !mNotificationPanelViewController.isExpanding()) {
+ mNotificationPanelViewController.flingSettings(0 /* velocity */,
+ NotificationPanelView.FLING_EXPAND);
+ mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN_QS, 1);
+ }
+ }
+
+ }
+
+ @Override
+ public void onCameraLaunchGestureDetected(int source) {
+ mStatusBar.setLastCameraLaunchSource(source);
+ if (mStatusBar.isGoingToSleep()) {
+ if (StatusBar.DEBUG_CAMERA_LIFT) {
+ Slog.d(StatusBar.TAG, "Finish going to sleep before launching camera");
+ }
+ mStatusBar.setLaunchCameraOnFinishedGoingToSleep(true);
+ return;
+ }
+ if (!mNotificationPanelViewController.canCameraGestureBeLaunched()) {
+ if (StatusBar.DEBUG_CAMERA_LIFT) {
+ Slog.d(StatusBar.TAG, "Can't launch camera right now");
+ }
+ return;
+ }
+ if (!mStatusBar.isDeviceInteractive()) {
+ mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_CAMERA_LAUNCH,
+ "com.android.systemui:CAMERA_GESTURE");
+ }
+ vibrateForCameraGesture();
+
+ if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) {
+ Log.v(StatusBar.TAG, "Camera launch");
+ mKeyguardUpdateMonitor.onCameraLaunched();
+ }
+
+ if (!mStatusBarKeyguardViewManager.isShowing()) {
+ final Intent cameraIntent = CameraIntents.getInsecureCameraIntent(mContext);
+ mStatusBar.startActivityDismissingKeyguard(cameraIntent,
+ false /* onlyProvisioned */, true /* dismissShade */,
+ true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
+ null /* animationController */);
+ } else {
+ if (!mStatusBar.isDeviceInteractive()) {
+ // Avoid flickering of the scrim when we instant launch the camera and the bouncer
+ // comes on.
+ mStatusBar.acquireGestureWakeLock(StatusBar.LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
+ }
+ if (isWakingUpOrAwake()) {
+ if (StatusBar.DEBUG_CAMERA_LIFT) {
+ Slog.d(StatusBar.TAG, "Launching camera");
+ }
+ if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
+ mStatusBarKeyguardViewManager.reset(true /* hide */);
+ }
+ mNotificationPanelViewController.launchCamera(
+ mStatusBar.isDeviceInteractive() /* animate */, source);
+ mStatusBar.updateScrimController();
+ } else {
+ // We need to defer the camera launch until the screen comes on, since otherwise
+ // we will dismiss us too early since we are waiting on an activity to be drawn and
+ // incorrectly get notified because of the screen on event (which resumes and pauses
+ // some activities)
+ if (StatusBar.DEBUG_CAMERA_LIFT) {
+ Slog.d(StatusBar.TAG, "Deferring until screen turns on");
+ }
+ mStatusBar.setLaunchCameraOnFinishedWaking(true);
+ }
+ }
+ }
+
+ @Override
+ public void onEmergencyActionLaunchGestureDetected() {
+ Intent emergencyIntent = mStatusBar.getEmergencyActionIntent();
+
+ if (emergencyIntent == null) {
+ Log.wtf(StatusBar.TAG, "Couldn't find an app to process the emergency intent.");
+ return;
+ }
+
+ if (isGoingToSleep()) {
+ mStatusBar.setLaunchEmergencyActionOnFinishedGoingToSleep(true);
+ return;
+ }
+
+ if (!mStatusBar.isDeviceInteractive()) {
+ mPowerManager.wakeUp(SystemClock.uptimeMillis(),
+ PowerManager.WAKE_REASON_GESTURE,
+ "com.android.systemui:EMERGENCY_GESTURE");
+ }
+ // TODO(b/169087248) Possibly add haptics here for emergency action. Currently disabled for
+ // app-side haptic experimentation.
+
+ if (!mStatusBarKeyguardViewManager.isShowing()) {
+ mStatusBar.startActivityDismissingKeyguard(emergencyIntent,
+ false /* onlyProvisioned */, true /* dismissShade */,
+ true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
+ null /* animationController */);
+ return;
+ }
+
+ if (!mStatusBar.isDeviceInteractive()) {
+ // Avoid flickering of the scrim when we instant launch the camera and the bouncer
+ // comes on.
+ mStatusBar.acquireGestureWakeLock(StatusBar.LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
+ }
+
+ if (isWakingUpOrAwake()) {
+ if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
+ mStatusBarKeyguardViewManager.reset(true /* hide */);
+ }
+ mContext.startActivityAsUser(emergencyIntent, UserHandle.CURRENT);
+ return;
+ }
+ // We need to defer the emergency action launch until the screen comes on, since otherwise
+ // we will dismiss us too early since we are waiting on an activity to be drawn and
+ // incorrectly get notified because of the screen on event (which resumes and pauses
+ // some activities)
+ mStatusBar.setLaunchEmergencyActionOnFinishedWaking(true);
+ }
+
+ @Override
+ public void onRecentsAnimationStateChanged(boolean running) {
+ mStatusBar.setInteracting(StatusBarManager.WINDOW_NAVIGATION_BAR, running);
+ }
+
+
+ @Override
+ public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
+ AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
+ @Behavior int behavior, InsetsVisibilities requestedVisibilities, String packageName) {
+ if (displayId != mDisplayId) {
+ return;
+ }
+ boolean barModeChanged = mStatusBar.setAppearance(appearance);
+
+ mLightBarController.onStatusBarAppearanceChanged(appearanceRegions, barModeChanged,
+ mStatusBar.getBarMode(), navbarColorManagedByIme);
+
+ mStatusBar.updateBubblesVisibility();
+ mStatusBarStateController.setSystemBarAttributes(
+ appearance, behavior, requestedVisibilities, packageName);
+ }
+
+ @Override
+ public void showTransient(int displayId, @InternalInsetsType int[] types) {
+ if (displayId != mDisplayId) {
+ return;
+ }
+ if (!containsType(types, ITYPE_STATUS_BAR)) {
+ return;
+ }
+ mStatusBar.showTransientUnchecked();
+ }
+
+ @Override
+ public void toggleKeyboardShortcutsMenu(int deviceId) {
+ int msg = StatusBar.MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
+ mStatusBar.getHandler().removeMessages(msg);
+ mStatusBar.getHandler().obtainMessage(msg, deviceId, 0).sendToTarget();
+ }
+
+ @Override
+ public void setTopAppHidesStatusBar(boolean topAppHidesStatusBar) {
+ mStatusBar.setTopHidesStatusBar(topAppHidesStatusBar);
+ if (!topAppHidesStatusBar && mStatusBar.getWereIconsJustHidden()) {
+ // Immediately update the icon hidden state, since that should only apply if we're
+ // staying fullscreen.
+ mStatusBar.setWereIconsJustHidden(false);
+ mCommandQueue.recomputeDisableFlags(mDisplayId, true);
+ }
+ mStatusBar.updateHideIconsForBouncer(true /* animate */);
+ }
+
+ @Override
+ public void setWindowState(
+ int displayId, @StatusBarManager.WindowType int window,
+ @StatusBarManager.WindowVisibleState int state) {
+ if (displayId != mDisplayId) {
+ return;
+ }
+ boolean showing = state == WINDOW_STATE_SHOWING;
+ if (mNotificationShadeWindowView != null
+ && window == StatusBarManager.WINDOW_STATUS_BAR
+ && !mStatusBar.isSameStatusBarState(state)) {
+ mStatusBar.setWindowState(state);
+ if (StatusBar.DEBUG_WINDOW_STATE) {
+ Log.d(StatusBar.TAG, "Status bar " + windowStateToString(state));
+ }
+ if (mStatusBar.getStatusBarView() != null) {
+ if (!showing && mStatusBarStateController.getState() == StatusBarState.SHADE) {
+ mStatusBar.getStatusBarView().collapsePanel(
+ false /* animate */, false /* delayed */, 1.0f /* speedUpFactor */);
+ }
+
+ mStatusBar.updateHideIconsForBouncer(false /* animate */);
+ }
+ }
+
+ mStatusBar.updateBubblesVisibility();
+ }
+
+ @Override
+ public void showAssistDisclosure() {
+ mAssistManager.showDisclosure();
+ }
+
+ @Override
+ public void showPinningEnterExitToast(boolean entering) {
+ if (mStatusBar.getNavigationBarView() != null) {
+ mStatusBar.getNavigationBarView().showPinningEnterExitToast(entering);
+ }
+ }
+
+ @Override
+ public void showPinningEscapeToast() {
+ if (mStatusBar.getNavigationBarView() != null) {
+ mStatusBar.getNavigationBarView().showPinningEscapeToast();
+ }
+ }
+
+ @Override
+ public void showScreenPinningRequest(int taskId) {
+ if (mKeyguardStateController.isShowing()) {
+ // Don't allow apps to trigger this from keyguard.
+ return;
+ }
+ // Show screen pinning request, since this comes from an app, show 'no thanks', button.
+ mStatusBar.showScreenPinningRequest(taskId, true);
+ }
+
+ @Override
+ public void showWirelessChargingAnimation(int batteryLevel) {
+ mStatusBar.showWirelessChargingAnimation(batteryLevel);
+ }
+
+ @Override
+ public void startAssist(Bundle args) {
+ mAssistManager.startAssist(args);
+ }
+
+ @Override
+ public void suppressAmbientDisplay(boolean suppressed) {
+ mDozeServiceHost.setDozeSuppressed(suppressed);
+ }
+
+ @Override
+ public void togglePanel() {
+ if (mStatusBar.isPanelExpanded()) {
+ mShadeController.animateCollapsePanels();
+ } else {
+ animateExpandNotificationsPanel();
+ }
+ }
+
+ @Override
+ public void toggleSplitScreen() {
+ mStatusBar.toggleSplitScreenMode(-1 /* metricsDockAction */, -1 /* metricsUndockAction */);
+ }
+
+ private boolean isGoingToSleep() {
+ return mWakefulnessLifecycle.getWakefulness()
+ == WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP;
+ }
+
+ private boolean isWakingUpOrAwake() {
+ return mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_AWAKE
+ || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_WAKING;
+ }
+
+ private void vibrateForCameraGesture() {
+ // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
+ mVibratorOptional.ifPresent(
+ v -> v.vibrate(mCameraLaunchGestureVibrationEffect, VIBRATION_ATTRIBUTES));
+ }
+
+ private static VibrationEffect getCameraGestureVibrationEffect(
+ Optional<Vibrator> vibratorOptional, Resources resources) {
+ if (vibratorOptional.isPresent() && vibratorOptional.get().areAllPrimitivesSupported(
+ VibrationEffect.Composition.PRIMITIVE_QUICK_RISE,
+ VibrationEffect.Composition.PRIMITIVE_CLICK)) {
+ return VibrationEffect.startComposition()
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_RISE)
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 50)
+ .compose();
+ }
+ if (vibratorOptional.isPresent() && vibratorOptional.get().hasAmplitudeControl()) {
+ return VibrationEffect.createWaveform(
+ StatusBar.CAMERA_LAUNCH_GESTURE_VIBRATION_TIMINGS,
+ StatusBar.CAMERA_LAUNCH_GESTURE_VIBRATION_AMPLITUDES,
+ /* repeat= */ -1);
+ }
+
+ int[] pattern = resources.getIntArray(R.array.config_cameraLaunchGestureVibePattern);
+ long[] timings = new long[pattern.length];
+ for (int i = 0; i < pattern.length; i++) {
+ timings[i] = pattern[i];
+ }
+ return VibrationEffect.createWaveform(timings, /* repeat= */ -1);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index dbe4c1e394eb..48fe77482340 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -37,9 +37,9 @@ import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.demomode.DemoModeCommandReceiver;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarMobileView;
import com.android.systemui.statusbar.StatusBarWifiView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 1717b82d8912..dba3b2418790 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -52,10 +52,10 @@ import com.android.systemui.assist.AssistManager;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationClickNotifier;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
@@ -71,6 +71,7 @@ import com.android.systemui.statusbar.notification.collection.render.GroupMember
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowDragController;
import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -402,6 +403,53 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mIsCollapsingToShowActivityOverLockscreen = false;
}
+ /**
+ * Called when a notification is dropped on proper target window.
+ * Intent that is included in this entry notification,
+ * will be sent by {@link ExpandableNotificationRowDragController}
+ *
+ * @param entry notification entry that is dropped.
+ */
+ @Override
+ public void onDragSuccess(NotificationEntry entry) {
+ // this method is not responsible for intent sending.
+ // will focus follow operation only after drag-and-drop that notification.
+ NotificationVisibility.NotificationLocation location =
+ NotificationLogger.getNotificationLocation(entry);
+ final NotificationVisibility nv = NotificationVisibility.obtain(entry.getKey(),
+ entry.getRanking().getRank(), getVisibleNotificationsCount(), true, location);
+
+ // retrieve the group summary to remove with this entry before we tell NMS the
+ // notification was clicked to avoid a race condition
+ final boolean shouldAutoCancel = shouldAutoCancel(entry.getSbn());
+ final NotificationEntry summaryToRemove = shouldAutoCancel
+ ? mOnUserInteractionCallback.getGroupSummaryToDismiss(entry) : null;
+
+ String notificationKey = entry.getKey();
+ // inform NMS that the notification was clicked
+ mClickNotifier.onNotificationClick(notificationKey, nv);
+
+ if (shouldAutoCancel || mRemoteInputManager.isNotificationKeptForRemoteInputHistory(
+ notificationKey)) {
+ // Immediately remove notification from visually showing.
+ // We have to post the removal to the UI thread for synchronization.
+ mMainThreadHandler.post(() -> {
+ final Runnable removeNotification = () ->
+ mOnUserInteractionCallback.onDismiss(
+ entry, REASON_CLICK, summaryToRemove);
+ if (mPresenter.isCollapsing()) {
+ // To avoid lags we're only performing the remove
+ // after the shade is collapsed
+ mShadeController.addPostCollapseAction(removeNotification);
+ } else {
+ removeNotification.run();
+ }
+ });
+ }
+
+ mIsCollapsingToShowActivityOverLockscreen = false;
+ }
+
private void expandBubbleStackOnMainThread(NotificationEntry entry) {
if (!mBubblesManagerOptional.isPresent()) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index fe52281652a9..71364320839c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -25,7 +25,7 @@ import android.util.Log;
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index a5b868b6f8a3..6b52dca42eda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -149,14 +149,18 @@ class UnlockedScreenOffAnimationController @Inject constructor(
lightRevealAnimationPlaying = false
aodUiAnimationPlaying = false
- // Make sure the status bar is in the correct keyguard state, forcing it if necessary. This
- // is required if the screen off animation is cancelled, since it might be incorrectly left
- // in the KEYGUARD or SHADE states depending on when it was cancelled and whether 'lock
- // instantly' is enabled. We need to force it so that the state is set even if we're going
- // from SHADE to SHADE or KEYGUARD to KEYGUARD, since we might have changed parts of the UI
- // (such as showing AOD in the shade) without actually changing the StatusBarState. This
- // ensures that the UI definitely reflects the desired state.
- statusBar.updateIsKeyguard(true /* force */)
+ // If we can't control the screen off animation, we shouldn't mess with the StatusBar's
+ // keyguard state unnecessarily.
+ if (dozeParameters.get().canControlUnlockedScreenOff()) {
+ // Make sure the status bar is in the correct keyguard state, forcing it if necessary.
+ // This is required if the screen off animation is cancelled, since it might be
+ // incorrectly left in the KEYGUARD or SHADE states depending on when it was cancelled
+ // and whether 'lock instantly' is enabled. We need to force it so that the state is set
+ // even if we're going from SHADE to SHADE or KEYGUARD to KEYGUARD, since we might have
+ // changed parts of the UI (such as showing AOD in the shade) without actually changing
+ // the StatusBarState. This ensures that the UI definitely reflects the desired state.
+ statusBar.updateIsKeyguard(true /* force */)
+ }
}
override fun onStartedGoingToSleep() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
index d71fc9ea6b78..d408c0cc3267 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarComponent.java
@@ -24,6 +24,7 @@ import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController;
import com.android.systemui.statusbar.phone.SplitShadeHeaderController;
+import com.android.systemui.statusbar.phone.StatusBarCommandQueueCallbacks;
import com.android.systemui.statusbar.phone.StatusBarDemoMode;
import com.android.systemui.statusbar.phone.StatusBarHeadsUpChangeListener;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
@@ -103,6 +104,12 @@ public interface StatusBarComponent {
StatusBarHeadsUpChangeListener getStatusBarHeadsUpChangeListener();
/**
+ * Creates a StatusBarCommandQueueCallbacks.
+ */
+ @StatusBarScope
+ StatusBarCommandQueueCallbacks getStatusBarCommandQueueCallbacks();
+
+ /**
* Creates a SplitShadeHeaderController.
*/
@StatusBarScope
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 5e8eecbd9acb..eabb2ab696ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -18,18 +18,16 @@ package com.android.systemui.statusbar.phone.dagger;
import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
+import android.app.WallpaperManager;
import android.content.Context;
import android.os.Handler;
import android.os.PowerManager;
import android.util.DisplayMetrics;
-import androidx.annotation.Nullable;
-
import com.android.internal.logging.MetricsLogger;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.InitController;
-import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollector;
@@ -37,7 +35,7 @@ import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.demomode.DemoModeController;
-import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
@@ -48,9 +46,7 @@ import com.android.systemui.plugins.PluginDependencyProvider;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.shared.plugins.PluginManager;
-import com.android.unfold.config.UnfoldTransitionConfig;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -62,8 +58,6 @@ import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.charging.WiredChargingRippleController;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
@@ -81,7 +75,6 @@ import com.android.systemui.statusbar.phone.DozeServiceHost;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
-import com.android.systemui.statusbar.phone.KeyguardLiftController;
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.LightsOutNotifController;
import com.android.systemui.statusbar.phone.LockscreenWallpaper;
@@ -94,7 +87,6 @@ import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;
import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
-import com.android.systemui.statusbar.phone.StatusBarSignalPolicy;
import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
@@ -104,12 +96,13 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
+import com.android.systemui.tuner.TunerService;
import com.android.systemui.volume.VolumeComponent;
import com.android.systemui.wmshell.BubblesManager;
+import com.android.unfold.config.UnfoldTransitionConfig;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.startingsurface.StartingSurface;
@@ -140,7 +133,6 @@ public interface StatusBarPhoneModule {
LightBarController lightBarController,
AutoHideController autoHideController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- StatusBarSignalPolicy signalPolicy,
PulseExpansionHandler pulseExpansionHandler,
NotificationWakeUpCoordinator notificationWakeUpCoordinator,
KeyguardBypassController keyguardBypassController,
@@ -151,7 +143,6 @@ public interface StatusBarPhoneModule {
FalsingManager falsingManager,
FalsingCollector falsingCollector,
BroadcastDispatcher broadcastDispatcher,
- RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
NotificationInterruptStateProvider notificationInterruptStateProvider,
@@ -170,19 +161,16 @@ public interface StatusBarPhoneModule {
ScreenLifecycle screenLifecycle,
WakefulnessLifecycle wakefulnessLifecycle,
SysuiStatusBarStateController statusBarStateController,
- VibratorHelper vibratorHelper,
Optional<BubblesManager> bubblesManagerOptional,
Optional<Bubbles> bubblesOptional,
VisualStabilityManager visualStabilityManager,
DeviceProvisionedController deviceProvisionedController,
NavigationBarController navigationBarController,
- AccessibilityFloatingMenuController accessibilityFloatingMenuController,
Lazy<AssistManager> assistManagerLazy,
ConfigurationController configurationController,
NotificationShadeWindowController notificationShadeWindowController,
DozeParameters dozeParameters,
ScrimController scrimController,
- @Nullable KeyguardLiftController keyguardLiftController,
Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
DozeServiceHost dozeServiceHost,
@@ -211,11 +199,9 @@ public interface StatusBarPhoneModule {
KeyguardIndicationController keyguardIndicationController,
DemoModeController demoModeController,
Lazy<NotificationShadeDepthController> notificationShadeDepthController,
- DismissCallbackRegistry dismissCallbackRegistry,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
NotificationIconAreaController notificationIconAreaController,
BrightnessSlider.Factory brightnessSliderFactory,
- WiredChargingRippleController chargingRippleAnimationController,
UnfoldTransitionConfig unfoldTransitionConfig,
Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation,
OngoingCallController ongoingCallController,
@@ -225,15 +211,16 @@ public interface StatusBarPhoneModule {
LockscreenShadeTransitionController transitionController,
FeatureFlags featureFlags,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
+ WallpaperManager wallpaperManager,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
- Optional<StartingSurface> startingSurfaceOptional) {
+ Optional<StartingSurface> startingSurfaceOptional,
+ TunerService tunerService) {
return new StatusBar(
context,
notificationsController,
lightBarController,
autoHideController,
keyguardUpdateMonitor,
- signalPolicy,
pulseExpansionHandler,
notificationWakeUpCoordinator,
keyguardBypassController,
@@ -244,7 +231,6 @@ public interface StatusBarPhoneModule {
falsingManager,
falsingCollector,
broadcastDispatcher,
- remoteInputQuickSettingsDisabler,
notificationGutsManager,
notificationLogger,
notificationInterruptStateProvider,
@@ -263,19 +249,16 @@ public interface StatusBarPhoneModule {
screenLifecycle,
wakefulnessLifecycle,
statusBarStateController,
- vibratorHelper,
bubblesManagerOptional,
bubblesOptional,
visualStabilityManager,
deviceProvisionedController,
navigationBarController,
- accessibilityFloatingMenuController,
assistManagerLazy,
configurationController,
notificationShadeWindowController,
dozeParameters,
scrimController,
- keyguardLiftController,
lockscreenWallpaperLazy,
biometricUnlockControllerLazy,
dozeServiceHost,
@@ -301,13 +284,11 @@ public interface StatusBarPhoneModule {
userInfoControllerImpl,
phoneStatusBarPolicy,
keyguardIndicationController,
- dismissCallbackRegistry,
demoModeController,
notificationShadeDepthController,
statusBarTouchableRegionManager,
notificationIconAreaController,
brightnessSliderFactory,
- chargingRippleAnimationController,
unfoldTransitionConfig,
unfoldLightRevealOverlayAnimation,
ongoingCallController,
@@ -317,7 +298,9 @@ public interface StatusBarPhoneModule {
transitionController,
featureFlags,
keyguardUnlockAnimationController,
+ wallpaperManager,
unlockedScreenOffAnimationController,
- startingSurfaceOptional);
+ startingSurfaceOptional,
+ tunerService);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
index d691dca1c898..0e83eda2734a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
@@ -21,6 +21,7 @@ import android.view.View;
import com.android.keyguard.LockIconView;
import com.android.systemui.R;
+import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.biometrics.AuthRippleView;
import com.android.systemui.statusbar.phone.NotificationPanelView;
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
@@ -73,6 +74,13 @@ public abstract class StatusBarViewModule {
/** */
@Provides
@StatusBarComponent.StatusBarScope
+ static BatteryMeterView getBatteryMeterView(@Named(SPLIT_SHADE_HEADER) View view) {
+ return view.findViewById(R.id.batteryRemainingIcon);
+ }
+
+ /** */
+ @Provides
+ @StatusBarComponent.StatusBarScope
public static TapAgainView getTapAgainView(NotificationPanelView npv) {
return npv.getTapAgainView();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 16fa5da9e979..1db6ce4ea2a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -24,7 +24,6 @@ import android.app.Notification.CallStyle.CALL_TYPE_ONGOING
import android.content.Intent
import android.util.Log
import android.view.View
-import android.widget.Chronometer
import androidx.annotation.VisibleForTesting
import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.R
@@ -32,7 +31,7 @@ import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
@@ -130,7 +129,6 @@ class OngoingCallController @Inject constructor(
}
}
-
/**
* Called when the chip's visibility may have changed.
*
@@ -220,7 +218,11 @@ class OngoingCallController @Inject constructor(
uidObserver = object : IUidObserver.Stub() {
override fun onUidStateChanged(
- uid: Int, procState: Int, procStateSeq: Long, capability: Int) {
+ uid: Int,
+ procState: Int,
+ procStateSeq: Long,
+ capability: Int
+ ) {
if (uid == currentCallNotificationInfo.uid) {
val oldIsCallAppVisible = isCallAppVisible
isCallAppVisible = isProcessVisibleToUser(procState)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
new file mode 100644
index 000000000000..41cacf5142fd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+
+import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_IGNORED;
+import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_LOCKED;
+import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCKED;
+
+import static com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule.DEVICE_STATE_ROTATION_LOCK_DEFAULTS;
+
+import android.annotation.Nullable;
+import android.hardware.devicestate.DeviceStateManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseIntArray;
+
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.util.wrapper.RotationPolicyWrapper;
+
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * Handles reading and writing of rotation lock settings per device state, as well as setting
+ * the rotation lock when device state changes.
+ **/
+@SysUISingleton
+public final class DeviceStateRotationLockSettingController implements Listenable,
+ RotationLockController.RotationLockControllerCallback {
+
+ private static final String TAG = "DSRotateLockSettingCon";
+
+ private static final String SEPARATOR_REGEX = ":";
+
+ private final SecureSettings mSecureSettings;
+ private final RotationPolicyWrapper mRotationPolicyWrapper;
+ private final DeviceStateManager mDeviceStateManager;
+ private final Executor mMainExecutor;
+ private final String[] mDeviceStateRotationLockDefaults;
+
+ private SparseIntArray mDeviceStateRotationLockSettings;
+ // TODO(b/183001527): Add API to query current device state and initialize this.
+ private int mDeviceState = -1;
+ @Nullable
+ private DeviceStateManager.DeviceStateCallback mDeviceStateCallback;
+
+
+ @Inject
+ public DeviceStateRotationLockSettingController(
+ SecureSettings secureSettings,
+ RotationPolicyWrapper rotationPolicyWrapper,
+ DeviceStateManager deviceStateManager,
+ @Main Executor executor,
+ @Named(DEVICE_STATE_ROTATION_LOCK_DEFAULTS) String[] deviceStateRotationLockDefaults
+ ) {
+ mSecureSettings = secureSettings;
+ mRotationPolicyWrapper = rotationPolicyWrapper;
+ mDeviceStateManager = deviceStateManager;
+ mMainExecutor = executor;
+ mDeviceStateRotationLockDefaults = deviceStateRotationLockDefaults;
+ }
+
+ /**
+ * Loads the settings from storage.
+ */
+ public void initialize() {
+ String serializedSetting =
+ mSecureSettings.getStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ UserHandle.USER_CURRENT);
+ if (TextUtils.isEmpty(serializedSetting)) {
+ // No settings saved, we should load the defaults and persist them.
+ fallbackOnDefaults();
+ return;
+ }
+ String[] values = serializedSetting.split(SEPARATOR_REGEX);
+ if (values.length % 2 != 0) {
+ // Each entry should be a key/value pair, so this is corrupt.
+ Log.wtf(TAG, "Can't deserialize saved settings, falling back on defaults");
+ fallbackOnDefaults();
+ return;
+ }
+ mDeviceStateRotationLockSettings = new SparseIntArray(values.length / 2);
+ int key;
+ int value;
+
+ for (int i = 0; i < values.length - 1; ) {
+ try {
+ key = Integer.parseInt(values[i++]);
+ value = Integer.parseInt(values[i++]);
+ mDeviceStateRotationLockSettings.put(key, value);
+ } catch (NumberFormatException e) {
+ Log.wtf(TAG, "Error deserializing one of the saved settings", e);
+ fallbackOnDefaults();
+ return;
+ }
+ }
+ }
+
+ private void fallbackOnDefaults() {
+ loadDefaults();
+ persistSettings();
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+ if (listening) {
+ // Note that this is called once with the initial state of the device, even if there
+ // is no user action.
+ mDeviceStateCallback = this::updateDeviceState;
+ mDeviceStateManager.registerCallback(mMainExecutor, mDeviceStateCallback);
+ } else {
+ if (mDeviceStateCallback != null) {
+ mDeviceStateManager.unregisterCallback(mDeviceStateCallback);
+ }
+ }
+ }
+
+ @Override
+ public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
+ if (mDeviceState == -1) {
+ Log.wtf(TAG, "Device state was not initialized.");
+ return;
+ }
+
+ if (rotationLocked == isRotationLockedForCurrentState()) {
+ Log.v(TAG, "Rotation lock same as the current setting, no need to update.");
+ return;
+ }
+
+ saveNewRotationLockSetting(rotationLocked);
+ }
+
+ private void saveNewRotationLockSetting(boolean isRotationLocked) {
+ Log.v(TAG, "saveNewRotationLockSetting [state=" + mDeviceState + "] [isRotationLocked="
+ + isRotationLocked + "]");
+
+ mDeviceStateRotationLockSettings.put(mDeviceState,
+ isRotationLocked
+ ? DEVICE_STATE_ROTATION_LOCK_LOCKED
+ : DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
+ persistSettings();
+ }
+
+ private boolean isRotationLockedForCurrentState() {
+ return mDeviceStateRotationLockSettings.get(mDeviceState,
+ DEVICE_STATE_ROTATION_LOCK_IGNORED) == DEVICE_STATE_ROTATION_LOCK_LOCKED;
+ }
+
+ private void updateDeviceState(int state) {
+ Log.v(TAG, "updateDeviceState [state=" + state + "]");
+ if (mDeviceState == state) {
+ return;
+ }
+
+ int rotationLockSetting =
+ mDeviceStateRotationLockSettings.get(state, DEVICE_STATE_ROTATION_LOCK_IGNORED);
+ if (rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_IGNORED) {
+ // We won't handle this device state. The same rotation lock setting as before should
+ // apply and any changes to the rotation lock setting will be written for the previous
+ // valid device state.
+ Log.v(TAG, "Ignoring new device state: " + state);
+ return;
+ }
+
+ // Accept the new state
+ mDeviceState = state;
+
+ // Update the rotation lock setting if needed for this new device state
+ boolean newRotationLockSetting = rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_LOCKED;
+ if (newRotationLockSetting != mRotationPolicyWrapper.isRotationLocked()) {
+ mRotationPolicyWrapper.setRotationLock(newRotationLockSetting);
+ }
+ }
+
+ private void persistSettings() {
+ if (mDeviceStateRotationLockSettings.size() == 0) {
+ mSecureSettings.putStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ /* value= */"", UserHandle.USER_CURRENT);
+ return;
+ }
+
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append(mDeviceStateRotationLockSettings.keyAt(0))
+ .append(SEPARATOR_REGEX)
+ .append(mDeviceStateRotationLockSettings.valueAt(0));
+
+ for (int i = 1; i < mDeviceStateRotationLockSettings.size(); i++) {
+ stringBuilder
+ .append(SEPARATOR_REGEX)
+ .append(mDeviceStateRotationLockSettings.keyAt(i))
+ .append(SEPARATOR_REGEX)
+ .append(mDeviceStateRotationLockSettings.valueAt(i));
+ }
+ mSecureSettings.putStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ stringBuilder.toString(), UserHandle.USER_CURRENT);
+ }
+
+ private void loadDefaults() {
+ if (mDeviceStateRotationLockDefaults.length == 0) {
+ Log.w(TAG, "Empty default settings");
+ mDeviceStateRotationLockSettings = new SparseIntArray(/* initialCapacity= */0);
+ return;
+ }
+ mDeviceStateRotationLockSettings =
+ new SparseIntArray(mDeviceStateRotationLockDefaults.length);
+ for (String serializedDefault : mDeviceStateRotationLockDefaults) {
+ String[] entry = serializedDefault.split(SEPARATOR_REGEX);
+ try {
+ int key = Integer.parseInt(entry[0]);
+ int value = Integer.parseInt(entry[1]);
+ mDeviceStateRotationLockSettings.put(key, value);
+ } catch (NumberFormatException e) {
+ Log.wtf(TAG, "Error deserializing default settings", e);
+ }
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 43781f3941ba..3490e1567ea8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -57,7 +57,7 @@ import com.android.settingslib.mobile.MobileStatusTracker.SubscriptionDefaults;
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.net.SignalStrengthUtil;
import com.android.systemui.R;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index fa6111589bff..00ada4fbc23a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -70,8 +70,8 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.settings.CurrentUserTracker;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.util.CarrierConfigTracker;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
index 53d68d0ff0ac..67f5364e3d3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
@@ -16,36 +16,54 @@
package com.android.systemui.statusbar.policy;
-import android.content.Context;
+import static com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule.DEVICE_STATE_ROTATION_LOCK_DEFAULTS;
+
import android.os.UserHandle;
import androidx.annotation.NonNull;
-import com.android.internal.view.RotationPolicy;
+import com.android.internal.view.RotationPolicy.RotationPolicyListener;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.util.wrapper.RotationPolicyWrapper;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.inject.Inject;
+import javax.inject.Named;
/** Platform implementation of the rotation lock controller. **/
@SysUISingleton
public final class RotationLockControllerImpl implements RotationLockController {
- private final Context mContext;
private final CopyOnWriteArrayList<RotationLockControllerCallback> mCallbacks =
- new CopyOnWriteArrayList<RotationLockControllerCallback>();
+ new CopyOnWriteArrayList<>();
- private final RotationPolicy.RotationPolicyListener mRotationPolicyListener =
- new RotationPolicy.RotationPolicyListener() {
+ private final RotationPolicyListener mRotationPolicyListener =
+ new RotationPolicyListener() {
@Override
public void onChange() {
notifyChanged();
}
};
+ private final RotationPolicyWrapper mRotationPolicy;
+ private final DeviceStateRotationLockSettingController
+ mDeviceStateRotationLockSettingController;
+ private final boolean mIsPerDeviceStateRotationLockEnabled;
+
@Inject
- public RotationLockControllerImpl(Context context) {
- mContext = context;
+ public RotationLockControllerImpl(
+ RotationPolicyWrapper rotationPolicyWrapper,
+ DeviceStateRotationLockSettingController deviceStateRotationLockSettingController,
+ @Named(DEVICE_STATE_ROTATION_LOCK_DEFAULTS) String[] deviceStateRotationLockDefaults
+ ) {
+ mRotationPolicy = rotationPolicyWrapper;
+ mDeviceStateRotationLockSettingController = deviceStateRotationLockSettingController;
+ mIsPerDeviceStateRotationLockEnabled = deviceStateRotationLockDefaults.length > 0;
+ if (mIsPerDeviceStateRotationLockEnabled) {
+ deviceStateRotationLockSettingController.initialize();
+ mCallbacks.add(mDeviceStateRotationLockSettingController);
+ }
+
setListening(true);
}
@@ -61,32 +79,35 @@ public final class RotationLockControllerImpl implements RotationLockController
}
public int getRotationLockOrientation() {
- return RotationPolicy.getRotationLockOrientation(mContext);
+ return mRotationPolicy.getRotationLockOrientation();
}
public boolean isRotationLocked() {
- return RotationPolicy.isRotationLocked(mContext);
+ return mRotationPolicy.isRotationLocked();
}
public void setRotationLocked(boolean locked) {
- RotationPolicy.setRotationLock(mContext, locked);
+ mRotationPolicy.setRotationLock(locked);
}
public void setRotationLockedAtAngle(boolean locked, int rotation){
- RotationPolicy.setRotationLockAtAngle(mContext, locked, rotation);
+ mRotationPolicy.setRotationLockAtAngle(locked, rotation);
}
public boolean isRotationLockAffordanceVisible() {
- return RotationPolicy.isRotationLockToggleVisible(mContext);
+ return mRotationPolicy.isRotationLockToggleVisible();
}
@Override
public void setListening(boolean listening) {
if (listening) {
- RotationPolicy.registerRotationPolicyListener(mContext, mRotationPolicyListener,
+ mRotationPolicy.registerRotationPolicyListener(mRotationPolicyListener,
UserHandle.USER_ALL);
} else {
- RotationPolicy.unregisterRotationPolicyListener(mContext, mRotationPolicyListener);
+ mRotationPolicy.unregisterRotationPolicyListener(mRotationPolicyListener);
+ }
+ if (mIsPerDeviceStateRotationLockEnabled) {
+ mDeviceStateRotationLockSettingController.setListening(listening);
}
}
@@ -97,7 +118,7 @@ public final class RotationLockControllerImpl implements RotationLockController
}
private void notifyChanged(RotationLockControllerCallback callback) {
- callback.onRotationLockStateChanged(RotationPolicy.isRotationLocked(mContext),
- RotationPolicy.isRotationLockToggleVisible(mContext));
+ callback.onRotationLockStateChanged(mRotationPolicy.isRotationLocked(),
+ mRotationPolicy.isRotationLockToggleVisible());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 8f1a5782e779..251ecc626387 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -26,6 +26,7 @@ import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.IActivityTaskManager;
+import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
@@ -114,6 +115,8 @@ public class UserSwitcherController implements Dumpable {
@VisibleForTesting
final GuestResumeSessionReceiver mGuestResumeSessionReceiver;
private final KeyguardStateController mKeyguardStateController;
+ private final DeviceProvisionedController mDeviceProvisionedController;
+ private final DevicePolicyManager mDevicePolicyManager;
protected final Handler mHandler;
private final ActivityStarter mActivityStarter;
private final BroadcastDispatcher mBroadcastDispatcher;
@@ -149,6 +152,8 @@ public class UserSwitcherController implements Dumpable {
UserManager userManager,
UserTracker userTracker,
KeyguardStateController keyguardStateController,
+ DeviceProvisionedController deviceProvisionedController,
+ DevicePolicyManager devicePolicyManager,
@Main Handler handler,
ActivityStarter activityStarter,
BroadcastDispatcher broadcastDispatcher,
@@ -178,6 +183,8 @@ public class UserSwitcherController implements Dumpable {
mGuestIsResetting = new AtomicBoolean();
mGuestCreationScheduled = new AtomicBoolean();
mKeyguardStateController = keyguardStateController;
+ mDeviceProvisionedController = deviceProvisionedController;
+ mDevicePolicyManager = devicePolicyManager;
mHandler = handler;
mActivityStarter = activityStarter;
mUserManager = userManager;
@@ -336,8 +343,7 @@ public class UserSwitcherController implements Dumpable {
true /* isGuest */, false /* isCurrent */,
false /* isAddUser */, false /* isRestricted */,
isSwitchToGuestEnabled);
- // Don't call checkIfAddUserDisallowedByAdminOnly if
- // config_guestUserAutoCreated=true.
+ checkIfAddUserDisallowedByAdminOnly(guestRecord);
records.add(guestRecord);
} else if (canCreateGuest) {
guestRecord = new UserRecord(null /* info */, null /* picture */,
@@ -733,10 +739,27 @@ public class UserSwitcherController implements Dumpable {
}
/**
+ * Guarantee guest is present only if the device is provisioned. Otherwise, create a content
+ * observer to wait until the device is provisioned, then schedule the guest creation.
+ */
+ public void schedulePostBootGuestCreation() {
+ if (isDeviceAllowedToAddGuest()) {
+ guaranteeGuestPresent();
+ } else {
+ mDeviceProvisionedController.addCallback(mGuaranteeGuestPresentAfterProvisioned);
+ }
+ }
+
+ private boolean isDeviceAllowedToAddGuest() {
+ return mDeviceProvisionedController.isDeviceProvisioned()
+ && !mDevicePolicyManager.isDeviceManaged();
+ }
+
+ /**
* If there is no guest on the device, schedule creation of a new guest user in the background.
*/
- public void guaranteeGuestPresent() {
- if (mUserManager.findCurrentGuestUser() == null) {
+ private void guaranteeGuestPresent() {
+ if (isDeviceAllowedToAddGuest() && mUserManager.findCurrentGuestUser() == null) {
scheduleGuestCreation();
}
}
@@ -1056,6 +1079,21 @@ public class UserSwitcherController implements Dumpable {
}
};
+ private final DeviceProvisionedController.DeviceProvisionedListener
+ mGuaranteeGuestPresentAfterProvisioned =
+ new DeviceProvisionedController.DeviceProvisionedListener() {
+ @Override
+ public void onDeviceProvisionedChanged() {
+ if (isDeviceAllowedToAddGuest()) {
+ mBgExecutor.execute(
+ () -> mDeviceProvisionedController.removeCallback(
+ mGuaranteeGuestPresentAfterProvisioned));
+ guaranteeGuestPresent();
+ }
+ }
+ };
+
+
private final class ExitGuestDialog extends SystemUIDialog implements
DialogInterface.OnClickListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index f8e36476c4a6..fc19564bf554 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -36,7 +36,7 @@ import com.android.settingslib.graph.SignalDrawable;
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.wifi.WifiStatusTracker;
import com.android.systemui.R;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
index c224cf574528..1eec639670ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
@@ -16,8 +16,10 @@
package com.android.systemui.statusbar.policy.dagger;
+import android.content.res.Resources;
import android.os.UserManager;
+import com.android.internal.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.settings.UserTracker;
@@ -57,6 +59,8 @@ import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
import java.util.concurrent.Executor;
+import javax.inject.Named;
+
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
@@ -65,6 +69,9 @@ import dagger.Provides;
/** Dagger Module for code in the statusbar.policy package. */
@Module
public interface StatusBarPolicyModule {
+
+ String DEVICE_STATE_ROTATION_LOCK_DEFAULTS = "DEVICE_STATE_ROTATION_LOCK_DEFAULTS";
+
/** */
@Binds
BluetoothController provideBluetoothController(BluetoothControllerImpl controllerImpl);
@@ -154,4 +161,14 @@ public interface StatusBarPolicyModule {
controller.init();
return controller;
}
+
+ /**
+ * Default values for per-device state rotation lock settings.
+ */
+ @Provides
+ @Named(DEVICE_STATE_ROTATION_LOCK_DEFAULTS)
+ static String[] providesDeviceStateRotationLockDefaults(@Main Resources resources) {
+ return resources.getStringArray(
+ R.array.config_perDeviceStateRotationLockDefaults);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 81999b534046..c807ad828e30 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -57,9 +57,9 @@ 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.flags.FeatureFlags;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.util.settings.SecureSettings;
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index df889f2c2ca6..35251002fb7b 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -39,6 +39,7 @@ 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.EnhancedEstimatesImpl;
+import com.android.systemui.power.dagger.PowerModule;
import com.android.systemui.qs.dagger.QSModule;
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
import com.android.systemui.recents.Recents;
@@ -81,6 +82,7 @@ import dagger.Provides;
* overridden by the System UI implementation.
*/
@Module(includes = {
+ PowerModule.class,
QSModule.class
},
subcomponents = {
diff --git a/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java b/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java
index cdfa1457f4a5..981bf01164e3 100644
--- a/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/dagger/UtilModule.java
@@ -18,12 +18,15 @@ package com.android.systemui.util.dagger;
import com.android.systemui.util.RingerModeTracker;
import com.android.systemui.util.RingerModeTrackerImpl;
+import com.android.systemui.util.wrapper.UtilWrapperModule;
import dagger.Binds;
import dagger.Module;
/** Dagger Module for code in the util package. */
-@Module
+@Module(includes = {
+ UtilWrapperModule.class
+ })
public interface UtilModule {
/** */
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
index b38fc77fd131..90e022a52d7a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
@@ -290,15 +290,18 @@ public class ProximitySensor implements ThresholdSensor {
return;
}
- if (!mSecondaryThresholdSensor.isLoaded()) {
+
+ if (!mSecondaryThresholdSensor.isLoaded()) { // No secondary
logDebug("Primary sensor event: " + event.getBelow() + ". No secondary.");
onSensorEvent(event);
- } else if (event.getBelow()) {
+ } else if (event.getBelow()) { // Covered? Check secondary.
logDebug("Primary sensor event: " + event.getBelow() + ". Checking secondary.");
if (mCancelSecondaryRunnable != null) {
mCancelSecondaryRunnable.run();
}
mSecondaryThresholdSensor.resume();
+ } else { // Uncovered. Report immediately.
+ onSensorEvent(event);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt b/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
new file mode 100644
index 000000000000..2a0cc7ddacf5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.wrapper
+
+import android.content.Context
+import com.android.internal.view.RotationPolicy
+import com.android.internal.view.RotationPolicy.RotationPolicyListener
+import javax.inject.Inject
+
+/**
+ * Testable wrapper interface around RotationPolicy {link com.android.internal.view.RotationPolicy}
+ */
+interface RotationPolicyWrapper {
+ fun setRotationLock(enabled: Boolean)
+ fun setRotationLockAtAngle(enabled: Boolean, rotation: Int)
+ fun getRotationLockOrientation(): Int
+ fun isRotationLockToggleVisible(): Boolean
+ fun isRotationLocked(): Boolean
+ fun registerRotationPolicyListener(listener: RotationPolicyListener, userHandle: Int)
+ fun unregisterRotationPolicyListener(listener: RotationPolicyListener)
+}
+
+class RotationPolicyWrapperImpl @Inject constructor(private val context: Context) :
+ RotationPolicyWrapper {
+
+ override fun setRotationLock(enabled: Boolean) {
+ RotationPolicy.setRotationLock(context, enabled)
+ }
+
+ override fun setRotationLockAtAngle(enabled: Boolean, rotation: Int) {
+ RotationPolicy.setRotationLockAtAngle(context, enabled, rotation)
+ }
+
+ override fun getRotationLockOrientation(): Int =
+ RotationPolicy.getRotationLockOrientation(context)
+
+ override fun isRotationLockToggleVisible(): Boolean =
+ RotationPolicy.isRotationLockToggleVisible(context)
+
+ override fun isRotationLocked(): Boolean =
+ RotationPolicy.isRotationLocked(context)
+
+ override fun registerRotationPolicyListener(
+ listener: RotationPolicyListener,
+ userHandle: Int
+ ) {
+ RotationPolicy.registerRotationPolicyListener(context, listener, userHandle)
+ }
+
+ override fun unregisterRotationPolicyListener(listener: RotationPolicyListener) {
+ RotationPolicy.unregisterRotationPolicyListener(context, listener)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt b/packages/SystemUI/src/com/android/systemui/util/wrapper/UtilWrapperModule.kt
index 01e34d9f8f97..7e3aa277db33 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/wrapper/UtilWrapperModule.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,16 +14,16 @@
* limitations under the License.
*/
-package com.android.server.wm.flicker.launch
+package com.android.systemui.util.wrapper
-import android.platform.helpers.IAppHelper
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.HOME_WINDOW_TITLE
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
-fun FlickerTestParameter.appWindowReplacesLauncherAsTopWindow(testApp: IAppHelper) {
- assertWm {
- this.showsAppWindowOnTop(*HOME_WINDOW_TITLE)
- .then()
- .showsAppWindowOnTop("Snapshot", testApp.getPackage())
- }
-} \ No newline at end of file
+@Module
+abstract class UtilWrapperModule {
+
+ @Binds
+ @SysUISingleton
+ abstract fun bindRotationPolicyWrapper(impl: RotationPolicyWrapperImpl): RotationPolicyWrapper
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index f31762819d00..dbf115b62a58 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -2255,6 +2255,11 @@ public class VolumeDialogImpl implements VolumeDialog,
@Override
public void onClick(View view) {
+ // If the ringer drawer isn't open, don't let anything in it be clicked.
+ if (!mIsRingerDrawerOpen) {
+ return;
+ }
+
setRingerMode(mClickedRingerMode);
mRingerDrawerIconAnimatingSelected = getDrawerIconViewForMode(mClickedRingerMode);
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletCardCarousel.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletCardCarousel.java
index 1e1b459382d7..77fd2e830873 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletCardCarousel.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletCardCarousel.java
@@ -190,6 +190,15 @@ public class WalletCardCarousel extends RecyclerView {
}
/**
+ * Sets the adapter again in the RecyclerView, updating the ViewHolders children's layout.
+ * This is needed when changing the state of the device (eg fold/unfold) so the ViewHolders are
+ * recreated.
+ */
+ void resetAdapter() {
+ setAdapter(mWalletCardCarouselAdapter);
+ }
+
+ /**
* Returns true if the data set is changed.
*/
boolean setData(List<WalletCardViewInfo> data, int selectedIndex, boolean hasLockStateChanged) {
@@ -376,8 +385,8 @@ public class WalletCardCarousel extends RecyclerView {
CardView cardView = viewHolder.mCardView;
cardView.setRadius(mCornerRadiusPx);
ViewGroup.LayoutParams layoutParams = cardView.getLayoutParams();
- layoutParams.width = mCardWidthPx;
- layoutParams.height = mCardHeightPx;
+ layoutParams.width = getCardWidthPx();
+ layoutParams.height = getCardHeightPx();
view.setTag(viewHolder);
return viewHolder;
}
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
index 420f84abe0dd..9b2702ff7bf2 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
@@ -99,17 +99,13 @@ public class WalletView extends FrameLayout implements WalletCardCarousel.OnCard
mCardCarousel.setExpectedViewWidth(getWidth());
}
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- updateViewForOrientation(newConfig.orientation);
- }
-
private void updateViewForOrientation(@Configuration.Orientation int orientation) {
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
renderViewPortrait();
} else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
renderViewLandscape();
}
+ mCardCarousel.resetAdapter(); // necessary to update cards width
ViewGroup.LayoutParams params = mCardCarouselContainer.getLayoutParams();
if (params instanceof MarginLayoutParams) {
((MarginLayoutParams) params).topMargin =
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index fe166d7b3738..d3581a9fd177 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -60,10 +60,10 @@ import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.notification.NotificationChannelHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 7e733a9721ef..7e3553a63958 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -55,6 +55,7 @@ import com.android.wm.shell.common.annotations.ShellAnimationThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
import com.android.wm.shell.draganddrop.DragAndDropController;
+import com.android.wm.shell.freeform.FreeformTaskListener;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
@@ -213,6 +214,13 @@ public abstract class WMShellBaseModule {
}
//
+ // Freeform (optional feature)
+ //
+
+ @BindsOptionalOf
+ abstract Optional<FreeformTaskListener> optionalFreeformTaskListener();
+
+ //
// Hide display cutout
//
@@ -328,9 +336,11 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
static Transitions provideTransitions(ShellTaskOrganizer organizer, TransactionPool pool,
- Context context, @ShellMainThread ShellExecutor mainExecutor,
+ DisplayController displayController, Context context,
+ @ShellMainThread ShellExecutor mainExecutor,
@ShellAnimationThread ShellExecutor animExecutor) {
- return new Transitions(organizer, pool, context, mainExecutor, animExecutor);
+ return new Transitions(organizer, pool, displayController, context, mainExecutor,
+ animExecutor);
}
//
@@ -451,6 +461,7 @@ public abstract class WMShellBaseModule {
Optional<AppPairsController> appPairsOptional,
Optional<PipTouchHandler> pipTouchHandlerOptional,
FullscreenTaskListener fullscreenTaskListener,
+ Optional<Optional<FreeformTaskListener>> freeformTaskListener,
Transitions transitions,
StartingWindowController startingWindow,
@ShellMainThread ShellExecutor mainExecutor) {
@@ -463,6 +474,7 @@ public abstract class WMShellBaseModule {
appPairsOptional,
pipTouchHandlerOptional,
fullscreenTaskListener,
+ freeformTaskListener,
transitions,
startingWindow,
mainExecutor);
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index be7813e19b11..6397ce680a82 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -36,6 +36,7 @@ import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ChoreographerSfVsync;
import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.freeform.FreeformTaskListener;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.Pip;
@@ -89,6 +90,18 @@ public class WMShellModule {
}
//
+ // Freeform
+ //
+
+ @WMSingleton
+ @Provides
+ static Optional<FreeformTaskListener> provideFreeformTaskListener(
+ Context context,
+ SyncTransactionQueue syncQueue) {
+ return Optional.ofNullable(FreeformTaskListener.create(context, syncQueue));
+ }
+
+ //
// Split/multiwindow
//
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 06b0bb25e01c..ce65733ad5e5 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -19,7 +19,6 @@ package com.android.keyguard;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -29,6 +28,7 @@ import static org.mockito.Mockito.when;
import android.content.res.Resources;
import android.testing.AndroidTestingRunner;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
@@ -104,6 +104,8 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
private AnimatableClockView mLargeClockView;
@Mock
private FrameLayout mLargeClockFrame;
+ @Mock
+ private ViewGroup mSmartspaceContainer;
private final View mFakeSmartspaceView = new View(mContext);
@@ -123,6 +125,8 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
when(mView.findViewById(R.id.animatable_clock_view)).thenReturn(mClockView);
when(mView.findViewById(R.id.animatable_clock_view_large)).thenReturn(mLargeClockView);
when(mView.findViewById(R.id.lockscreen_clock_view_large)).thenReturn(mLargeClockFrame);
+ when(mView.findViewById(R.id.keyguard_smartspace_container))
+ .thenReturn(mSmartspaceContainer);
when(mClockView.getContext()).thenReturn(getContext());
when(mLargeClockView.getContext()).thenReturn(getContext());
@@ -210,7 +214,7 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
@Test
public void testSmartspaceEnabledRemovesKeyguardStatusArea() {
- when(mSmartspaceController.isEnabled()).thenReturn(true);
+ when(mSmartspaceController.isSmartspaceEnabled()).thenReturn(true);
when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
mController.init();
@@ -219,7 +223,7 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
@Test
public void testSmartspaceDisabledShowsKeyguardStatusArea() {
- when(mSmartspaceController.isEnabled()).thenReturn(false);
+ when(mSmartspaceController.isSmartspaceEnabled()).thenReturn(false);
mController.init();
assertEquals(View.VISIBLE, mStatusArea.getVisibility());
@@ -227,17 +231,16 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
@Test
public void testDetachRemovesSmartspaceView() {
- when(mSmartspaceController.isEnabled()).thenReturn(true);
+ when(mSmartspaceController.isSmartspaceEnabled()).thenReturn(true);
when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
mController.init();
- verify(mView).addView(eq(mFakeSmartspaceView), anyInt(), any());
ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor =
ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture());
listenerArgumentCaptor.getValue().onViewDetachedFromWindow(mView);
- verify(mView).removeView(mFakeSmartspaceView);
+ verify(mSmartspaceContainer).removeAllViews();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
index bb71bed84f43..8e1e42a9c9a2 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
@@ -26,6 +26,7 @@ import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.classifier.FalsingCollectorFake
+import com.android.systemui.statusbar.policy.DevicePostureController
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -62,6 +63,8 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() {
private lateinit var mKeyguardMessageAreaController: KeyguardMessageAreaController
@Mock
private lateinit var mLockPatternView: LockPatternView
+ @Mock
+ private lateinit var mPostureController: DevicePostureController
private lateinit var mKeyguardPatternViewController: KeyguardPatternViewController
@@ -78,7 +81,7 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() {
mKeyguardPatternViewController = KeyguardPatternViewController(mKeyguardPatternView,
mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
mLatencyTracker, mFalsingCollector, mEmergencyButtonController,
- mKeyguardMessageAreaControllerFactory)
+ mKeyguardMessageAreaControllerFactory, mPostureController)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index ec4dfba87af0..d3557d4b1809 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -86,8 +86,8 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.telephony.TelephonyListenerManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
index 14f112b8b071..cc35a8f9e1b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
@@ -196,7 +196,7 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {
return RemoteAnimationTarget(
0, RemoteAnimationTarget.MODE_OPENING, SurfaceControl(), false, Rect(), Rect(), 0,
Point(), Rect(), bounds, WindowConfiguration(), false, SurfaceControl(), Rect(),
- taskInfo
+ taskInfo, false
)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java
new file mode 100644
index 000000000000..b1d7d0c505a7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.battery;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.tuner.TunerService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+public class BatteryMeterViewControllerTest extends SysuiTestCase {
+ @Mock
+ private BatteryMeterView mBatteryMeterView;
+
+ @Mock
+ private ConfigurationController mConfigurationController;
+ @Mock
+ private TunerService mTunerService;
+
+ private BatteryMeterViewController mController;
+
+ @Before
+ public void setup() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ when(mBatteryMeterView.getContext()).thenReturn(mContext);
+ when(mBatteryMeterView.getResources()).thenReturn(mContext.getResources());
+
+ mController = new BatteryMeterViewController(
+ mBatteryMeterView,
+ mConfigurationController,
+ mTunerService
+ );
+ }
+
+ @Test
+ public void onViewAttached_callbacksRegistered() {
+ mController.onViewAttached();
+
+ verify(mConfigurationController).addCallback(any());
+ verify(mTunerService).addTunable(any(), any());
+ }
+
+ @Test
+ public void onViewDetached_callbacksUnregistered() {
+ // Set everything up first.
+ mController.onViewAttached();
+
+ mController.onViewDetached();
+
+ verify(mConfigurationController).removeCallback(any());
+ verify(mTunerService).removeTunable(any());
+ }
+
+ @Test
+ public void ignoreTunerUpdates_afterOnViewAttached_callbackUnregistered() {
+ // Start out receiving tuner updates
+ mController.onViewAttached();
+
+ mController.ignoreTunerUpdates();
+
+ verify(mTunerService).removeTunable(any());
+ }
+
+ @Test
+ public void ignoreTunerUpdates_beforeOnViewAttached_callbackNeverRegistered() {
+ mController.ignoreTunerUpdates();
+
+ mController.onViewAttached();
+
+ verify(mTunerService, never()).addTunable(any(), any());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
index 5cd781085b15..f91c02938845 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
@@ -23,7 +23,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
@@ -50,7 +49,6 @@ import com.android.systemui.SysuiTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -78,14 +76,16 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
@Mock private TextView mIndicatorView;
@Mock private ImageView mIconView;
@Mock private View mIconHolderView;
- @Mock private AuthBiometricFaceView.IconController mIconController;
+ @Mock private AuthBiometricFaceView.IconController mFaceIconController;
+ @Mock private AuthBiometricFaceToFingerprintView.UdfpsIconController mUdfpsIconController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mFaceToFpView = new TestableView(mContext);
- mFaceToFpView.mIconController = mIconController;
+ mFaceToFpView.mFaceIconController = mFaceIconController;
+ mFaceToFpView.mUdfpsIconController = mUdfpsIconController;
mFaceToFpView.setCallback(mCallback);
mFaceToFpView.mNegativeButton = mNegativeButton;
@@ -99,20 +99,23 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
@Test
public void testStateUpdated_whenDialogAnimatedIn() {
mFaceToFpView.onDialogAnimatedIn();
- verify(mFaceToFpView.mIconController)
+ verify(mFaceToFpView.mFaceIconController)
.updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
+ verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt());
}
@Test
public void testIconUpdatesState_whenDialogStateUpdated() {
mFaceToFpView.onDialogAnimatedIn();
- verify(mFaceToFpView.mIconController)
+ verify(mFaceToFpView.mFaceIconController)
.updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
+ verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt());
mFaceToFpView.updateState(AuthBiometricFaceView.STATE_AUTHENTICATED);
- verify(mFaceToFpView.mIconController).updateState(
+ verify(mFaceToFpView.mFaceIconController).updateState(
eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING),
eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATED));
+ verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt());
assertEquals(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATED, mFaceToFpView.mState);
}
@@ -120,21 +123,20 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
@Test
public void testStateUpdated_whenSwitchToFingerprint() {
mFaceToFpView.onDialogAnimatedIn();
- verify(mFaceToFpView.mIconController)
+ verify(mFaceToFpView.mFaceIconController)
.updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_ERROR);
+
+ verify(mFaceToFpView.mFaceIconController).deactivate();
+ verify(mFaceToFpView.mUdfpsIconController).updateState(
+ eq(AuthBiometricFaceToFingerprintView.STATE_IDLE));
+ verify(mConfirmButton).setVisibility(eq(View.GONE));
+
mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING);
- InOrder order = inOrder(mFaceToFpView.mIconController);
- order.verify(mFaceToFpView.mIconController).updateState(
- eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING),
- eq(AuthBiometricFaceToFingerprintView.STATE_ERROR));
- order.verify(mFaceToFpView.mIconController).updateState(
- eq(AuthBiometricFaceToFingerprintView.STATE_ERROR),
+ verify(mFaceToFpView.mUdfpsIconController).updateState(
eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
-
- verify(mConfirmButton).setVisibility(eq(View.GONE));
}
@Test
@@ -172,7 +174,10 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
eq(mContext.getString(R.string.fingerprint_dialog_use_fingerprint_instead)));
verify(mCallback).onAction(
eq(AuthBiometricView.Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR));
- assertEquals(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING, mFaceToFpView.mState);
+
+ // First we enter the error state, since we need to show the error animation/text. The
+ // error state is later cleared based on a timer, and we enter STATE_AUTHENTICATING.
+ assertEquals(AuthBiometricFaceToFingerprintView.STATE_ERROR, mFaceToFpView.mState);
}
@Test
@@ -185,13 +190,16 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
eq(mContext.getString(R.string.fingerprint_dialog_use_fingerprint_instead)));
verify(mCallback).onAction(
eq(AuthBiometricView.Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR));
- assertEquals(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING, mFaceToFpView.mState);
+
+ // First we enter the error state, since we need to show the error animation/text. The
+ // error state is later cleared based on a timer, and we enter STATE_AUTHENTICATING.
+ assertEquals(AuthBiometricFaceToFingerprintView.STATE_ERROR, mFaceToFpView.mState);
}
@Test
public void testFingerprintOnlyStartsOnFirstError() {
mFaceToFpView.onDialogAnimatedIn();
- verify(mFaceToFpView.mIconController)
+ verify(mFaceToFpView.mFaceIconController)
.updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
mFaceToFpView.onDialogAnimatedIn();
@@ -260,11 +268,6 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
protected int getDelayAfterAuthenticatedDurationMs() {
return 0;
}
-
- @Override
- protected IconController createUdfpsIconController() {
- return AuthBiometricFaceToFingerprintViewTest.this.mIconController;
- }
}
private class MockInjector extends AuthBiometricView.Injector {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java
index 043bd5cd6ba5..b93381d2b5c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java
@@ -62,7 +62,7 @@ public class AuthBiometricFaceViewTest extends SysuiTestCase {
public void setup() {
MockitoAnnotations.initMocks(this);
mFaceView = new TestableFaceView(mContext);
- mFaceView.mIconController = mock(TestableFaceView.TestableIconController.class);
+ mFaceView.mFaceIconController = mock(TestableFaceView.TestableIconController.class);
mFaceView.setCallback(mCallback);
mFaceView.mNegativeButton = mNegativeButton;
@@ -78,18 +78,18 @@ public class AuthBiometricFaceViewTest extends SysuiTestCase {
@Test
public void testStateUpdated_whenDialogAnimatedIn() {
mFaceView.onDialogAnimatedIn();
- verify(mFaceView.mIconController)
+ verify(mFaceView.mFaceIconController)
.updateState(anyInt(), eq(AuthBiometricFaceView.STATE_AUTHENTICATING));
}
@Test
public void testIconUpdatesState_whenDialogStateUpdated() {
mFaceView.updateState(AuthBiometricFaceView.STATE_AUTHENTICATING);
- verify(mFaceView.mIconController)
+ verify(mFaceView.mFaceIconController)
.updateState(anyInt(), eq(AuthBiometricFaceView.STATE_AUTHENTICATING));
mFaceView.updateState(AuthBiometricFaceView.STATE_AUTHENTICATED);
- verify(mFaceView.mIconController).updateState(
+ verify(mFaceView.mFaceIconController).updateState(
eq(AuthBiometricFaceView.STATE_AUTHENTICATING),
eq(AuthBiometricFaceView.STATE_AUTHENTICATED));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java
index 223714cfda30..7bc5f86510a1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java
@@ -32,6 +32,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.util.wrapper.BuildInfo;
import org.junit.Before;
@@ -43,6 +44,7 @@ import org.mockito.MockitoAnnotations;
public class FeatureFlagReaderTest extends SysuiTestCase {
@Mock private Resources mResources;
@Mock private BuildInfo mBuildInfo;
+ @Mock private PluginManager mPluginManager;
@Mock private SystemPropertiesHelper mSystemPropertiesHelper;
private FeatureFlagReader mReader;
@@ -63,7 +65,8 @@ public class FeatureFlagReaderTest extends SysuiTestCase {
private void initialize(boolean isDebuggable, boolean isOverrideable) {
when(mBuildInfo.isDebuggable()).thenReturn(isDebuggable);
when(mResources.getBoolean(R.bool.are_flags_overrideable)).thenReturn(isOverrideable);
- mReader = new FeatureFlagReader(mResources, mBuildInfo, mSystemPropertiesHelper);
+ mReader = new FeatureFlagReader(
+ mResources, mBuildInfo, mPluginManager, mSystemPropertiesHelper);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsTest.java b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsTest.java
new file mode 100644
index 000000000000..1a961787ee79
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.flags;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.FlagReaderPlugin;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+public class FeatureFlagsTest extends SysuiTestCase {
+
+ @Mock FeatureFlagReader mFeatureFlagReader;
+
+ private FeatureFlags mFeatureFlags;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ mFeatureFlags = new FeatureFlags(mFeatureFlagReader, getContext());
+ }
+
+ @Test
+ public void testAddListener() {
+ Flag<?> flag = new BooleanFlag(1);
+ mFeatureFlags.addFlag(flag);
+
+ // Assert and capture that a plugin listener was added.
+ ArgumentCaptor<FlagReaderPlugin.Listener> pluginListenerCaptor =
+ ArgumentCaptor.forClass(FlagReaderPlugin.Listener.class);
+
+ verify(mFeatureFlagReader).addListener(pluginListenerCaptor.capture());
+ FlagReaderPlugin.Listener pluginListener = pluginListenerCaptor.getValue();
+
+ // Signal a change. No listeners, so no real effect.
+ pluginListener.onFlagChanged(flag.getId());
+
+ // Add a listener for the flag
+ final Flag<?>[] changedFlag = {null};
+ FeatureFlags.Listener listener = f -> changedFlag[0] = f;
+ mFeatureFlags.addFlagListener(flag, listener);
+
+ // No changes seen yet.
+ assertThat(changedFlag[0]).isNull();
+
+ // Signal a change.
+ pluginListener.onFlagChanged(flag.getId());
+
+ // Assert that the change was for the correct flag.
+ assertThat(changedFlag[0]).isEqualTo(flag);
+ }
+
+ @Test
+ public void testRemoveListener() {
+ Flag<?> flag = new BooleanFlag(1);
+ mFeatureFlags.addFlag(flag);
+
+ // Assert and capture that a plugin listener was added.
+ ArgumentCaptor<FlagReaderPlugin.Listener> pluginListenerCaptor =
+ ArgumentCaptor.forClass(FlagReaderPlugin.Listener.class);
+
+ verify(mFeatureFlagReader).addListener(pluginListenerCaptor.capture());
+ FlagReaderPlugin.Listener pluginListener = pluginListenerCaptor.getValue();
+
+ // Add a listener for the flag
+ final Flag<?>[] changedFlag = {null};
+ FeatureFlags.Listener listener = f -> changedFlag[0] = f;
+ mFeatureFlags.addFlagListener(flag, listener);
+
+ // Signal a change.
+ pluginListener.onFlagChanged(flag.getId());
+
+ // Assert that the change was for the correct flag.
+ assertThat(changedFlag[0]).isEqualTo(flag);
+
+ changedFlag[0] = null;
+
+ // Now remove the listener.
+ mFeatureFlags.removeFlagListener(flag, listener);
+ // Signal a change.
+ pluginListener.onFlagChanged(flag.getId());
+ // Assert that the change was not triggered
+ assertThat(changedFlag[0]).isNull();
+
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagsTest.java b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagsTest.java
new file mode 100644
index 000000000000..25c302885e07
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagsTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.flags;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.util.Pair;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Test;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@SmallTest
+public class FlagsTest extends SysuiTestCase {
+
+ @Test
+ public void testDuplicateFlagIdCheckWorks() {
+ List<Pair<String, Flag<?>>> flags = collectFlags(DuplicateFlagContainer.class);
+ Map<Integer, List<String>> duplicates = groupDuplicateFlags(flags);
+
+ assertWithMessage(generateAssertionMessage(duplicates))
+ .that(duplicates.size()).isEqualTo(2);
+ }
+
+ @Test
+ public void testNoDuplicateFlagIds() {
+ List<Pair<String, Flag<?>>> flags = collectFlags(Flags.class);
+ Map<Integer, List<String>> duplicates = groupDuplicateFlags(flags);
+
+ assertWithMessage(generateAssertionMessage(duplicates))
+ .that(duplicates.size()).isEqualTo(0);
+ }
+
+ private String generateAssertionMessage(Map<Integer, List<String>> duplicates) {
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("Duplicate flag keys found: {");
+ for (int id : duplicates.keySet()) {
+ stringBuilder
+ .append(" ")
+ .append(id)
+ .append(": [")
+ .append(String.join(", ", duplicates.get(id)))
+ .append("]");
+ }
+ stringBuilder.append(" }");
+
+ return stringBuilder.toString();
+ }
+
+ private List<Pair<String, Flag<?>>> collectFlags(Class<?> clz) {
+ List<Pair<String, Flag<?>>> flags = new ArrayList<>();
+
+ Field[] fields = clz.getFields();
+
+ for (Field field : fields) {
+ Class<?> t = field.getType();
+ if (Flag.class.isAssignableFrom(t)) {
+ try {
+ flags.add(Pair.create(field.getName(), (Flag<?>) field.get(null)));
+ } catch (IllegalAccessException e) {
+ // no-op
+ }
+ }
+ }
+
+ return flags;
+ }
+
+ private Map<Integer, List<String>> groupDuplicateFlags(List<Pair<String, Flag<?>>> flags) {
+ Map<Integer, List<String>> grouping = new HashMap<>();
+
+ for (Pair<String, Flag<?>> flag : flags) {
+ grouping.putIfAbsent(flag.second.getId(), new ArrayList<>());
+ grouping.get(flag.second.getId()).add(flag.first);
+ }
+
+ Map<Integer, List<String>> result = new HashMap<>();
+ for (Integer id : grouping.keySet()) {
+ if (grouping.get(id).size() > 1) {
+ result.put(id, grouping.get(id));
+ }
+ }
+
+ return result;
+ }
+
+ private static class DuplicateFlagContainer {
+ public static final BooleanFlag A_FLAG = new BooleanFlag(0);
+ public static final BooleanFlag B_FLAG = new BooleanFlag(0);
+ public static final StringFlag C_FLAG = new StringFlag(0);
+
+ public static final BooleanFlag D_FLAG = new BooleanFlag(1);
+
+ public static final DoubleFlag E_FLAG = new DoubleFlag(3);
+ public static final DoubleFlag F_FLAG = new DoubleFlag(3);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index ad0878031679..31d70f5c811f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -67,7 +67,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@TestableLooper.RunWithLooper
@SmallTest
public class KeyguardViewMediatorTest extends SysuiTestCase {
private KeyguardViewMediator mViewMediator;
@@ -126,7 +126,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
mUnlockedScreenOffAnimationController,
() -> mNotificationShadeDepthController);
mViewMediator.start();
- mViewMediator.onSystemReady();
}
@Test
@@ -165,8 +164,10 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
}
@Test
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
public void restoreBouncerWhenSimLockedAndKeyguardIsGoingAway() {
// When showing and provisioned
+ mViewMediator.onSystemReady();
when(mUpdateMonitor.isDeviceProvisioned()).thenReturn(true);
mViewMediator.setShowingLocked(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
index 79b0dd0eda71..8e1b13c55d97 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
@@ -69,7 +69,7 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
whenever(notificationLockscreenUserManager.shouldShowLockscreenNotifications())
.thenReturn(true)
whenever(mediaHost.hostView).thenReturn(hostView)
-
+ hostView.layoutParams = FrameLayout.LayoutParams(100, 100)
keyguardMediaController = KeyguardMediaController(
mediaHost,
bypassController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
index 8fd2a329a33e..3ea57be98be0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
@@ -142,6 +142,8 @@ public class NavigationBarControllerTest extends SysuiTestCase {
@Test
public void testCreateNavigationBarsIncludeDefaultTrue() {
+ // Tablets may be using taskbar and the logic is different
+ mNavigationBarController.mIsTablet = false;
doNothing().when(mNavigationBarController).createNavigationBar(any(), any(), any());
mNavigationBarController.createNavigationBars(true, null);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterActionsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterActionsControllerTest.kt
new file mode 100644
index 000000000000..9378b2be2945
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterActionsControllerTest.kt
@@ -0,0 +1,91 @@
+package com.android.systemui.qs
+
+import com.android.systemui.R
+import android.os.UserManager
+import android.view.LayoutInflater
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.MetricsLogger
+import com.android.internal.logging.UiEventLogger
+import com.android.internal.logging.testing.FakeMetricsLogger
+import com.android.systemui.Dependency
+import com.android.systemui.classifier.FalsingManagerFake
+import com.android.systemui.globalactions.GlobalActionsDialogLite
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.statusbar.phone.MultiUserSwitchController
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.UserInfoController
+import com.android.systemui.tuner.TunerService
+import com.android.systemui.utils.leaks.FakeTunerService
+import com.android.systemui.utils.leaks.LeakCheckedTest
+import org.junit.Before
+import org.junit.Test
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+class QSFooterActionsControllerTest : LeakCheckedTest() {
+ @Mock
+ private lateinit var userManager: UserManager
+ @Mock
+ private lateinit var activityStarter: ActivityStarter
+ @Mock
+ private lateinit var deviceProvisionedController: DeviceProvisionedController
+ @Mock
+ private lateinit var userInfoController: UserInfoController
+ @Mock
+ private lateinit var qsPanelController: QSPanelController
+ @Mock
+ private lateinit var multiUserSwitchController: MultiUserSwitchController
+ @Mock
+ private lateinit var globalActionsDialog: GlobalActionsDialogLite
+ @Mock
+ private lateinit var uiEventLogger: UiEventLogger
+ @Mock
+ private lateinit var controller: QSFooterActionsController
+
+ private val metricsLogger: MetricsLogger = FakeMetricsLogger()
+ private lateinit var view: QSFooterActionsView
+ private val falsingManager: FalsingManagerFake = FalsingManagerFake()
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ injectLeakCheckedDependencies(*LeakCheckedTest.ALL_SUPPORTED_CLASSES)
+ val fakeTunerService = Dependency.get(TunerService::class.java) as FakeTunerService
+
+ view = LayoutInflater.from(context)
+ .inflate(R.layout.qs_footer_actions, null) as QSFooterActionsView
+
+ controller = QSFooterActionsController(view, qsPanelController, activityStarter,
+ userManager, userInfoController, multiUserSwitchController,
+ deviceProvisionedController, falsingManager, metricsLogger, fakeTunerService,
+ globalActionsDialog, uiEventLogger, showPMLiteButton = true)
+ controller.init()
+ controller.onViewAttached()
+ }
+
+ @Test
+ fun testLogPowerMenuClick() {
+ controller.expanded = true
+ falsingManager.setFalseTap(false)
+
+ view.findViewById<View>(R.id.pm_lite).performClick()
+ // Verify clicks are logged
+ verify(uiEventLogger, Mockito.times(1))
+ .log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS)
+ }
+
+ @Test
+ fun testSettings_UserNotSetup() {
+ whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(false)
+ view.findViewById<View>(R.id.settings_button).performClick()
+ // Verify Settings wasn't launched.
+ verify<ActivityStarter>(activityStarter, Mockito.never()).startActivity(any(), anyBoolean())
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
index 6f7bf3b09daa..8c6c358385ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
@@ -18,16 +18,11 @@ package com.android.systemui.qs;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ClipData;
import android.content.ClipboardManager;
-import android.os.UserManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
@@ -35,21 +30,8 @@ import android.widget.TextView;
import androidx.test.filters.SmallTest;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.testing.FakeMetricsLogger;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.classifier.FalsingManagerFake;
-import com.android.systemui.globalactions.GlobalActionsDialogLite;
-import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.phone.MultiUserSwitchController;
-import com.android.systemui.statusbar.phone.SettingsButton;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.UserInfoController;
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.utils.leaks.FakeTunerService;
import com.android.systemui.utils.leaks.LeakCheckedTest;
import org.junit.Before;
@@ -67,14 +49,6 @@ public class QSFooterViewControllerTest extends LeakCheckedTest {
@Mock
private QSFooterView mView;
@Mock
- private UserManager mUserManager;
- @Mock
- private ActivityStarter mActivityStarter;
- @Mock
- private DeviceProvisionedController mDeviceProvisionedController;
- @Mock
- private UserInfoController mUserInfoController;
- @Mock
private UserTracker mUserTracker;
@Mock
private QSPanelController mQSPanelController;
@@ -82,36 +56,19 @@ public class QSFooterViewControllerTest extends LeakCheckedTest {
private ClipboardManager mClipboardManager;
@Mock
private QuickQSPanelController mQuickQSPanelController;
- private FakeTunerService mFakeTunerService;
- private MetricsLogger mMetricsLogger = new FakeMetricsLogger();
- private FalsingManagerFake mFalsingManager;
-
- @Mock
- private SettingsButton mSettingsButton;
@Mock
private TextView mBuildText;
@Mock
- private View mEdit;
- @Mock
- private MultiUserSwitchController mMultiUserSwitchController;
- @Mock
- private View mPowerMenuLiteView;
- @Mock
- private GlobalActionsDialogLite mGlobalActionsDialog;
- @Mock
- private UiEventLogger mUiEventLogger;
+ private QSFooterActionsController mQSFooterActionsController;
private QSFooterViewController mController;
@Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
- mFalsingManager = new FalsingManagerFake();
injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
- mFakeTunerService = (FakeTunerService) Dependency.get(TunerService.class);
-
mContext.addMockSystemService(ClipboardManager.class, mClipboardManager);
when(mView.getContext()).thenReturn(mContext);
@@ -119,16 +76,10 @@ public class QSFooterViewControllerTest extends LeakCheckedTest {
when(mUserTracker.getUserContext()).thenReturn(mContext);
when(mView.isAttachedToWindow()).thenReturn(true);
- when(mView.findViewById(R.id.settings_button)).thenReturn(mSettingsButton);
when(mView.findViewById(R.id.build)).thenReturn(mBuildText);
- when(mView.findViewById(android.R.id.edit)).thenReturn(mEdit);
- when(mView.findViewById(R.id.pm_lite)).thenReturn(mPowerMenuLiteView);
- mController = new QSFooterViewController(mView, mUserManager, mUserInfoController,
- mActivityStarter, mDeviceProvisionedController, mUserTracker, mQSPanelController,
- mMultiUserSwitchController, mQuickQSPanelController, mFakeTunerService,
- mMetricsLogger, mFalsingManager, false, mGlobalActionsDialog,
- mUiEventLogger);
+ mController = new QSFooterViewController(mView, mUserTracker, mQSPanelController,
+ mQuickQSPanelController, mQSFooterActionsController);
mController.init();
}
@@ -148,40 +99,4 @@ public class QSFooterViewControllerTest extends LeakCheckedTest {
verify(mClipboardManager).setPrimaryClip(captor.capture());
assertThat(captor.getValue().getItemAt(0).getText()).isEqualTo(text);
}
-
- @Test
- public void testSettings_UserNotSetup() {
- ArgumentCaptor<View.OnClickListener> onClickCaptor =
- ArgumentCaptor.forClass(View.OnClickListener.class);
- verify(mSettingsButton).setOnClickListener(onClickCaptor.capture());
-
- when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(false);
-
- onClickCaptor.getValue().onClick(mSettingsButton);
- // Verify Settings wasn't launched.
- verify(mActivityStarter, never()).startActivity(any(), anyBoolean());
- }
-
- @Test
- public void testLogPowerMenuClick() {
- // Enable power menu button
- mController = new QSFooterViewController(mView, mUserManager, mUserInfoController,
- mActivityStarter, mDeviceProvisionedController, mUserTracker, mQSPanelController,
- mMultiUserSwitchController, mQuickQSPanelController, mFakeTunerService,
- mMetricsLogger, new FalsingManagerFake(), true, mGlobalActionsDialog,
- mUiEventLogger);
- mController.init();
- mController.setExpanded(true);
- mFalsingManager.setFalseTap(false);
-
- ArgumentCaptor<View.OnClickListener> onClickCaptor =
- ArgumentCaptor.forClass(View.OnClickListener.class);
- verify(mPowerMenuLiteView).setOnClickListener(onClickCaptor.capture());
-
- onClickCaptor.getValue().onClick(mPowerMenuLiteView);
-
- // Verify clicks are logged
- verify(mUiEventLogger, times(1))
- .log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS);
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelSwitchToParentTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelSwitchToParentTest.kt
new file mode 100644
index 000000000000..56f2905e834f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelSwitchToParentTest.kt
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs
+
+import com.google.common.truth.Truth.assertThat
+
+import androidx.test.filters.SmallTest
+
+import android.testing.AndroidTestingRunner
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.children
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class QSPanelSwitchToParentTest : SysuiTestCase() {
+
+ private lateinit var parent1: FrameLayout
+ private lateinit var parent2: FrameLayout
+
+ private lateinit var movingView: View
+
+ private lateinit var view1A: View
+ private lateinit var view1B: View
+ private lateinit var view1C: View
+
+ private lateinit var view2A: View
+ private lateinit var view2B: View
+ private lateinit var view2C: View
+
+ @Before
+ fun setUp() {
+ parent1 = FrameLayout(mContext)
+ parent2 = FrameLayout(mContext)
+
+ movingView = View(mContext)
+
+ view1A = View(mContext)
+ parent1.addView(view1A)
+ view1B = View(mContext)
+ parent1.addView(view1B)
+ view1C = View(mContext)
+ parent1.addView(view1C)
+
+ view2A = View(mContext)
+ parent2.addView(view2A)
+ view2B = View(mContext)
+ parent2.addView(view2B)
+ view2C = View(mContext)
+ parent2.addView(view2C)
+ }
+
+ @Test
+ fun testNullTargetNoInteractions() {
+ QSPanel.switchToParent(movingView, null, -1, "")
+
+ assertThat(movingView.parent).isNull()
+ }
+
+ @Test
+ fun testMoveToEndNoParent() {
+ QSPanel.switchToParent(movingView, parent2, -1, "")
+
+ assertThat(parent1.childrenList).containsExactly(
+ view1A, view1B, view1C
+ )
+
+ assertThat(parent2.childrenList).containsExactly(
+ view2A, view2B, view2C, movingView
+ )
+ }
+
+ @Test
+ fun testMoveToEndDifferentParent() {
+ parent1.addView(movingView, 0)
+
+ QSPanel.switchToParent(movingView, parent2, -1, "")
+
+ assertThat(parent1.childrenList).containsExactly(
+ view1A, view1B, view1C
+ )
+ assertThat(parent2.childrenList).containsExactly(
+ view2A, view2B, view2C, movingView
+ )
+ }
+
+ @Test
+ fun testMoveToEndSameParent() {
+ parent2.addView(movingView, 0)
+
+ QSPanel.switchToParent(movingView, parent2, -1, "")
+
+ assertThat(parent1.childrenList).containsExactly(
+ view1A, view1B, view1C
+ )
+ assertThat(parent2.childrenList).containsExactly(
+ view2A, view2B, view2C, movingView
+ )
+ }
+
+ @Test
+ fun testMoveToMiddleFromNoParent() {
+ QSPanel.switchToParent(movingView, parent2, 1, "")
+
+ assertThat(parent1.childrenList).containsExactly(
+ view1A, view1B, view1C
+ )
+ assertThat(parent2.childrenList).containsExactly(
+ view2A, movingView, view2B, view2C
+ )
+ }
+
+ @Test
+ fun testMoveToMiddleDifferentParent() {
+ parent1.addView(movingView, 1)
+
+ QSPanel.switchToParent(movingView, parent2, 2, "")
+
+ assertThat(parent1.childrenList).containsExactly(
+ view1A, view1B, view1C
+ )
+ assertThat(parent2.childrenList).containsExactly(
+ view2A, view2B, movingView, view2C
+ )
+ }
+
+ @Test
+ fun testMoveToMiddleSameParent() {
+ parent2.addView(movingView, 0)
+
+ QSPanel.switchToParent(movingView, parent2, 1, "")
+
+ assertThat(parent1.childrenList).containsExactly(
+ view1A, view1B, view1C
+ )
+ assertThat(parent2.childrenList).containsExactly(
+ view2A, movingView, view2B, view2C
+ )
+ }
+
+ private val ViewGroup.childrenList: List<View>
+ get() = children.toList()
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
index a83a5e1f5484..3500c183de39 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
@@ -69,6 +69,8 @@ class QSPanelTest : SysuiTestCase() {
@Mock
private lateinit var mQSTileView: QSTileView
+ private lateinit var mFooter: View
+
@Before
@Throws(Exception::class)
fun setup() {
@@ -81,7 +83,8 @@ class QSPanelTest : SysuiTestCase() {
mQsPanel = QSPanel(mContext, null)
mQsPanel.initialize()
// QSPanel inflates a footer inside of it, mocking it here
- mQsPanel.addView(LinearLayout(mContext).apply { id = R.id.qs_footer })
+ mFooter = LinearLayout(mContext).apply { id = R.id.qs_footer }
+ mQsPanel.addView(mFooter)
mQsPanel.onFinishInflate()
mQsPanel.setSecurityFooter(View(mContext), false)
mQsPanel.setHeaderContainer(LinearLayout(mContext))
@@ -125,7 +128,10 @@ class QSPanelTest : SysuiTestCase() {
mQsPanel.isExpanded = true
}
- assertThat(mQsPanel.indexOfChild(mQsPanel.mSecurityFooter)).isEqualTo(2)
+ // After mFooter
+ assertThat(mQsPanel.indexOfChild(mQsPanel.mSecurityFooter)).isEqualTo(
+ mQsPanel.indexOfChild(mFooter) + 1
+ )
}
@Test
@@ -137,7 +143,10 @@ class QSPanelTest : SysuiTestCase() {
mQsPanel.isExpanded = true
}
- assertThat(mQsPanel.indexOfChild(mQsPanel.mSecurityFooter)).isEqualTo(2)
+ // After mFooter
+ assertThat(mQsPanel.indexOfChild(mQsPanel.mSecurityFooter)).isEqualTo(
+ mQsPanel.indexOfChild(mFooter) + 1
+ )
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index f208b807f747..c9dc7ad6c5e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -44,7 +44,6 @@ import android.view.View;
import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
-import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.CollectionUtils;
@@ -53,6 +52,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QSFactory;
import com.android.systemui.plugins.qs.QSTile;
@@ -64,22 +64,18 @@ import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.settings.SecureSettings;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoSession;
-import org.mockito.quality.Strictness;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -133,16 +129,9 @@ public class QSTileHostTest extends SysuiTestCase {
private Handler mHandler;
private TestableLooper mLooper;
private QSTileHost mQSTileHost;
- MockitoSession mMockingSession = null;
@Before
public void setUp() {
- // TODO(b/174753536): Remove the mMockingSession when
- // FeatureFlagUtils.SETTINGS_PROVIDER_MODEL is removed.
- mMockingSession = ExtendedMockito.mockitoSession().strictness(Strictness.LENIENT)
- .mockStatic(FeatureFlags.class).startMocking();
- ExtendedMockito.doReturn(false)
- .when(() -> FeatureFlags.isProviderModelSettingEnabled(mContext));
MockitoAnnotations.initMocks(this);
mLooper = TestableLooper.get(this);
mHandler = new Handler(mLooper.getLooper());
@@ -156,13 +145,6 @@ public class QSTileHostTest extends SysuiTestCase {
.thenReturn("");
}
- @After
- public void tearDown() throws Exception {
- if (mMockingSession != null) {
- mMockingSession.finishMocking();
- }
- }
-
private void setUpTileFactory() {
when(mMockState.toString()).thenReturn(MOCK_STATE_STRING);
// Only create this kind of tiles
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
index 62ac72ecc2d2..66a006fd4fba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
@@ -27,7 +27,7 @@ import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.plugins.qs.QSTileView
import com.android.systemui.qs.customize.QSCustomizerController
import com.android.systemui.qs.logging.QSLogger
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
import org.junit.After
import org.junit.Before
import org.junit.Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
index 35360bd19393..b3e00f826db9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
@@ -23,8 +23,10 @@ import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.battery.BatteryMeterViewController
import com.android.systemui.colorextraction.SysuiColorExtractor
import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.privacy.OngoingPrivacyChip
import com.android.systemui.privacy.PrivacyDialogController
@@ -32,7 +34,6 @@ import com.android.systemui.privacy.PrivacyItemController
import com.android.systemui.privacy.logging.PrivacyLogger
import com.android.systemui.qs.carrier.QSCarrierGroup
import com.android.systemui.qs.carrier.QSCarrierGroupController
-import com.android.systemui.statusbar.FeatureFlags
import com.android.systemui.statusbar.phone.StatusBarIconController
import com.android.systemui.statusbar.phone.StatusIconContainer
import com.android.systemui.statusbar.policy.Clock
@@ -47,9 +48,9 @@ import org.junit.runner.RunWith
import org.mockito.Answers
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
@@ -87,6 +88,8 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
@Mock
private lateinit var privacyDialogController: PrivacyDialogController
@Mock
+ private lateinit var batteryMeterViewController: BatteryMeterViewController
+ @Mock
private lateinit var clock: Clock
@Mock
private lateinit var mockView: View
@@ -133,6 +136,7 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
colorExtractor,
privacyDialogController,
qsExpansionPathInterpolator,
+ batteryMeterViewController,
featureFlags
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
index 72c7ddd3e5a5..126b332af30d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
@@ -37,8 +37,8 @@ import android.widget.TextView;
import androidx.test.filters.SmallTest;
import com.android.keyguard.CarrierTextManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
import com.android.systemui.util.CarrierConfigTracker;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
index 4a1411a329be..8546a359b459 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
@@ -45,26 +45,23 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.text.TextUtils;
import android.util.ArraySet;
-import android.util.FeatureFlagUtils;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
-import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.internal.logging.InstanceId;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -74,8 +71,6 @@ import org.mockito.Captor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoSession;
-import org.mockito.quality.Strictness;
import java.util.ArrayList;
import java.util.Arrays;
@@ -114,7 +109,6 @@ public class TileQueryHelperTest extends SysuiTestCase {
private PackageManager mPackageManager;
@Mock
private UserTracker mUserTracker;
- @Mock private FeatureFlags mFeatureFlags;
@Captor
private ArgumentCaptor<List<TileQueryHelper.TileInfo>> mCaptor;
@@ -122,18 +116,10 @@ public class TileQueryHelperTest extends SysuiTestCase {
private TileQueryHelper mTileQueryHelper;
private FakeExecutor mMainExecutor;
private FakeExecutor mBgExecutor;
- MockitoSession mMockingSession = null;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- // TODO(b/174753536): Remove the mMockingSession when
- // FeatureFlagUtils.SETTINGS_PROVIDER_MODEL is removed.
- mMockingSession = ExtendedMockito.mockitoSession().strictness(Strictness.LENIENT)
- .mockStatic(FeatureFlagUtils.class).startMocking();
- ExtendedMockito.doReturn(false).when(() -> FeatureFlagUtils.isEnabled(mContext,
- FeatureFlagUtils.SETTINGS_PROVIDER_MODEL));
-
mContext.setMockPackageManager(mPackageManager);
mState = new QSTile.State();
@@ -153,17 +139,10 @@ public class TileQueryHelperTest extends SysuiTestCase {
mMainExecutor = new FakeExecutor(clock);
mBgExecutor = new FakeExecutor(clock);
mTileQueryHelper = new TileQueryHelper(
- mContext, mUserTracker, mMainExecutor, mBgExecutor, mFeatureFlags);
+ mContext, mUserTracker, mMainExecutor, mBgExecutor);
mTileQueryHelper.setListener(mListener);
}
- @After
- public void tearDown() throws Exception {
- if (mMockingSession != null) {
- mMockingSession.finishMocking();
- }
- }
-
@Test
public void testIsFinished_falseBeforeQuerying() {
assertFalse(mTileQueryHelper.isFinished());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
index 3a4bc699b967..670a130d610a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
@@ -26,7 +26,6 @@ import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
-import android.content.Context;
import android.graphics.Rect;
import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
@@ -36,7 +35,6 @@ import android.view.IWindowManager;
import android.view.ScrollCaptureResponse;
import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.screenshot.ScrollCaptureClient.CaptureResult;
@@ -83,7 +81,7 @@ public class ScrollCaptureClientTest extends SysuiTestCase {
/* taskId */ anyInt(), any(IScrollCaptureResponseListener.class));
// Create client
- ScrollCaptureClient client = new ScrollCaptureClient(mContext, mWm);
+ ScrollCaptureClient client = new ScrollCaptureClient(mWm, Runnable::run, mContext);
// Request scroll capture
ListenableFuture<ScrollCaptureResponse> requestFuture =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index d23a9ce26def..7c045c1f2894 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -184,8 +184,9 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
@Test
fun setQsPanelExpansion_appliesBlur() {
notificationShadeDepthController.qsPanelExpansion = 1f
+ notificationShadeDepthController.onPanelExpansionChanged(0.5f, tracking = false)
notificationShadeDepthController.updateBlurCallback.doFrame(0)
- verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
+ verify(blurUtils).applyBlur(any(), eq(maxBlur / 2), eq(false))
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt
index 85ec3faa4013..f2671b763b56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt
@@ -22,7 +22,7 @@ import android.view.WindowManager
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.ConfigurationController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
index 116f807a888d..756e9844e6c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
@@ -41,7 +41,7 @@ import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener
import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
import com.android.systemui.util.concurrency.FakeExecution
@@ -389,7 +389,6 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
verify(userTracker).removeCallback(userListener)
verify(contentResolver).unregisterContentObserver(settingsObserver)
verify(configurationController).removeCallback(configChangeListener)
- verify(statusBarStateController).removeCallback(statusBarStateListener)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 1be14b66e968..8a32ce6c4f43 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -64,7 +64,7 @@ import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index 9a5482c33501..39d794dc0bd9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -67,7 +67,7 @@ import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.dump.LogBufferEulogizer;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.notification.collection.NoManSimulator.NotifEvent;
import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
new file mode 100644
index 000000000000..24a0ad3de196
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row;
+
+import static android.view.DragEvent.ACTION_DRAG_STARTED;
+
+import android.content.Context;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.DragEvent;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class ExpandableNotificationRowDragControllerTest extends SysuiTestCase {
+
+ private ExpandableNotificationRow mRow;
+ private ExpandableNotificationRow mGroupRow;
+ private ExpandableNotificationRowDragController mController;
+ private NotificationTestHelper mNotificationTestHelper;
+
+ private NotificationGutsManager mGutsManager = mock(NotificationGutsManager.class);
+ private HeadsUpManager mHeadsUpManager = mock(HeadsUpManager.class);
+ private NotificationMenuRow mMenuRow = mock(NotificationMenuRow.class);
+ private NotificationMenuRowPlugin.MenuItem mMenuItem =
+ mock(NotificationMenuRowPlugin.MenuItem.class);
+
+ @Before
+ public void setUp() throws Exception {
+ allowTestableLooperAsMainThread();
+
+ mDependency.injectMockDependency(ShadeController.class);
+
+ mNotificationTestHelper = new NotificationTestHelper(
+ mContext,
+ mDependency,
+ TestableLooper.get(this));
+ mRow = mNotificationTestHelper.createRow();
+ mGroupRow = mNotificationTestHelper.createGroup(4);
+ when(mMenuRow.getLongpressMenuItem(any(Context.class))).thenReturn(mMenuItem);
+
+ mController = new ExpandableNotificationRowDragController(mContext, mHeadsUpManager);
+ }
+
+ @Test
+ public void testDoStartDragHeadsUpNotif_startDragAndDrop() throws Exception {
+ ExpandableNotificationRowDragController controller = createSpyController();
+ mRow.setDragController(controller);
+ mRow.setHeadsUp(true);
+ mRow.setPinned(true);
+
+ mRow.doLongClickCallback(0, 0);
+ mRow.doDragCallback(0, 0);
+ verify(controller).startDragAndDrop(mRow);
+
+ // Simulate the drag start
+ mRow.dispatchDragEvent(DragEvent.obtain(ACTION_DRAG_STARTED, 0, 0, 0, 0, null, null, null,
+ null, null, false));
+ verify(mHeadsUpManager, times(1)).releaseAllImmediately();
+ }
+
+ @Test
+ public void testDoStartDragNotif() throws Exception {
+ ExpandableNotificationRowDragController controller = createSpyController();
+ mRow.setDragController(controller);
+
+ mDependency.get(ShadeController.class).instantExpandNotificationsPanel();
+ mRow.doDragCallback(0, 0);
+ verify(controller).startDragAndDrop(mRow);
+
+ // Simulate the drag start
+ mRow.dispatchDragEvent(DragEvent.obtain(ACTION_DRAG_STARTED, 0, 0, 0, 0, null, null, null,
+ null, null, false));
+ verify(mDependency.get(ShadeController.class)).animateCollapsePanels(0, true);
+ }
+
+ private ExpandableNotificationRowDragController createSpyController() {
+ return spy(mController);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index cea49b71f009..4562e4f5954d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -47,11 +47,11 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
@@ -265,7 +265,8 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
new FalsingManagerFake(),
new FalsingCollectorFake(),
mPeopleNotificationIdentifier,
- Optional.of(mock(BubblesManager.class))
+ Optional.of(mock(BubblesManager.class)),
+ mock(ExpandableNotificationRowDragController.class)
));
when(mNotificationRowComponentBuilder.activatableNotificationView(any()))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index c56d085a3aaf..07ebaea8bdda 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -46,11 +46,11 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index d02d77eac13a..4e76b1695f0b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -52,7 +52,6 @@ import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.EmptyShadeView;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.StatusBarState;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
index b0d1fc144b3d..b051a5987fbc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
@@ -37,8 +37,8 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiBaseFragmentTest;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
index 5bf1bb3c573f..7a0b3669991c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
@@ -38,7 +38,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.doze.DozeScreenState;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.tuner.TunerService;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index 6e0cbd9ecfa3..bca1227b7d35 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -202,6 +202,5 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
verify(mPanelView).removeTrackingHeadsUpListener(any());
verify(mPanelView).setHeadsUpAppearanceController(isNull());
verify(mStackScrollerController).removeOnExpandedHeightChangedListener(any());
- verify(mStackScrollerController).removeOnLayoutChangeListener(any());
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index 690b8415762d..2e76bd76e823 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -38,35 +38,27 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
private static final float ZERO_DRAG = 0.f;
private static final float OPAQUE = 1.f;
private static final float TRANSPARENT = 0.f;
- private static final boolean HAS_CUSTOM_CLOCK = false;
- private static final boolean HAS_VISIBLE_NOTIFS = false;
private KeyguardClockPositionAlgorithm mClockPositionAlgorithm;
private KeyguardClockPositionAlgorithm.Result mClockPosition;
- private int mNotificationStackHeight;
private float mPanelExpansion;
private int mKeyguardStatusHeight;
private float mDark;
- private boolean mHasCustomClock;
- private boolean mHasVisibleNotifs;
private float mQsExpansion;
- private int mCutoutTopInset = 0; // in pixels
+ private int mCutoutTopInsetPx = 0;
+ private int mSplitShadeSmartspaceHeightPx = 0;
private boolean mIsSplitShade = false;
@Before
public void setUp() {
mClockPositionAlgorithm = new KeyguardClockPositionAlgorithm();
mClockPosition = new KeyguardClockPositionAlgorithm.Result();
-
- mHasCustomClock = HAS_CUSTOM_CLOCK;
- mHasVisibleNotifs = HAS_VISIBLE_NOTIFS;
}
@Test
public void clockPositionTopOfScreenOnAOD() {
- // GIVEN on AOD and both stack scroll and clock have 0 height
+ // GIVEN on AOD and clock has 0 height
givenAOD();
- mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = EMPTY_HEIGHT;
// WHEN the clock position algorithm is run
positionClock();
@@ -79,11 +71,10 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
@Test
public void clockPositionBelowCutout() {
- // GIVEN on AOD and both stack scroll and clock have 0 height
+ // GIVEN on AOD and clock has 0 height
givenAOD();
- mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = EMPTY_HEIGHT;
- mCutoutTopInset = 300;
+ mCutoutTopInsetPx = 300;
// WHEN the clock position algorithm is run
positionClock();
// THEN the clock Y position is below the cutout
@@ -97,7 +88,6 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
public void clockPositionAdjustsForKeyguardStatusOnAOD() {
// GIVEN on AOD with a clock of height 100
givenAOD();
- mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = 100;
// WHEN the clock position algorithm is run
positionClock();
@@ -112,7 +102,6 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
public void clockPositionLargeClockOnAOD() {
// GIVEN on AOD with a full screen clock
givenAOD();
- mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = SCREEN_HEIGHT;
// WHEN the clock position algorithm is run
positionClock();
@@ -125,9 +114,8 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
@Test
public void clockPositionTopOfScreenOnLockScreen() {
- // GIVEN on lock screen with stack scroll and clock of 0 height
+ // GIVEN on lock screen with clock of 0 height
givenLockScreen();
- mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = EMPTY_HEIGHT;
// WHEN the clock position algorithm is run
positionClock();
@@ -138,24 +126,9 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
}
@Test
- public void clockPositionWithStackScrollExpandOnLockScreen() {
- // GIVEN on lock screen with stack scroll of height 500
- givenLockScreen();
- mNotificationStackHeight = 500;
- mKeyguardStatusHeight = EMPTY_HEIGHT;
- // WHEN the clock position algorithm is run
- positionClock();
- // THEN the clock Y position stays to the top
- assertThat(mClockPosition.clockY).isEqualTo(0);
- // AND the clock is positioned on the left.
- assertThat(mClockPosition.clockX).isEqualTo(0);
- }
-
- @Test
public void clockPositionWithPartialDragOnLockScreen() {
// GIVEN dragging up on lock screen
givenLockScreen();
- mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = EMPTY_HEIGHT;
mPanelExpansion = 0.5f;
// WHEN the clock position algorithm is run
@@ -171,7 +144,6 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
public void clockPositionWithFullDragOnLockScreen() {
// GIVEN the lock screen is dragged up
givenLockScreen();
- mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = EMPTY_HEIGHT;
mPanelExpansion = 0.f;
// WHEN the clock position algorithm is run
@@ -184,7 +156,6 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
public void largeClockOnLockScreenIsTransparent() {
// GIVEN on lock screen with a full screen clock
givenLockScreen();
- mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = SCREEN_HEIGHT;
// WHEN the clock position algorithm is run
positionClock();
@@ -194,9 +165,8 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
@Test
public void notifPositionTopOfScreenOnAOD() {
- // GIVEN on AOD and both stack scroll and clock have 0 height
+ // GIVEN on AOD and clock has 0 height
givenAOD();
- mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = EMPTY_HEIGHT;
// WHEN the position algorithm is run
positionClock();
@@ -208,7 +178,6 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
public void notifPositionIndependentOfKeyguardStatusHeightOnAOD() {
// GIVEN on AOD and clock has a nonzero height
givenAOD();
- mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = 100;
// WHEN the position algorithm is run
positionClock();
@@ -220,7 +189,6 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
public void notifPositionWithLargeClockOnAOD() {
// GIVEN on AOD and clock has a nonzero height
givenAOD();
- mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = SCREEN_HEIGHT;
// WHEN the position algorithm is run
positionClock();
@@ -230,9 +198,8 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
@Test
public void notifPositionMiddleOfScreenOnLockScreen() {
- // GIVEN on lock screen and both stack scroll and clock have 0 height
+ // GIVEN on lock screen and clock has 0 height
givenLockScreen();
- mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = EMPTY_HEIGHT;
// WHEN the position algorithm is run
positionClock();
@@ -241,58 +208,42 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
}
@Test
- public void notifPositionAdjustsForStackHeightOnLockScreen() {
- // GIVEN on lock screen and stack scroller has a nonzero height
- givenLockScreen();
- mNotificationStackHeight = 500;
- mKeyguardStatusHeight = EMPTY_HEIGHT;
- // WHEN the position algorithm is run
- positionClock();
- // THEN the notif padding adjusts for keyguard status height
- assertThat(mClockPosition.stackScrollerPadding).isEqualTo(0);
- }
-
- @Test
public void notifPositionAdjustsForClockHeightOnLockScreen() {
// GIVEN on lock screen and stack scroller has a nonzero height
givenLockScreen();
- mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = 200;
// WHEN the position algorithm is run
positionClock();
- // THEN the notif padding adjusts for both clock and notif stack.
+
assertThat(mClockPosition.stackScrollerPadding).isEqualTo(200);
}
@Test
- public void notifPositionAdjustsForStackHeightAndClockHeightOnLockScreen() {
- // GIVEN on lock screen and stack scroller has a nonzero height
+ public void notifPositionAlignedWithClockInSplitShadeMode() {
givenLockScreen();
- mNotificationStackHeight = 500;
+ mIsSplitShade = true;
mKeyguardStatusHeight = 200;
// WHEN the position algorithm is run
positionClock();
- // THEN the notifs are placed below the statusview
- assertThat(mClockPosition.stackScrollerPadding).isEqualTo(200);
+ // THEN the notif padding DOESN'T adjust for keyguard status height.
+ assertThat(mClockPosition.stackScrollerPadding).isEqualTo(0);
}
@Test
- public void notifPositionAlignedWithClockInSplitShadeMode() {
- // GIVEN on lock screen and split shade mode
+ public void notifPositionAdjustedBySmartspaceHeightInSplitShadeMode() {
givenLockScreen();
+ mSplitShadeSmartspaceHeightPx = 200;
mIsSplitShade = true;
- mHasCustomClock = true;
// WHEN the position algorithm is run
positionClock();
- // THEN the notif padding DOESN'T adjust for keyguard status height.
- assertThat(mClockPosition.stackScrollerPadding).isEqualTo(0);
+
+ assertThat(mClockPosition.stackScrollerPadding).isEqualTo(200);
}
@Test
public void notifPositionWithLargeClockOnLockScreen() {
// GIVEN on lock screen and clock has a nonzero height
givenLockScreen();
- mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = SCREEN_HEIGHT;
// WHEN the position algorithm is run
positionClock();
@@ -304,7 +255,6 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
public void notifPositionWithFullDragOnLockScreen() {
// GIVEN the lock screen is dragged up
givenLockScreen();
- mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = EMPTY_HEIGHT;
mPanelExpansion = 0.f;
// WHEN the clock position algorithm is run
@@ -317,19 +267,18 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
public void notifPositionWithLargeClockFullDragOnLockScreen() {
// GIVEN the lock screen is dragged up and a full screen clock
givenLockScreen();
- mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = SCREEN_HEIGHT;
mPanelExpansion = 0.f;
// WHEN the clock position algorithm is run
positionClock();
- // THEN the notif padding is zero.
+
assertThat(mClockPosition.stackScrollerPadding).isEqualTo(
(int) (mKeyguardStatusHeight * .667f));
}
@Test
public void clockHiddenWhenQsIsExpanded() {
- // GIVEN on the lock screen with a custom clock and visible notifications
+ // GIVEN on the lock screen with visible notifications
givenLockScreen();
mQsExpansion = 1;
// WHEN the clock position algorithm is run
@@ -349,12 +298,12 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
}
private void positionClock() {
- mClockPositionAlgorithm.setup(EMPTY_MARGIN, SCREEN_HEIGHT, mNotificationStackHeight,
- mPanelExpansion, SCREEN_HEIGHT, mKeyguardStatusHeight,
+ mClockPositionAlgorithm.setup(EMPTY_MARGIN, SCREEN_HEIGHT,
+ mPanelExpansion, mKeyguardStatusHeight,
0 /* userSwitchHeight */, 0 /* userSwitchPreferredY */,
- mHasCustomClock, mHasVisibleNotifs, mDark, ZERO_DRAG, false /* bypassEnabled */,
+ mDark, ZERO_DRAG, false /* bypassEnabled */,
0 /* unlockedStackScrollerPadding */, mQsExpansion,
- mCutoutTopInset, mIsSplitShade);
+ mCutoutTopInsetPx, mSplitShadeSmartspaceHeightPx, mIsSplitShade);
mClockPositionAlgorithm.run(mClockPosition);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index 217a77d9ffdf..9cc762c8302e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -28,7 +28,8 @@ import androidx.test.filters.SmallTest;
import com.android.keyguard.CarrierTextController;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.battery.BatteryMeterViewController;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -59,6 +60,8 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
private StatusBarIconController mStatusBarIconController;
@Mock
private FeatureFlags mFeatureFlags;
+ @Mock
+ private BatteryMeterViewController mBatteryMeterViewController;
private KeyguardStatusBarViewController mController;
@@ -78,7 +81,8 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
mBatteryController,
mUserInfoController,
mStatusBarIconController,
- new StatusBarIconController.TintedIconManager.Factory(mFeatureFlags)
+ new StatusBarIconController.TintedIconManager.Factory(mFeatureFlags),
+ mBatteryMeterViewController
);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index cbaca3a59da4..1387b8e1f1b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -63,6 +63,7 @@ import android.view.ViewPropertyAnimator;
import android.view.ViewStub;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.FrameLayout;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
@@ -112,6 +113,7 @@ import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.events.PrivacyDotViewController;
+import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.statusbar.notification.ConversationNotificationManager;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -300,6 +302,10 @@ public class NotificationPanelViewTest extends SysuiTestCase {
private RecordingController mRecordingController;
@Mock
private ControlsComponent mControlsComponent;
+ @Mock
+ private LockscreenSmartspaceController mLockscreenSmartspaceController;
+ @Mock
+ private FrameLayout mSplitShadeSmartspaceContainer;
private SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController;
@@ -349,6 +355,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame);
when(mView.findViewById(R.id.keyguard_status_view))
.thenReturn(mock(KeyguardStatusView.class));
+ when(mView.findViewById(R.id.split_shade_smartspace_container))
+ .thenReturn(mSplitShadeSmartspaceContainer);
mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null);
mNotificationContainerParent.addView(newViewWithId(R.id.qs_frame));
mNotificationContainerParent.addView(newViewWithId(R.id.notification_stack_scroller));
@@ -442,6 +450,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
new FakeExecutor(new FakeSystemClock()),
mSecureSettings,
mSplitShadeHeaderController,
+ mLockscreenSmartspaceController,
mUnlockedScreenOffAnimationController,
mNotificationRemoteInputManager,
mControlsComponent);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
new file mode 100644
index 000000000000..50cea073c701
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.CommandQueue
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class PhoneStatusBarViewControllerTest : SysuiTestCase() {
+
+ @Mock
+ private lateinit var commandQueue: CommandQueue
+
+ private lateinit var view: PhoneStatusBarView
+ private lateinit var controller: PhoneStatusBarViewController
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ view = PhoneStatusBarView(mContext, null)
+ controller = PhoneStatusBarViewController(view, commandQueue)
+ }
+
+ @Test
+ fun constructor_setsPanelEnabledProviderOnView() {
+ var providerUsed = false
+ `when`(commandQueue.panelsEnabled()).then {
+ providerUsed = true
+ true
+ }
+
+ // If the constructor correctly set a [PanelEnabledProvider], then it should be used
+ // when [PhoneStatusBarView.panelEnabled] is called.
+ view.panelEnabled()
+
+ assertThat(providerUsed).isTrue()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
new file mode 100644
index 000000000000..49ab6ebbde93
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+
+@SmallTest
+class PhoneStatusBarViewTest : SysuiTestCase() {
+
+ private lateinit var view: PhoneStatusBarView
+
+ @Before
+ fun setUp() {
+ view = PhoneStatusBarView(mContext, null)
+ }
+
+ @Test
+ fun panelEnabled_providerReturnsTrue_returnsTrue() {
+ view.setPanelEnabledProvider { true }
+
+ assertThat(view.panelEnabled()).isTrue()
+ }
+
+ @Test
+ fun panelEnabled_providerReturnsFalse_returnsFalse() {
+ view.setPanelEnabledProvider { false }
+
+ assertThat(view.panelEnabled()).isFalse()
+ }
+
+ @Test
+ fun panelEnabled_noProvider_noCrash() {
+ view.panelEnabled()
+ // No assert needed, just testing no crash
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index f4421f1393fb..30fc13b168f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -642,23 +642,6 @@ public class ScrimControllerTest extends SysuiTestCase {
mScrimBehind, SEMI_TRANSPARENT));
}
- @Test
- public void transitionToBubbleExpanded() {
- mScrimController.transitionTo(ScrimState.BUBBLE_EXPANDED);
- finishAnimationsImmediately();
-
- assertScrimTinted(Map.of(
- mScrimInFront, false,
- mScrimBehind, false
- ));
-
- // Front scrim should be transparent
- assertEquals(ScrimController.TRANSPARENT,
- mScrimInFront.getViewAlpha(), 0.0f);
- // Back scrim should be visible
- assertEquals(ScrimController.BUSY_SCRIM_ALPHA,
- mScrimBehind.getViewAlpha(), 0.0f);
- }
@Test
public void scrimStateCallback() {
@@ -1061,7 +1044,7 @@ public class ScrimControllerTest extends SysuiTestCase {
HashSet<ScrimState> regularStates = new HashSet<>(Arrays.asList(
ScrimState.UNINITIALIZED, ScrimState.KEYGUARD, ScrimState.BOUNCER,
ScrimState.BOUNCER_SCRIMMED, ScrimState.BRIGHTNESS_MIRROR, ScrimState.UNLOCKED,
- ScrimState.BUBBLE_EXPANDED, ScrimState.SHADE_LOCKED, ScrimState.AUTH_SCRIMMED));
+ ScrimState.SHADE_LOCKED, ScrimState.AUTH_SCRIMMED));
for (ScrimState state : ScrimState.values()) {
if (!lowPowerModeStates.contains(state) && !regularStates.contains(state)) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java
new file mode 100644
index 000000000000..52538c7f5496
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.StatusBarManager;
+import android.os.PowerManager;
+import android.os.Vibrator;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.testing.FakeMetricsLogger;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.StatusBarStateControllerImpl;
+import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
+import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
+
+import java.util.Optional;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class StatusBarCommandQueueCallbacksTest extends SysuiTestCase {
+ @Mock private StatusBar mStatusBar;
+ @Mock private ShadeController mShadeController;
+ @Mock private CommandQueue mCommandQueue;
+ @Mock private NotificationPanelViewController mNotificationPanelViewController;
+ @Mock private LegacySplitScreen mLegacySplitScreen;
+ @Mock private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
+ private final MetricsLogger mMetricsLogger = new FakeMetricsLogger();
+ @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock private KeyguardStateController mKeyguardStateController;
+ @Mock private HeadsUpManagerPhone mHeadsUpManager;
+ @Mock private WakefulnessLifecycle mWakefulnessLifecycle;
+ @Mock private DeviceProvisionedController mDeviceProvisionedController;
+ @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ @Mock private AssistManager mAssistManager;
+ @Mock private DozeServiceHost mDozeServiceHost;
+ @Mock private StatusBarStateControllerImpl mStatusBarStateController;
+ @Mock private NotificationShadeWindowView mNotificationShadeWindowView;
+ @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
+ @Mock private PowerManager mPowerManager;
+ @Mock private VibratorHelper mVibratorHelper;
+ @Mock private Vibrator mVibrator;
+ @Mock private LightBarController mLightBarController;
+
+ StatusBarCommandQueueCallbacks mSbcqCallbacks;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ mSbcqCallbacks = new StatusBarCommandQueueCallbacks(
+ mStatusBar,
+ mContext,
+ mContext.getResources(),
+ mShadeController,
+ mCommandQueue,
+ mNotificationPanelViewController,
+ Optional.of(mLegacySplitScreen),
+ mRemoteInputQuickSettingsDisabler,
+ mMetricsLogger,
+ mKeyguardUpdateMonitor,
+ mKeyguardStateController,
+ mHeadsUpManager,
+ mWakefulnessLifecycle,
+ mDeviceProvisionedController,
+ mStatusBarKeyguardViewManager,
+ mAssistManager,
+ mDozeServiceHost,
+ mStatusBarStateController,
+ mNotificationShadeWindowView,
+ mNotificationStackScrollLayoutController,
+ mPowerManager,
+ mVibratorHelper,
+ Optional.of(mVibrator),
+ mLightBarController,
+ DEFAULT_DISPLAY);
+
+ when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
+ when(mRemoteInputQuickSettingsDisabler.adjustDisableFlags(anyInt()))
+ .thenAnswer((Answer<Integer>) invocation -> invocation.getArgument(0));
+ }
+
+ @Test
+ public void testDisableNotificationShade() {
+ when(mStatusBar.getDisabled1()).thenReturn(StatusBarManager.DISABLE_NONE);
+ when(mStatusBar.getDisabled2()).thenReturn(StatusBarManager.DISABLE_NONE);
+ when(mCommandQueue.panelsEnabled()).thenReturn(false);
+ mSbcqCallbacks.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE,
+ StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false);
+
+ verify(mStatusBar).updateQsExpansionEnabled();
+ verify(mShadeController).animateCollapsePanels();
+
+ // Trying to open it does nothing.
+ mSbcqCallbacks.animateExpandNotificationsPanel();
+ verify(mNotificationPanelViewController, never()).expandWithoutQs();
+ mSbcqCallbacks.animateExpandSettingsPanel(null);
+ verify(mNotificationPanelViewController, never()).expand(anyBoolean());
+ }
+
+ @Test
+ public void testEnableNotificationShade() {
+ when(mStatusBar.getDisabled1()).thenReturn(StatusBarManager.DISABLE_NONE);
+ when(mStatusBar.getDisabled2()).thenReturn(StatusBarManager.DISABLE2_NOTIFICATION_SHADE);
+ when(mCommandQueue.panelsEnabled()).thenReturn(true);
+ mSbcqCallbacks.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE,
+ StatusBarManager.DISABLE2_NONE, false);
+ verify(mStatusBar).updateQsExpansionEnabled();
+ verify(mShadeController, never()).animateCollapsePanels();
+
+ // Can now be opened.
+ mSbcqCallbacks.animateExpandNotificationsPanel();
+ verify(mNotificationPanelViewController).expandWithoutQs();
+ mSbcqCallbacks.animateExpandSettingsPanel(null);
+ verify(mNotificationPanelViewController).expandWithQs();
+ }
+
+ @Test
+ public void testSuppressAmbientDisplay_suppress() {
+ mSbcqCallbacks.suppressAmbientDisplay(true);
+ verify(mDozeServiceHost).setDozeSuppressed(true);
+ }
+
+ @Test
+ public void testSuppressAmbientDisplay_unsuppress() {
+ mSbcqCallbacks.suppressAmbientDisplay(false);
+ verify(mDozeServiceHost).setDozeSuppressed(false);
+ }
+
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
index e3263d4ca6b3..0f1c40bacb7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
@@ -30,8 +30,8 @@ import android.widget.LinearLayout;
import androidx.test.filters.SmallTest;
import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarMobileView;
import com.android.systemui.statusbar.StatusBarWifiView;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 83bf96b5885b..72a3d664a6ce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -53,10 +53,10 @@ import com.android.systemui.ActivityIntentHelper;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationClickNotifier;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 2a58f7c8e98d..e4f6e13db607 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -18,7 +18,6 @@ package com.android.systemui.statusbar.phone;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
-import static android.view.Display.DEFAULT_DISPLAY;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
@@ -40,7 +39,7 @@ import static org.mockito.Mockito.when;
import android.app.IWallpaperManager;
import android.app.Notification;
-import android.app.StatusBarManager;
+import android.app.WallpaperManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -78,29 +77,25 @@ import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.InitController;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.demomode.DemoModeController;
-import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.PluginDependencyProvider;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.shared.plugins.PluginManager;
-import com.android.unfold.config.UnfoldTransitionConfig;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationListener;
@@ -114,11 +109,8 @@ import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
-import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.charging.WiredChargingRippleController;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
@@ -143,14 +135,15 @@ import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
+import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.volume.VolumeComponent;
import com.android.systemui.wmshell.BubblesManager;
+import com.android.unfold.config.UnfoldTransitionConfig;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.startingsurface.StartingSurface;
@@ -181,7 +174,6 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private NotificationsController mNotificationsController;
@Mock private LightBarController mLightBarController;
- @Mock private StatusBarSignalPolicy mStatusBarSignalPolicy;
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock private KeyguardStateController mKeyguardStateController;
@Mock private KeyguardIndicationController mKeyguardIndicationController;
@@ -206,7 +198,6 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private BatteryController mBatteryController;
@Mock private DeviceProvisionedController mDeviceProvisionedController;
@Mock private StatusBarNotificationPresenter mNotificationPresenter;
- @Mock private NotificationEntryListener mEntryListener;
@Mock private NotificationFilter mNotificationFilter;
@Mock private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
@Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
@@ -217,7 +208,6 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private NotificationGutsManager mNotificationGutsManager;
@Mock private NotificationMediaManager mNotificationMediaManager;
@Mock private NavigationBarController mNavigationBarController;
- @Mock private AccessibilityFloatingMenuController mAccessibilityFloatingMenuController;
@Mock private BypassHeadsUpNotifier mBypassHeadsUpNotifier;
@Mock private SysuiColorExtractor mColorExtractor;
@Mock private ColorExtractor.GradientColors mGradientColors;
@@ -229,7 +219,6 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private NotificationViewHierarchyManager mNotificationViewHierarchyManager;
@Mock private UserSwitcherController mUserSwitcherController;
@Mock private NetworkController mNetworkController;
- @Mock private VibratorHelper mVibratorHelper;
@Mock private BubblesManager mBubblesManager;
@Mock private Bubbles mBubbles;
@Mock private NotificationShadeWindowController mNotificationShadeWindowController;
@@ -240,7 +229,6 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private LockscreenWallpaper mLockscreenWallpaper;
@Mock private DozeServiceHost mDozeServiceHost;
@Mock private ViewMediatorCallback mKeyguardVieMediatorCallback;
- @Mock private KeyguardLiftController mKeyguardLiftController;
@Mock private VolumeComponent mVolumeComponent;
@Mock private CommandQueue mCommandQueue;
@Mock private Provider<StatusBarComponent.Builder> mStatusBarComponentBuilderProvider;
@@ -251,12 +239,10 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
@Mock private LightsOutNotifController mLightsOutNotifController;
@Mock private ViewMediatorCallback mViewMediatorCallback;
- @Mock private DismissCallbackRegistry mDismissCallbackRegistry;
@Mock private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
@Mock private ScreenPinningRequest mScreenPinningRequest;
@Mock private StatusBarNotificationActivityStarter.Builder
mStatusBarNotificationActivityStarterBuilder;
- @Mock private DarkIconDispatcher mDarkIconDispatcher;
@Mock private PluginDependencyProvider mPluginDependencyProvider;
@Mock private KeyguardDismissUtil mKeyguardDismissUtil;
@Mock private ExtensionController mExtensionController;
@@ -265,7 +251,6 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private DemoModeController mDemoModeController;
@Mock private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
@Mock private BrightnessSlider.Factory mBrightnessSliderFactory;
- @Mock private WiredChargingRippleController mWiredChargingRippleController;
@Mock private UnfoldTransitionConfig mUnfoldTransitionConfig;
@Mock private Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealOverlayAnimationLazy;
@Mock private OngoingCallController mOngoingCallController;
@@ -274,9 +259,11 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private StatusBarIconController mIconController;
@Mock private LockscreenShadeTransitionController mLockscreenTransitionController;
@Mock private FeatureFlags mFeatureFlags;
- @Mock private IWallpaperManager mWallpaperManager;
+ @Mock private WallpaperManager mWallpaperManager;
+ @Mock private IWallpaperManager mIWallpaperManager;
@Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+ @Mock private TunerService mTunerService;
@Mock private StartingSurface mStartingSurface;
private ShadeController mShadeController;
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
@@ -335,7 +322,7 @@ public class StatusBarTest extends SysuiTestCase {
}).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());
WakefulnessLifecycle wakefulnessLifecycle =
- new WakefulnessLifecycle(mContext, mWallpaperManager);
+ new WakefulnessLifecycle(mContext, mIWallpaperManager);
wakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
wakefulnessLifecycle.dispatchFinishedWakingUp();
@@ -362,7 +349,6 @@ public class StatusBarTest extends SysuiTestCase {
mLightBarController,
mAutoHideController,
mKeyguardUpdateMonitor,
- mStatusBarSignalPolicy,
mPulseExpansionHandler,
mNotificationWakeUpCoordinator,
mKeyguardBypassController,
@@ -373,11 +359,6 @@ public class StatusBarTest extends SysuiTestCase {
new FalsingManagerFake(),
new FalsingCollectorFake(),
mBroadcastDispatcher,
- new RemoteInputQuickSettingsDisabler(
- mContext,
- configurationController,
- mCommandQueue
- ),
mNotificationGutsManager,
notificationLogger,
mNotificationInterruptStateProvider,
@@ -396,19 +377,16 @@ public class StatusBarTest extends SysuiTestCase {
new ScreenLifecycle(),
wakefulnessLifecycle,
mStatusBarStateController,
- mVibratorHelper,
Optional.of(mBubblesManager),
Optional.of(mBubbles),
mVisualStabilityManager,
mDeviceProvisionedController,
mNavigationBarController,
- mAccessibilityFloatingMenuController,
() -> mAssistManager,
configurationController,
mNotificationShadeWindowController,
mDozeParameters,
mScrimController,
- mKeyguardLiftController,
mLockscreenWallpaperLazy,
mBiometricUnlockControllerLazy,
mDozeServiceHost,
@@ -433,13 +411,11 @@ public class StatusBarTest extends SysuiTestCase {
mUserInfoControllerImpl,
mPhoneStatusBarPolicy,
mKeyguardIndicationController,
- mDismissCallbackRegistry,
mDemoModeController,
mNotificationShadeDepthControllerLazy,
mStatusBarTouchableRegionManager,
mNotificationIconAreaController,
mBrightnessSliderFactory,
- mWiredChargingRippleController,
mUnfoldTransitionConfig,
mUnfoldLightRevealOverlayAnimationLazy,
mOngoingCallController,
@@ -449,8 +425,10 @@ public class StatusBarTest extends SysuiTestCase {
mLockscreenTransitionController,
mFeatureFlags,
mKeyguardUnlockAnimationController,
+ mWallpaperManager,
mUnlockedScreenOffAnimationController,
- Optional.of(mStartingSurface));
+ Optional.of(mStartingSurface),
+ mTunerService);
when(mKeyguardViewMediator.registerStatusBar(any(StatusBar.class), any(ViewGroup.class),
any(NotificationPanelViewController.class), any(BiometricUnlockController.class),
any(ViewGroup.class), any(KeyguardBypassController.class)))
@@ -754,31 +732,6 @@ public class StatusBarTest extends SysuiTestCase {
}
@Test
- public void testDisableExpandStatusBar() {
- mStatusBar.setBarStateForTest(StatusBarState.SHADE);
- mStatusBar.setUserSetupForTest(true);
- when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
-
- when(mCommandQueue.panelsEnabled()).thenReturn(false);
- mStatusBar.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE,
- StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false);
- verify(mNotificationPanelViewController).setQsExpansionEnabledPolicy(false);
- mStatusBar.animateExpandNotificationsPanel();
- verify(mNotificationPanelViewController, never()).expand(anyBoolean());
- mStatusBar.animateExpandSettingsPanel(null);
- verify(mNotificationPanelViewController, never()).expand(anyBoolean());
-
- when(mCommandQueue.panelsEnabled()).thenReturn(true);
- mStatusBar.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE,
- StatusBarManager.DISABLE2_NONE, false);
- verify(mNotificationPanelViewController).setQsExpansionEnabledPolicy(true);
- mStatusBar.animateExpandNotificationsPanel();
- verify(mNotificationPanelViewController).expandWithoutQs();
- mStatusBar.animateExpandSettingsPanel(null);
- verify(mNotificationPanelViewController).expandWithQs();
- }
-
- @Test
public void testDump_DoesNotCrash() {
mStatusBar.dump(null, new PrintWriter(new ByteArrayOutputStream()), null);
}
@@ -905,18 +858,6 @@ public class StatusBarTest extends SysuiTestCase {
}
@Test
- public void testSuppressAmbientDisplay_suppress() {
- mStatusBar.suppressAmbientDisplay(true);
- verify(mDozeServiceHost).setDozeSuppressed(true);
- }
-
- @Test
- public void testSuppressAmbientDisplay_unsuppress() {
- mStatusBar.suppressAmbientDisplay(false);
- verify(mDozeServiceHost).setDozeSuppressed(false);
- }
-
- @Test
public void testUpdateResources_updatesBouncer() {
mStatusBar.updateResources();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
index d36cb0b3a717..31fa04d63d13 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -34,7 +34,7 @@ import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.flags.FeatureFlags
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
@@ -223,7 +223,6 @@ class OngoingCallControllerTest : SysuiTestCase() {
verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean())
}
-
@Test
fun onEntryRemoved_notifKeyDoesNotMatchOngoingCallNotif_listenerNotNotified() {
notifCollectionListener.onEntryAdded(createOngoingCallNotifEntry())
@@ -349,7 +348,7 @@ class OngoingCallControllerTest : SysuiTestCase() {
// Update the process to visible.
uidObserver.onUidStateChanged(CALL_UID, PROC_STATE_VISIBLE, 0, 0)
mainExecutor.advanceClockToLast()
- mainExecutor.runAllReady();
+ mainExecutor.runAllReady()
verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean())
}
@@ -370,7 +369,7 @@ class OngoingCallControllerTest : SysuiTestCase() {
// Update the process to invisible.
uidObserver.onUidStateChanged(CALL_UID, PROC_STATE_INVISIBLE, 0, 0)
mainExecutor.advanceClockToLast()
- mainExecutor.runAllReady();
+ mainExecutor.runAllReady()
verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean())
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
new file mode 100644
index 000000000000..30717f431f5b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+
+import android.hardware.devicestate.DeviceStateManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableResources;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.view.RotationPolicy;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.settings.FakeSettings;
+import com.android.systemui.util.time.FakeSystemClock;
+import com.android.systemui.util.wrapper.RotationPolicyWrapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase {
+
+ private static final String[] DEFAULT_SETTINGS = new String[]{
+ "0:0",
+ "1:2"
+ };
+
+ private final FakeSettings mFakeSettings = new FakeSettings();
+ private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
+ private final FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock);
+ @Mock DeviceStateManager mDeviceStateManager;
+ RotationPolicyWrapper mFakeRotationPolicy = new FakeRotationPolicy();
+ DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
+ private DeviceStateManager.DeviceStateCallback mDeviceStateCallback;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(/* testClass= */ this);
+ TestableResources resources = mContext.getOrCreateTestableResources();
+
+ ArgumentCaptor<DeviceStateManager.DeviceStateCallback> deviceStateCallbackArgumentCaptor =
+ ArgumentCaptor.forClass(
+ DeviceStateManager.DeviceStateCallback.class);
+
+ mDeviceStateRotationLockSettingController = new DeviceStateRotationLockSettingController(
+ mFakeSettings,
+ mFakeRotationPolicy,
+ mDeviceStateManager,
+ mFakeExecutor,
+ DEFAULT_SETTINGS
+ );
+
+ mDeviceStateRotationLockSettingController.setListening(true);
+ verify(mDeviceStateManager).registerCallback(any(),
+ deviceStateCallbackArgumentCaptor.capture());
+ mDeviceStateCallback = deviceStateCallbackArgumentCaptor.getValue();
+ }
+
+ @Test
+ public void whenSavedSettingsEmpty_defaultsLoadedAndSaved() {
+ mFakeSettings.putStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK, "",
+ UserHandle.USER_CURRENT);
+
+ mDeviceStateRotationLockSettingController.initialize();
+
+ assertThat(mFakeSettings
+ .getStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ UserHandle.USER_CURRENT))
+ .isEqualTo("0:0:1:2");
+ }
+
+ @Test
+ public void whenNoSavedValueForDeviceState_assumeIgnored() {
+ mFakeSettings.putStringForUser(
+ Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ /* value= */"0:2:1:2",
+ UserHandle.USER_CURRENT);
+ mFakeRotationPolicy.setRotationLock(true);
+ mDeviceStateRotationLockSettingController.initialize();
+
+ mDeviceStateCallback.onStateChanged(1);
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+
+ // Settings only exist for state 0 and 1
+ mDeviceStateCallback.onStateChanged(2);
+
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+ }
+
+ @Test
+ public void whenDeviceStateSwitched_loadCorrectSetting() {
+ mFakeSettings.putStringForUser(
+ Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ /* value= */"0:2:1:1",
+ UserHandle.USER_CURRENT);
+ mFakeRotationPolicy.setRotationLock(true);
+ mDeviceStateRotationLockSettingController.initialize();
+
+ mDeviceStateCallback.onStateChanged(0);
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+
+ mDeviceStateCallback.onStateChanged(1);
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue();
+
+ }
+
+ @Test
+ public void whenUserChangesSetting_saveSettingForCurrentState() {
+ mFakeSettings.putStringForUser(
+ Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ /* value= */"0:1:1:2",
+ UserHandle.USER_CURRENT);
+ mFakeRotationPolicy.setRotationLock(true);
+ mDeviceStateRotationLockSettingController.initialize();
+
+ mDeviceStateCallback.onStateChanged(0);
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue();
+
+ mDeviceStateRotationLockSettingController
+ .onRotationLockStateChanged(/* rotationLocked= */false,
+ /* affordanceVisible= */ true);
+
+ assertThat(mFakeSettings
+ .getStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ UserHandle.USER_CURRENT))
+ .isEqualTo("0:2:1:2");
+ }
+
+
+ @Test
+ public void whenDeviceStateSwitchedToIgnoredState_usePreviousSetting() {
+ mFakeSettings.putStringForUser(
+ Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ /* value= */"0:0:1:2",
+ UserHandle.USER_CURRENT);
+ mFakeRotationPolicy.setRotationLock(true);
+ mDeviceStateRotationLockSettingController.initialize();
+
+ mDeviceStateCallback.onStateChanged(1);
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+
+ mDeviceStateCallback.onStateChanged(0);
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+ }
+
+ @Test
+ public void whenDeviceStateSwitchedToIgnoredState_newSettingsSaveForPreviousState() {
+ mFakeSettings.putStringForUser(
+ Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ /* value= */"0:0:1:2",
+ UserHandle.USER_CURRENT);
+ mFakeRotationPolicy.setRotationLock(true);
+ mDeviceStateRotationLockSettingController.initialize();
+
+ mDeviceStateCallback.onStateChanged(1);
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+
+ mDeviceStateCallback.onStateChanged(0);
+ assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse();
+
+ mDeviceStateRotationLockSettingController
+ .onRotationLockStateChanged(/* rotationLocked= */true,
+ /* affordanceVisible= */ true);
+
+ assertThat(mFakeSettings
+ .getStringForUser(Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ UserHandle.USER_CURRENT))
+ .isEqualTo("0:0:1:1");
+ }
+
+ private static class FakeRotationPolicy implements RotationPolicyWrapper {
+
+ private boolean mRotationLock;
+
+ @Override
+ public void setRotationLock(boolean enabled) {
+ mRotationLock = enabled;
+ }
+
+ @Override
+ public void setRotationLockAtAngle(boolean enabled, int rotation) {
+ mRotationLock = enabled;
+ }
+
+ @Override
+ public int getRotationLockOrientation() {
+ throw new AssertionError("Not implemented");
+ }
+
+ @Override
+ public boolean isRotationLockToggleVisible() {
+ throw new AssertionError("Not implemented");
+ }
+
+ @Override
+ public boolean isRotationLocked() {
+ return mRotationLock;
+ }
+
+ @Override
+ public void registerRotationPolicyListener(RotationPolicy.RotationPolicyListener listener,
+ int userHandle) {
+ throw new AssertionError("Not implemented");
+ }
+
+ @Override
+ public void unregisterRotationPolicyListener(
+ RotationPolicy.RotationPolicyListener listener) {
+ throw new AssertionError("Not implemented");
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index f2de26c29805..21c4a1745a88 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -70,7 +70,7 @@ import com.android.settingslib.net.DataUsageController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.demomode.DemoModeController;
-import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java
new file mode 100644
index 000000000000..0581264d18e2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableResources;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.view.RotationPolicy;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.wrapper.RotationPolicyWrapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class RotationLockControllerImplTest extends SysuiTestCase {
+
+ private static final String[] DEFAULT_SETTINGS = new String[]{
+ "0:0",
+ "1:2"
+ };
+
+ @Mock RotationPolicyWrapper mRotationPolicyWrapper;
+ @Mock DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
+
+ private TestableResources mResources;
+ private ArgumentCaptor<RotationPolicy.RotationPolicyListener>
+ mRotationPolicyListenerCaptor;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(/* testClass= */ this);
+ mResources = mContext.getOrCreateTestableResources();
+
+ mRotationPolicyListenerCaptor = ArgumentCaptor.forClass(
+ RotationPolicy.RotationPolicyListener.class);
+ }
+
+ @Test
+ public void whenFlagOff_doesntInteractWithDeviceStateRotationController() {
+ createRotationLockController(new String[0]);
+
+ verifyZeroInteractions(mDeviceStateRotationLockSettingController);
+ }
+
+ @Test
+ public void whenFlagOn_setListeningSetsListeningOnDeviceStateRotationController() {
+ createRotationLockController();
+
+ verify(mDeviceStateRotationLockSettingController).setListening(/* listening= */ true);
+ }
+
+ @Test
+ public void whenFlagOn_initializesDeviceStateRotationController() {
+ createRotationLockController();
+
+ verify(mDeviceStateRotationLockSettingController).initialize();
+ }
+
+ @Test
+ public void whenFlagOn_dviceStateRotationControllerAddedToCallbacks() {
+ createRotationLockController();
+ captureRotationPolicyListener().onChange();
+
+ verify(mDeviceStateRotationLockSettingController)
+ .onRotationLockStateChanged(anyBoolean(), anyBoolean());
+ }
+
+ private RotationPolicy.RotationPolicyListener captureRotationPolicyListener() {
+ verify(mRotationPolicyWrapper)
+ .registerRotationPolicyListener(mRotationPolicyListenerCaptor.capture(), anyInt());
+ return mRotationPolicyListenerCaptor.getValue();
+ }
+
+ private void createRotationLockController() {
+ createRotationLockController(DEFAULT_SETTINGS);
+ }
+ private void createRotationLockController(String[] deviceStateRotationLockDefaults) {
+ new RotationLockControllerImpl(
+ mRotationPolicyWrapper,
+ mDeviceStateRotationLockSettingController,
+ deviceStateRotationLockDefaults
+ );
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
index ace2c71d9c63..3431a9d895d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.policy
import android.app.IActivityTaskManager
+import android.app.admin.DevicePolicyManager
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
@@ -63,6 +64,8 @@ import org.mockito.MockitoAnnotations
@SmallTest
class UserSwitcherControllerTest : SysuiTestCase() {
@Mock private lateinit var keyguardStateController: KeyguardStateController
+ @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
+ @Mock private lateinit var devicePolicyManager: DevicePolicyManager
@Mock private lateinit var handler: Handler
@Mock private lateinit var userTracker: UserTracker
@Mock private lateinit var userManager: UserManager
@@ -107,6 +110,8 @@ class UserSwitcherControllerTest : SysuiTestCase() {
userManager,
userTracker,
keyguardStateController,
+ deviceProvisionedController,
+ devicePolicyManager,
handler,
activityStarter,
broadcastDispatcher,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 07d3fc20983f..f6a549363955 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -52,9 +52,9 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.util.settings.SecureSettings;
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 5efe05f6db46..84e6df23e740 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
@@ -60,9 +60,9 @@ import com.android.internal.util.IntPair;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java
index cc2afe2f7b8a..a34c5986f36c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java
@@ -18,6 +18,7 @@ package com.android.systemui.util.sensors;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -60,7 +61,8 @@ public class ProximitySensorDualTest extends SysuiTestCase {
}
@Test
- public void testPrimaryBelowDoesNotInvokeSecondary() {
+ public void testInitiallyAbovePrimary() {
+
TestableListener listener = new TestableListener();
mProximitySensor.register(listener);
@@ -70,12 +72,71 @@ public class ProximitySensorDualTest extends SysuiTestCase {
assertNull(listener.mLastEvent);
assertEquals(0, listener.mCallCount);
- // Trigger primary sensor. Our secondary sensor is not registered.
mThresholdSensorPrimary.triggerEvent(false, 0);
+ assertNotNull(listener.mLastEvent);
+ assertFalse(listener.mLastEvent.getBelow());
+ assertEquals(1, listener.mCallCount);
+ }
+
+ @Test
+ public void testInitiallyBelowPrimaryAboveSecondary() {
+
+ TestableListener listener = new TestableListener();
+
+ mProximitySensor.register(listener);
+ assertTrue(mProximitySensor.isRegistered());
assertFalse(mThresholdSensorPrimary.isPaused());
assertTrue(mThresholdSensorSecondary.isPaused());
assertNull(listener.mLastEvent);
assertEquals(0, listener.mCallCount);
+
+ mThresholdSensorPrimary.triggerEvent(true, 0);
+ assertNull(listener.mLastEvent);
+ assertEquals(0, listener.mCallCount);
+
+ mThresholdSensorSecondary.triggerEvent(false, 1);
+ assertNotNull(listener.mLastEvent);
+ assertFalse(listener.mLastEvent.getBelow());
+ assertEquals(1, listener.mCallCount);
+ }
+
+ @Test
+ public void testInitiallyBelowPrimaryAndSecondary() {
+
+ TestableListener listener = new TestableListener();
+
+ mProximitySensor.register(listener);
+ assertTrue(mProximitySensor.isRegistered());
+ assertFalse(mThresholdSensorPrimary.isPaused());
+ assertTrue(mThresholdSensorSecondary.isPaused());
+ assertNull(listener.mLastEvent);
+ assertEquals(0, listener.mCallCount);
+
+ mThresholdSensorPrimary.triggerEvent(true, 0);
+ assertNull(listener.mLastEvent);
+ assertEquals(0, listener.mCallCount);
+
+ mThresholdSensorSecondary.triggerEvent(true, 1);
+ assertNotNull(listener.mLastEvent);
+ assertTrue(listener.mLastEvent.getBelow());
+ assertEquals(1, listener.mCallCount);
+ }
+
+ @Test
+ public void testPrimaryBelowDoesNotInvokeSecondary() {
+ TestableListener listener = new TestableListener();
+
+ mProximitySensor.register(listener);
+ assertTrue(mProximitySensor.isRegistered());
+ assertFalse(mThresholdSensorPrimary.isPaused());
+ assertTrue(mThresholdSensorSecondary.isPaused());
+ assertNull(listener.mLastEvent);
+ assertEquals(0, listener.mCallCount);
+
+ // Trigger primary sensor. Our secondary sensor is not registered.
+ mThresholdSensorPrimary.triggerEvent(false, 0);
+ assertFalse(mThresholdSensorPrimary.isPaused());
+ assertTrue(mThresholdSensorSecondary.isPaused());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java
index 69764227040b..7bb26748a9d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java
@@ -31,6 +31,7 @@ public class FakeSettings implements SecureSettings, GlobalSettings, SystemSetti
private final Map<SettingsKey, String> mValues = new HashMap<>();
private final Map<SettingsKey, List<ContentObserver>> mContentObservers =
new HashMap<>();
+ private final Map<String, List<ContentObserver>> mContentObserversAllUsers = new HashMap<>();
public static final Uri CONTENT_URI = Uri.parse("content://settings/fake");
@@ -55,9 +56,15 @@ public class FakeSettings implements SecureSettings, GlobalSettings, SystemSetti
@Override
public void registerContentObserverForUser(Uri uri, boolean notifyDescendents,
ContentObserver settingsObserver, int userHandle) {
- SettingsKey key = new SettingsKey(userHandle, uri.toString());
- mContentObservers.putIfAbsent(key, new ArrayList<>());
- List<ContentObserver> observers = mContentObservers.get(key);
+ List<ContentObserver> observers;
+ if (userHandle == UserHandle.USER_ALL) {
+ mContentObserversAllUsers.putIfAbsent(uri.toString(), new ArrayList<>());
+ observers = mContentObserversAllUsers.get(uri.toString());
+ } else {
+ SettingsKey key = new SettingsKey(userHandle, uri.toString());
+ mContentObservers.putIfAbsent(key, new ArrayList<>());
+ observers = mContentObservers.get(key);
+ }
observers.add(settingsObserver);
}
@@ -67,6 +74,10 @@ public class FakeSettings implements SecureSettings, GlobalSettings, SystemSetti
List<ContentObserver> observers = mContentObservers.get(key);
observers.remove(settingsObserver);
}
+ for (String key : mContentObserversAllUsers.keySet()) {
+ List<ContentObserver> observers = mContentObserversAllUsers.get(key);
+ observers.remove(settingsObserver);
+ }
}
@Override
@@ -114,6 +125,10 @@ public class FakeSettings implements SecureSettings, GlobalSettings, SystemSetti
for (ContentObserver observer : mContentObservers.getOrDefault(key, new ArrayList<>())) {
observer.dispatchChange(false, List.of(uri), userHandle);
}
+ for (ContentObserver observer :
+ mContentObserversAllUsers.getOrDefault(uri.toString(), new ArrayList<>())) {
+ observer.dispatchChange(false, List.of(uri), userHandle);
+ }
return true;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java
index 0d560f237a07..34cae58d30e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java
@@ -25,6 +25,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.database.ContentObserver;
+import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
@@ -89,6 +90,16 @@ public class FakeSettingsTest extends SysuiTestCase {
}
@Test
+ public void testRegisterContentObserverAllUsers() {
+ mFakeSettings.registerContentObserverForUser(
+ mFakeSettings.getUriFor("cat"), false, mContentObserver, UserHandle.USER_ALL);
+
+ mFakeSettings.putString("cat", "hat");
+
+ verify(mContentObserver).dispatchChange(anyBoolean(), any(Collection.class), anyInt());
+ }
+
+ @Test
public void testUnregisterContentObserver() {
mFakeSettings.registerContentObserver("cat", mContentObserver);
mFakeSettings.unregisterContentObserver(mContentObserver);
@@ -98,4 +109,16 @@ public class FakeSettingsTest extends SysuiTestCase {
verify(mContentObserver, never()).dispatchChange(
anyBoolean(), any(Collection.class), anyInt());
}
+
+ @Test
+ public void testUnregisterContentObserverAllUsers() {
+ mFakeSettings.registerContentObserverForUser(
+ mFakeSettings.getUriFor("cat"), false, mContentObserver, UserHandle.USER_ALL);
+ mFakeSettings.unregisterContentObserver(mContentObserver);
+
+ mFakeSettings.putString("cat", "hat");
+
+ verify(mContentObserver, never()).dispatchChange(
+ anyBoolean(), any(Collection.class), anyInt());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index a0b93ad25b8b..9f755f7be2c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -76,11 +76,11 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
import com.android.systemui.statusbar.RankingBuilder;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index b0dd73ada7cf..a3bbb26c6b23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -64,10 +64,10 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index b05dffef9c53..244f35700d8b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -499,6 +499,9 @@ public class AccessibilityWindowManager {
if (oldWindow.displayId != newWindow.displayId) {
return true;
}
+ if (oldWindow.taskId != newWindow.taskId) {
+ return true;
+ }
return false;
}
@@ -699,6 +702,7 @@ public class AccessibilityWindowManager {
reportedWindow.setAnchorId(window.accessibilityIdOfAnchor);
reportedWindow.setPictureInPicture(window.inPictureInPicture);
reportedWindow.setDisplayId(window.displayId);
+ reportedWindow.setTaskId(window.taskId);
final int parentId = findWindowIdLocked(userId, window.parentToken);
if (parentId >= 0) {
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
index cd332a68fa88..4946ad442b0a 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -125,7 +125,7 @@ public class AppPredictionPerUserService extends
// connect with remote AppPredictionService instead for dark launch
usesPeopleService = false;
}
- final boolean serviceExists = resolveService(sessionId, false,
+ final boolean serviceExists = resolveService(sessionId, true,
usesPeopleService, s -> s.onCreatePredictionSession(context, sessionId));
if (serviceExists && !mSessionInfos.containsKey(sessionId)) {
final AppPredictionSessionInfo sessionInfo = new AppPredictionSessionInfo(
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 85ff2be43be4..b7c61a0d25cf 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -2505,6 +2505,16 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
mContext.sendBroadcastAsUser(intent, UserHandle.ALL, null, getTempAllowlistBroadcastOptions());
}
+ private boolean isBleState(int state) {
+ switch (state) {
+ case BluetoothAdapter.STATE_BLE_ON:
+ case BluetoothAdapter.STATE_BLE_TURNING_ON:
+ case BluetoothAdapter.STATE_BLE_TURNING_OFF:
+ return true;
+ }
+ return false;
+ }
+
@RequiresPermission(allOf = {
android.Manifest.permission.BLUETOOTH_CONNECT,
android.Manifest.permission.BLUETOOTH_PRIVILEGED,
@@ -2527,8 +2537,15 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
sendBluetoothServiceDownCallback();
unbindAndFinish();
sendBleStateChanged(prevState, newState);
- // Don't broadcast as it has already been broadcast before
- isStandardBroadcast = false;
+
+ /* Currently, the OFF intent is broadcasted externally only when we transition
+ * from TURNING_OFF to BLE_ON state. So if the previous state is a BLE state,
+ * we are guaranteed that the OFF intent has been broadcasted earlier and we
+ * can safely skip it.
+ * Conversely, if the previous state is not a BLE state, it indicates that some
+ * sort of crash has occurred, moving us directly to STATE_OFF without ever
+ * passing through BLE_ON. We should broadcast the OFF intent in this case. */
+ isStandardBroadcast = !isBleState(prevState);
} else if (!intermediate_off) {
// connect to GattService
@@ -2581,6 +2598,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
// Show prevState of BLE_ON as OFF to standard users
prevState = BluetoothAdapter.STATE_OFF;
}
+ if (DBG) {
+ Slog.d(TAG,
+ "Sending State Change: " + BluetoothAdapter.nameForState(prevState) + " > "
+ + BluetoothAdapter.nameForState(newState));
+ }
Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index 019e4ea207ef..422e8ae14862 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -21,8 +21,6 @@ import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
import static android.app.ActivityManager.RunningServiceInfo;
import static android.app.ActivityManager.RunningTaskInfo;
-import static android.app.ActivityManager.getCurrentUser;
-import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_PHONE_CALL_CAMERA;
@@ -383,17 +381,9 @@ public final class SensorPrivacyService extends SystemService {
int sensor;
if (result == MODE_IGNORED) {
- if (code == OP_RECORD_AUDIO) {
+ if (code == OP_RECORD_AUDIO || code == OP_PHONE_CALL_MICROPHONE) {
sensor = MICROPHONE;
- } else if (code == OP_CAMERA) {
- sensor = CAMERA;
- } else {
- return;
- }
- } else if (result == MODE_ALLOWED) {
- if (code == OP_PHONE_CALL_MICROPHONE) {
- sensor = MICROPHONE;
- } else if (code == OP_PHONE_CALL_CAMERA) {
+ } else if (code == OP_CAMERA || code == OP_PHONE_CALL_CAMERA) {
sensor = CAMERA;
} else {
return;
@@ -423,6 +413,12 @@ public final class SensorPrivacyService extends SystemService {
return;
}
+ if (uid == Process.SYSTEM_UID) {
+ // If the system uid is being blamed for sensor access, the ui must be shown
+ // explicitly using SensorPrivacyManager#showSensorUseDialog
+ return;
+ }
+
synchronized (mLock) {
if (mSuppressReminders.containsKey(new Pair<>(sensor, user))) {
Log.d(TAG,
@@ -431,11 +427,6 @@ public final class SensorPrivacyService extends SystemService {
}
}
- if (uid == Process.SYSTEM_UID) {
- enqueueSensorUseReminderDialogAsync(-1, user, packageName, sensor);
- return;
- }
-
// TODO: Handle reminders with multiple sensors
// - If we have a likely activity that triggered the sensor use overlay a dialog over
@@ -718,6 +709,9 @@ public final class SensorPrivacyService extends SystemService {
public void setIndividualSensorPrivacy(@UserIdInt int userId,
@SensorPrivacyManager.Sources.Source int source, int sensor, boolean enable) {
enforceManageSensorPrivacyPermission();
+ if (userId == UserHandle.USER_CURRENT) {
+ userId = mCurrentUser;
+ }
if (!canChangeIndividualSensorPrivacy(userId, sensor)) {
return;
}
@@ -843,6 +837,9 @@ public final class SensorPrivacyService extends SystemService {
public void setIndividualSensorPrivacyForProfileGroup(@UserIdInt int userId,
@SensorPrivacyManager.Sources.Source int source, int sensor, boolean enable) {
enforceManageSensorPrivacyPermission();
+ if (userId == UserHandle.USER_CURRENT) {
+ userId = mCurrentUser;
+ }
int parentId = mUserManagerInternal.getProfileParentId(userId);
forAllUsers(userId2 -> {
if (parentId == mUserManagerInternal.getProfileParentId(userId2)) {
@@ -896,6 +893,9 @@ public final class SensorPrivacyService extends SystemService {
@Override
public boolean isIndividualSensorPrivacyEnabled(@UserIdInt int userId, int sensor) {
enforceObserveSensorPrivacyPermission();
+ if (userId == UserHandle.USER_CURRENT) {
+ userId = mCurrentUser;
+ }
synchronized (mLock) {
return isIndividualSensorPrivacyEnabledLocked(userId, sensor);
}
@@ -1213,6 +1213,9 @@ public final class SensorPrivacyService extends SystemService {
public void suppressIndividualSensorPrivacyReminders(int userId, int sensor,
IBinder token, boolean suppress) {
enforceManageSensorPrivacyPermission();
+ if (userId == UserHandle.USER_CURRENT) {
+ userId = mCurrentUser;
+ }
Objects.requireNonNull(token);
Pair<Integer, UserHandle> key = new Pair<>(sensor, UserHandle.of(userId));
@@ -1239,6 +1242,18 @@ public final class SensorPrivacyService extends SystemService {
}
}
+ @Override
+ public void showSensorUseDialog(int sensor) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Can only be called by the system uid");
+ }
+ if (!isIndividualSensorPrivacyEnabled(mCurrentUser, sensor)) {
+ return;
+ }
+ enqueueSensorUseReminderDialogAsync(
+ -1, UserHandle.of(mCurrentUser), "android", sensor);
+ }
+
private void userSwitching(int from, int to) {
boolean micState;
boolean camState;
@@ -1265,10 +1280,14 @@ public final class SensorPrivacyService extends SystemService {
case MICROPHONE:
mAppOpsManagerInternal.setGlobalRestriction(OP_RECORD_AUDIO, enabled,
mAppOpsRestrictionToken);
+ mAppOpsManagerInternal.setGlobalRestriction(OP_PHONE_CALL_MICROPHONE, enabled,
+ mAppOpsRestrictionToken);
break;
case CAMERA:
mAppOpsManagerInternal.setGlobalRestriction(OP_CAMERA, enabled,
mAppOpsRestrictionToken);
+ mAppOpsManagerInternal.setGlobalRestriction(OP_PHONE_CALL_CAMERA, enabled,
+ mAppOpsRestrictionToken);
break;
}
}
@@ -1898,9 +1917,9 @@ public final class SensorPrivacyService extends SystemService {
if (!mIsInEmergencyCall) {
mIsInEmergencyCall = true;
if (mSensorPrivacyServiceImpl
- .isIndividualSensorPrivacyEnabled(getCurrentUser(), MICROPHONE)) {
+ .isIndividualSensorPrivacyEnabled(mCurrentUser, MICROPHONE)) {
mSensorPrivacyServiceImpl.setIndividualSensorPrivacyUnchecked(
- getCurrentUser(), OTHER, MICROPHONE, false);
+ mCurrentUser, OTHER, MICROPHONE, false);
mMicUnmutedForEmergencyCall = true;
} else {
mMicUnmutedForEmergencyCall = false;
@@ -1915,7 +1934,7 @@ public final class SensorPrivacyService extends SystemService {
mIsInEmergencyCall = false;
if (mMicUnmutedForEmergencyCall) {
mSensorPrivacyServiceImpl.setIndividualSensorPrivacyUnchecked(
- getCurrentUser(), OTHER, MICROPHONE, true);
+ mCurrentUser, OTHER, MICROPHONE, true);
mMicUnmutedForEmergencyCall = false;
}
}
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 85eadf5a5137..10071309bc0d 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -1168,8 +1168,8 @@ final class UiModeManagerService extends SystemService {
private boolean doesPackageHaveCallingUid(@NonNull String packageName) {
try {
- return getContext().getPackageManager().getPackageUid(packageName, 0)
- == mInjector.getCallingUid();
+ return getContext().getPackageManager().getPackageUidAsUser(packageName,
+ UserHandle.getCallingUserId()) == mInjector.getCallingUid();
} catch (PackageManager.NameNotFoundException e) {
return false;
}
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index d483f1863258..a03425c0bb75 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -26,6 +26,8 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.IVpnManager;
@@ -312,6 +314,26 @@ public class VpnManagerService extends IVpnManager.Stub {
}
}
+ // TODO : Move to a static lib to factorize with Vpn.java
+ private int getAppUid(final String app, final int userId) {
+ final PackageManager pm = mContext.getPackageManager();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return pm.getPackageUidAsUser(app, userId);
+ } catch (NameNotFoundException e) {
+ return -1;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ private void verifyCallingUidAndPackage(String packageName, int callingUid) {
+ final int userId = UserHandle.getUserId(callingUid);
+ if (getAppUid(packageName, userId) != callingUid) {
+ throw new SecurityException(packageName + " does not belong to uid " + callingUid);
+ }
+ }
+
/**
* Starts the VPN based on the stored profile for the given package
*
@@ -323,7 +345,9 @@ public class VpnManagerService extends IVpnManager.Stub {
*/
@Override
public void startVpnProfile(@NonNull String packageName) {
- final int user = UserHandle.getUserId(mDeps.getCallingUid());
+ final int callingUid = Binder.getCallingUid();
+ verifyCallingUidAndPackage(packageName, callingUid);
+ final int user = UserHandle.getUserId(callingUid);
synchronized (mVpns) {
throwIfLockdownEnabled();
mVpns.get(user).startVpnProfile(packageName);
@@ -340,7 +364,9 @@ public class VpnManagerService extends IVpnManager.Stub {
*/
@Override
public void stopVpnProfile(@NonNull String packageName) {
- final int user = UserHandle.getUserId(mDeps.getCallingUid());
+ final int callingUid = Binder.getCallingUid();
+ verifyCallingUidAndPackage(packageName, callingUid);
+ final int user = UserHandle.getUserId(callingUid);
synchronized (mVpns) {
mVpns.get(user).stopVpnProfile(packageName);
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 07847f1df053..f41036cde433 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -102,6 +102,7 @@ import android.app.usage.UsageEvents;
import android.appwidget.AppWidgetManagerInternal;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
+import android.compat.annotation.Overridable;
import android.content.ComponentName;
import android.content.ComponentName.WithComponentName;
import android.content.Context;
@@ -307,6 +308,7 @@ public final class ActiveServices {
*/
@ChangeId
@EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
+ @Overridable
static final long FGS_BG_START_RESTRICTION_CHANGE_ID = 170668199L;
/**
@@ -805,10 +807,12 @@ public final class ActiveServices {
if (fgRequired) {
// We are now effectively running a foreground service.
- ServiceState stracker = r.getTracker();
- if (stracker != null) {
- stracker.setForeground(true, mAm.mProcessStats.getMemFactorLocked(),
- r.lastActivity);
+ synchronized (mAm.mProcessStats.mLock) {
+ final ServiceState stracker = r.getTracker();
+ if (stracker != null) {
+ stracker.setForeground(true, mAm.mProcessStats.getMemFactorLocked(),
+ r.lastActivity);
+ }
}
mAm.mAppOpsService.startOperation(AppOpsManager.getToken(mAm.mAppOpsService),
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null,
@@ -1080,9 +1084,11 @@ public final class ActiveServices {
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
- ServiceState stracker = r.getTracker();
- if (stracker != null) {
- stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
+ synchronized (mAm.mProcessStats.mLock) {
+ final ServiceState stracker = r.getTracker();
+ if (stracker != null) {
+ stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
+ }
}
r.callStart = false;
@@ -1142,8 +1148,10 @@ public final class ActiveServices {
mAm.mBatteryStatsService.noteServiceStopRunning(uid, packageName, serviceName);
service.startRequested = false;
if (service.tracker != null) {
- service.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
- SystemClock.uptimeMillis());
+ synchronized (mAm.mProcessStats.mLock) {
+ service.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
+ SystemClock.uptimeMillis());
+ }
}
service.callStart = false;
@@ -1318,8 +1326,10 @@ public final class ActiveServices {
mAm.mBatteryStatsService.noteServiceStopRunning(uid, packageName, serviceName);
r.startRequested = false;
if (r.tracker != null) {
- r.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
- SystemClock.uptimeMillis());
+ synchronized (mAm.mProcessStats.mLock) {
+ r.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
+ SystemClock.uptimeMillis());
+ }
}
r.callStart = false;
final long origId = Binder.clearCallingIdentity();
@@ -1875,10 +1885,12 @@ public final class ActiveServices {
r.mStartForegroundCount++;
r.mFgsEnterTime = SystemClock.uptimeMillis();
if (!stopProcStatsOp) {
- ServiceState stracker = r.getTracker();
- if (stracker != null) {
- stracker.setForeground(true,
- mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
+ synchronized (mAm.mProcessStats.mLock) {
+ final ServiceState stracker = r.getTracker();
+ if (stracker != null) {
+ stracker.setForeground(true,
+ mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
+ }
}
} else {
stopProcStatsOp = false;
@@ -1913,10 +1925,12 @@ public final class ActiveServices {
if (stopProcStatsOp) {
// We got through to this point with it actively being started foreground,
// and never decided we wanted to keep it like that, so drop it.
- ServiceState stracker = r.getTracker();
- if (stracker != null) {
- stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),
- SystemClock.uptimeMillis());
+ synchronized (mAm.mProcessStats.mLock) {
+ final ServiceState stracker = r.getTracker();
+ if (stracker != null) {
+ stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),
+ SystemClock.uptimeMillis());
+ }
}
}
if (alreadyStartedOp) {
@@ -1958,10 +1972,12 @@ public final class ActiveServices {
r.isForeground = false;
r.mFgsExitTime = SystemClock.uptimeMillis();
- ServiceState stracker = r.getTracker();
- if (stracker != null) {
- stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),
- SystemClock.uptimeMillis());
+ synchronized (mAm.mProcessStats.mLock) {
+ final ServiceState stracker = r.getTracker();
+ if (stracker != null) {
+ stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(),
+ SystemClock.uptimeMillis());
+ }
}
mAm.mAppOpsService.finishOperation(
AppOpsManager.getToken(mAm.mAppOpsService),
@@ -2736,10 +2752,12 @@ public final class ActiveServices {
s.lastActivity = SystemClock.uptimeMillis();
if (!s.hasAutoCreateConnections()) {
// This is the first binding, let the tracker know.
- ServiceState stracker = s.getTracker();
- if (stracker != null) {
- stracker.setBound(true, mAm.mProcessStats.getMemFactorLocked(),
- s.lastActivity);
+ synchronized (mAm.mProcessStats.mLock) {
+ final ServiceState stracker = s.getTracker();
+ if (stracker != null) {
+ stracker.setBound(true, mAm.mProcessStats.getMemFactorLocked(),
+ s.lastActivity);
+ }
}
}
}
@@ -3376,9 +3394,11 @@ public final class ActiveServices {
ProcessServiceRecord psr;
if (r.executeNesting == 0) {
r.executeFg = fg;
- ServiceState stracker = r.getTracker();
- if (stracker != null) {
- stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
+ synchronized (mAm.mProcessStats.mLock) {
+ final ServiceState stracker = r.getTracker();
+ if (stracker != null) {
+ stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
+ }
}
if (r.app != null) {
psr = r.app.mServices;
@@ -3573,7 +3593,9 @@ public final class ActiveServices {
if (!mRestartingServices.contains(r)) {
r.createdFromFg = false;
mRestartingServices.add(r);
- r.makeRestarting(mAm.mProcessStats.getMemFactorLocked(), now);
+ synchronized (mAm.mProcessStats.mLock) {
+ r.makeRestarting(mAm.mProcessStats.getMemFactorLocked(), now);
+ }
}
cancelForegroundNotificationLocked(r);
@@ -3651,8 +3673,10 @@ public final class ActiveServices {
}
}
if (!stillTracking) {
- r.restartTracker.setRestarting(false, mAm.mProcessStats.getMemFactorLocked(),
- SystemClock.uptimeMillis());
+ synchronized (mAm.mProcessStats.mLock) {
+ r.restartTracker.setRestarting(false, mAm.mProcessStats.getMemFactorLocked(),
+ SystemClock.uptimeMillis());
+ }
r.restartTracker = null;
}
}
@@ -4172,9 +4196,11 @@ public final class ActiveServices {
+ r);
r.fgRequired = false;
r.fgWaiting = false;
- ServiceState stracker = r.getTracker();
- if (stracker != null) {
- stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(), now);
+ synchronized (mAm.mProcessStats.mLock) {
+ ServiceState stracker = r.getTracker();
+ if (stracker != null) {
+ stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(), now);
+ }
}
mAm.mAppOpsService.finishOperation(AppOpsManager.getToken(mAm.mAppOpsService),
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null);
@@ -4231,9 +4257,11 @@ public final class ActiveServices {
cancelForegroundNotificationLocked(r);
if (r.isForeground) {
decActiveForegroundAppLocked(smap, r);
- ServiceState stracker = r.getTracker();
- if (stracker != null) {
- stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(), now);
+ synchronized (mAm.mProcessStats.mLock) {
+ ServiceState stracker = r.getTracker();
+ if (stracker != null) {
+ stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(), now);
+ }
}
mAm.mAppOpsService.finishOperation(
AppOpsManager.getToken(mAm.mAppOpsService),
@@ -4301,13 +4329,15 @@ public final class ActiveServices {
((ServiceRestarter)r.restarter).setService(null);
}
- int memFactor = mAm.mProcessStats.getMemFactorLocked();
- if (r.tracker != null) {
- r.tracker.setStarted(false, memFactor, now);
- r.tracker.setBound(false, memFactor, now);
- if (r.executeNesting == 0) {
- r.tracker.clearCurrentOwner(r, false);
- r.tracker = null;
+ synchronized (mAm.mProcessStats.mLock) {
+ final int memFactor = mAm.mProcessStats.getMemFactorLocked();
+ if (r.tracker != null) {
+ r.tracker.setStarted(false, memFactor, now);
+ r.tracker.setBound(false, memFactor, now);
+ if (r.executeNesting == 0) {
+ r.tracker.clearCurrentOwner(r, false);
+ r.tracker = null;
+ }
}
}
@@ -4438,8 +4468,10 @@ public final class ActiveServices {
boolean hasAutoCreate = s.hasAutoCreateConnections();
if (!hasAutoCreate) {
if (s.tracker != null) {
- s.tracker.setBound(false, mAm.mProcessStats.getMemFactorLocked(),
- SystemClock.uptimeMillis());
+ synchronized (mAm.mProcessStats.mLock) {
+ s.tracker.setBound(false, mAm.mProcessStats.getMemFactorLocked(),
+ SystemClock.uptimeMillis());
+ }
}
}
bringDownServiceIfNeededLocked(s, true, hasAutoCreate, enqueueOomAdj);
@@ -4531,12 +4563,14 @@ public final class ActiveServices {
private void serviceProcessGoneLocked(ServiceRecord r, boolean enqueueOomAdj) {
if (r.tracker != null) {
- int memFactor = mAm.mProcessStats.getMemFactorLocked();
- long now = SystemClock.uptimeMillis();
- r.tracker.setExecuting(false, memFactor, now);
- r.tracker.setForeground(false, memFactor, now);
- r.tracker.setBound(false, memFactor, now);
- r.tracker.setStarted(false, memFactor, now);
+ synchronized (mAm.mProcessStats.mLock) {
+ final int memFactor = mAm.mProcessStats.getMemFactorLocked();
+ final long now = SystemClock.uptimeMillis();
+ r.tracker.setExecuting(false, memFactor, now);
+ r.tracker.setForeground(false, memFactor, now);
+ r.tracker.setBound(false, memFactor, now);
+ r.tracker.setStarted(false, memFactor, now);
+ }
}
serviceDoneExecutingLocked(r, true, true, enqueueOomAdj);
}
@@ -4583,13 +4617,15 @@ public final class ActiveServices {
}
r.executeFg = false;
if (r.tracker != null) {
- final int memFactor = mAm.mProcessStats.getMemFactorLocked();
- final long now = SystemClock.uptimeMillis();
- r.tracker.setExecuting(false, memFactor, now);
- r.tracker.setForeground(false, memFactor, now);
- if (finishing) {
- r.tracker.clearCurrentOwner(r, false);
- r.tracker = null;
+ synchronized (mAm.mProcessStats.mLock) {
+ final int memFactor = mAm.mProcessStats.getMemFactorLocked();
+ final long now = SystemClock.uptimeMillis();
+ r.tracker.setExecuting(false, memFactor, now);
+ r.tracker.setForeground(false, memFactor, now);
+ if (finishing) {
+ r.tracker.clearCurrentOwner(r, false);
+ r.tracker = null;
+ }
}
}
if (finishing) {
@@ -4974,8 +5010,10 @@ public final class ActiveServices {
// down it.
sr.startRequested = false;
if (sr.tracker != null) {
- sr.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
- SystemClock.uptimeMillis());
+ synchronized (mAm.mProcessStats.mLock) {
+ sr.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
+ SystemClock.uptimeMillis());
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 9dbb70757cf7..f32aa2295cb8 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -41,6 +41,7 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.ProcLocksReader;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.ServiceThread;
@@ -100,7 +101,7 @@ public final class CachedAppOptimizer {
// Defaults for phenotype flags.
@VisibleForTesting static final Boolean DEFAULT_USE_COMPACTION = false;
- @VisibleForTesting static final Boolean DEFAULT_USE_FREEZER = false;
+ @VisibleForTesting static final Boolean DEFAULT_USE_FREEZER = true;
@VisibleForTesting static final int DEFAULT_COMPACT_ACTION_1 = COMPACT_ACTION_FILE;
@VisibleForTesting static final int DEFAULT_COMPACT_ACTION_2 = COMPACT_ACTION_FULL;
@VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_1 = 5_000;
@@ -275,7 +276,7 @@ public final class CachedAppOptimizer {
DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ;
@GuardedBy("mPhenotypeFlagLock")
private volatile boolean mUseCompaction = DEFAULT_USE_COMPACTION;
- private volatile boolean mUseFreezer = DEFAULT_USE_FREEZER;
+ private volatile boolean mUseFreezer = false; // set to DEFAULT in init()
@GuardedBy("this")
private int mFreezerDisableCount = 1; // Freezer is initially disabled, until enabled
private final Random mRandom = new Random();
@@ -319,6 +320,7 @@ public final class CachedAppOptimizer {
private int mPersistentCompactionCount;
private int mBfgsCompactionCount;
private final ProcessDependencies mProcessDependencies;
+ private final ProcLocksReader mProcLocksReader;
public CachedAppOptimizer(ActivityManagerService am) {
this(am, null, new DefaultProcessDependencies());
@@ -335,6 +337,7 @@ public final class CachedAppOptimizer {
mProcessDependencies = processDependencies;
mTestCallback = callback;
mSettingsObserver = new SettingsContentObserver();
+ mProcLocksReader = new ProcLocksReader();
}
/**
@@ -675,6 +678,8 @@ public final class CachedAppOptimizer {
KEY_USE_FREEZER, DEFAULT_USE_FREEZER)) {
mUseFreezer = isFreezerSupported();
updateFreezerDebounceTimeout();
+ } else {
+ mUseFreezer = false;
}
final boolean useFreezer = mUseFreezer;
@@ -1312,7 +1317,7 @@ public final class CachedAppOptimizer {
try {
// pre-check for locks to avoid unnecessary freeze/unfreeze operations
- if (Process.hasFileLocks(pid)) {
+ if (mProcLocksReader.hasFileLocks(pid)) {
if (DEBUG_FREEZER) {
Slog.d(TAG_AM, name + " (" + pid + ") holds file locks, not freezing");
}
@@ -1399,7 +1404,7 @@ public final class CachedAppOptimizer {
try {
// post-check to prevent races
- if (Process.hasFileLocks(pid)) {
+ if (mProcLocksReader.hasFileLocks(pid)) {
if (DEBUG_FREEZER) {
Slog.d(TAG_AM, name + " (" + pid + ") holds file locks, reverting freeze");
}
diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
index e6cd509f50dc..916127126117 100644
--- a/services/core/java/com/android/server/am/ConnectionRecord.java
+++ b/services/core/java/com/android/server/am/ConnectionRecord.java
@@ -47,6 +47,7 @@ final class ConnectionRecord {
public AssociationState.SourceState association; // Association tracking
String stringName; // Caching of toString.
boolean serviceDead; // Well is it?
+ private Object mProcStatsLock; // Internal lock for accessing AssociationState
// Please keep the following two enum list synced.
private static final int[] BIND_ORIG_ENUMS = new int[] {
@@ -137,23 +138,29 @@ final class ConnectionRecord {
Slog.wtf(TAG_AM, "Inactive holder in referenced service "
+ binding.service.shortInstanceName + ": proc=" + binding.service.app);
} else {
- association = holder.pkg.getAssociationStateLocked(holder.state,
- binding.service.instanceName.getClassName()).startSource(clientUid,
- clientProcessName, clientPackageName);
-
+ mProcStatsLock = binding.service.app.mService.mProcessStats.mLock;
+ synchronized (mProcStatsLock) {
+ association = holder.pkg.getAssociationStateLocked(holder.state,
+ binding.service.instanceName.getClassName()).startSource(clientUid,
+ clientProcessName, clientPackageName);
+ }
}
}
}
public void trackProcState(int procState, int seq, long now) {
if (association != null) {
- association.trackProcState(procState, seq, now);
+ synchronized (mProcStatsLock) {
+ association.trackProcState(procState, seq, now);
+ }
}
}
public void stopAssociation() {
if (association != null) {
- association.stop();
+ synchronized (mProcStatsLock) {
+ association.stop();
+ }
association = null;
}
}
diff --git a/services/core/java/com/android/server/am/ContentProviderConnection.java b/services/core/java/com/android/server/am/ContentProviderConnection.java
index 3bc4fcf08921..3b9d47d509ad 100644
--- a/services/core/java/com/android/server/am/ContentProviderConnection.java
+++ b/services/core/java/com/android/server/am/ContentProviderConnection.java
@@ -38,6 +38,7 @@ public final class ContentProviderConnection extends Binder {
public final String clientPackage;
public AssociationState.SourceState association;
public final long createTime;
+ private Object mProcStatsLock; // Internal lock for accessing AssociationState
/**
* Internal lock that guards access to the two counters.
@@ -87,23 +88,29 @@ public final class ContentProviderConnection extends Binder {
Slog.wtf(TAG_AM, "Inactive holder in referenced provider "
+ provider.name.toShortString() + ": proc=" + provider.proc);
} else {
- association = holder.pkg.getAssociationStateLocked(holder.state,
- provider.name.getClassName()).startSource(client.uid, client.processName,
- clientPackage);
-
+ mProcStatsLock = provider.proc.mService.mProcessStats.mLock;
+ synchronized (mProcStatsLock) {
+ association = holder.pkg.getAssociationStateLocked(holder.state,
+ provider.name.getClassName()).startSource(client.uid,
+ client.processName, clientPackage);
+ }
}
}
}
public void trackProcState(int procState, int seq, long now) {
if (association != null) {
- association.trackProcState(procState, seq, now);
+ synchronized (mProcStatsLock) {
+ association.trackProcState(procState, seq, now);
+ }
}
}
public void stopAssociation() {
if (association != null) {
- association.stop();
+ synchronized (mProcStatsLock) {
+ association.stop();
+ }
association = null;
}
}
diff --git a/services/core/java/com/android/server/am/ContentProviderRecord.java b/services/core/java/com/android/server/am/ContentProviderRecord.java
index 5fd15db79d66..75f31c0ac29f 100644
--- a/services/core/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/core/java/com/android/server/am/ContentProviderRecord.java
@@ -321,6 +321,7 @@ final class ContentProviderRecord implements ComponentName.WithComponentName {
final String mOwningProcessName;
int mAcquisitionCount;
AssociationState.SourceState mAssociation;
+ private Object mProcStatsLock; // Internal lock for accessing AssociationState
public ExternalProcessHandle(IBinder token, int owningUid, String owningProcessName) {
mToken = token;
@@ -353,17 +354,21 @@ final class ContentProviderRecord implements ComponentName.WithComponentName {
Slog.wtf(TAG_AM, "Inactive holder in referenced provider "
+ provider.name.toShortString() + ": proc=" + provider.proc);
} else {
- mAssociation = holder.pkg.getAssociationStateLocked(holder.state,
- provider.name.getClassName()).startSource(mOwningUid,
- mOwningProcessName, null);
-
+ mProcStatsLock = provider.proc.mService.mProcessStats.mLock;
+ synchronized (mProcStatsLock) {
+ mAssociation = holder.pkg.getAssociationStateLocked(holder.state,
+ provider.name.getClassName()).startSource(mOwningUid,
+ mOwningProcessName, null);
+ }
}
}
}
public void stopAssociation() {
if (mAssociation != null) {
- mAssociation.stop();
+ synchronized (mProcStatsLock) {
+ mAssociation.stop();
+ }
mAssociation = null;
}
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index d6bf8dbe0a6a..5c19ceb7067a 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -2792,8 +2792,10 @@ public class OomAdjuster {
state.setNotCachedSinceIdle(false);
}
if (!doingAll) {
- mService.setProcessTrackerStateLOSP(app,
- mService.mProcessStats.getMemFactorLocked(), now);
+ synchronized (mService.mProcessStats.mLock) {
+ mService.setProcessTrackerStateLOSP(app,
+ mService.mProcessStats.getMemFactorLocked(), now);
+ }
} else {
state.setProcStateChanged(true);
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index a9905dcf8904..64b9bd98a2fc 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -45,6 +45,9 @@ import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_PLAY_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO_HOTWORD;
+import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_FAILED;
+import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_RESUMED;
+import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_STARTED;
import static android.app.AppOpsManager.OpEventProxyInfo;
import static android.app.AppOpsManager.RestrictionBypass;
import static android.app.AppOpsManager.SAMPLING_STRATEGY_BOOT_TIME_SAMPLING;
@@ -1238,6 +1241,11 @@ public class AppOpsService extends IAppOpsService.Stub {
scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid, parent.packageName,
tag, true, event.getAttributionFlags(), event.getAttributionChainId());
}
+ // Note: this always sends MODE_ALLOWED, even if the mode is FOREGROUND
+ // TODO ntmyren: figure out how to get the real mode.
+ scheduleOpStartedIfNeededLocked(parent.op, parent.uid, parent.packageName,
+ tag, event.getFlags(), MODE_ALLOWED, START_TYPE_RESUMED,
+ event.getAttributionFlags(), event.getAttributionChainId());
}
mPausedInProgressEvents = null;
}
@@ -3438,7 +3446,7 @@ public class AppOpsService extends IAppOpsService.Stub {
+ " package " + packageName + "flags: " +
AppOpsManager.flagsToString(flags));
return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
- packageName + " flags: " + AppOpsManager.flagsToString(flags));
+ packageName);
}
final Op op = getOpLocked(ops, code, uid, true);
final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
@@ -3945,13 +3953,15 @@ public class AppOpsService extends IAppOpsService.Stub {
}
boolean isRestricted = false;
+ int startType = START_TYPE_FAILED;
synchronized (this) {
final Ops ops = getOpsLocked(uid, packageName, attributionTag,
pvr.isAttributionTagValid, pvr.bypass, /* edit */ true);
if (ops == null) {
if (!dryRun) {
scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
- flags, AppOpsManager.MODE_IGNORED);
+ flags, AppOpsManager.MODE_IGNORED, startType, attributionFlags,
+ attributionChainId);
}
if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
+ " package " + packageName + " flags: "
@@ -3977,7 +3987,7 @@ public class AppOpsService extends IAppOpsService.Stub {
if (!dryRun) {
attributedOp.rejected(uidState.state, flags);
scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
- flags, uidMode);
+ flags, uidMode, startType, attributionFlags, attributionChainId);
}
return new SyncNotedAppOp(uidMode, code, attributionTag, packageName);
}
@@ -3993,7 +4003,7 @@ public class AppOpsService extends IAppOpsService.Stub {
if (!dryRun) {
attributedOp.rejected(uidState.state, flags);
scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
- flags, mode);
+ flags, mode, startType, attributionFlags, attributionChainId);
}
return new SyncNotedAppOp(mode, code, attributionTag, packageName);
}
@@ -4011,12 +4021,14 @@ public class AppOpsService extends IAppOpsService.Stub {
attributedOp.started(clientId, proxyUid, proxyPackageName,
proxyAttributionTag, uidState.state, flags, attributionFlags,
attributionChainId);
+ startType = START_TYPE_STARTED;
}
} catch (RemoteException e) {
throw new RuntimeException(e);
}
scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag, flags,
- isRestricted ? MODE_IGNORED : MODE_ALLOWED);
+ isRestricted ? MODE_IGNORED : MODE_ALLOWED, startType, attributionFlags,
+ attributionChainId);
}
}
@@ -4187,7 +4199,9 @@ public class AppOpsService extends IAppOpsService.Stub {
}
private void scheduleOpStartedIfNeededLocked(int code, int uid, String pkgName,
- String attributionTag, @OpFlags int flags, @Mode int result) {
+ String attributionTag, @OpFlags int flags, @Mode int result,
+ @AppOpsManager.OnOpStartedListener.StartedType int startedType,
+ @AttributionFlags int attributionFlags, int attributionChainId) {
ArraySet<StartedCallback> dispatchedCallbacks = null;
final int callbackListCount = mStartedWatchers.size();
for (int i = 0; i < callbackListCount; i++) {
@@ -4213,12 +4227,13 @@ public class AppOpsService extends IAppOpsService.Stub {
mHandler.sendMessage(PooledLambda.obtainMessage(
AppOpsService::notifyOpStarted,
this, dispatchedCallbacks, code, uid, pkgName, attributionTag, flags,
- result));
+ result, startedType, attributionFlags, attributionChainId));
}
private void notifyOpStarted(ArraySet<StartedCallback> callbacks,
int code, int uid, String packageName, String attributionTag, @OpFlags int flags,
- @Mode int result) {
+ @Mode int result, @AppOpsManager.OnOpStartedListener.StartedType int startedType,
+ @AttributionFlags int attributionFlags, int attributionChainId) {
final long identity = Binder.clearCallingIdentity();
try {
final int callbackCount = callbacks.size();
@@ -4226,7 +4241,7 @@ public class AppOpsService extends IAppOpsService.Stub {
final StartedCallback callback = callbacks.valueAt(i);
try {
callback.mCallback.opStarted(code, uid, packageName, attributionTag, flags,
- result);
+ result, startedType, attributionFlags, attributionChainId);
} catch (RemoteException e) {
/* do nothing */
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index f7d091498456..34e2578f7855 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -736,6 +736,11 @@ public class AudioService extends IAudioService.Stub
private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
private long mLoweredFromNormalToVibrateTime;
+ // Uid of the active hotword detection service to check if caller is the one or not.
+ @GuardedBy("mHotwordDetectionServiceUidLock")
+ private int mHotwordDetectionServiceUid = android.os.Process.INVALID_UID;
+ private final Object mHotwordDetectionServiceUidLock = new Object();
+
// Array of Uids of valid accessibility services to check if caller is one of them
private final Object mAccessibilityServiceUidsLock = new Object();
@GuardedBy("mAccessibilityServiceUidsLock")
@@ -1337,6 +1342,9 @@ public class AudioService extends IAudioService.Stub
updateAssistantUId(true);
AudioSystem.setRttEnabled(mRttEnabled);
}
+ synchronized (mHotwordDetectionServiceUidLock) {
+ AudioSystem.setHotwordDetectionServiceUid(mHotwordDetectionServiceUid);
+ }
synchronized (mAccessibilityServiceUidsLock) {
AudioSystem.setA11yServicesUids(mAccessibilityServiceUids);
}
@@ -9108,6 +9116,16 @@ public class AudioService extends IAudioService.Stub
}
@Override
+ public void setHotwordDetectionServiceUid(int uid) {
+ synchronized (mHotwordDetectionServiceUidLock) {
+ if (mHotwordDetectionServiceUid != uid) {
+ mHotwordDetectionServiceUid = uid;
+ AudioSystem.setHotwordDetectionServiceUid(mHotwordDetectionServiceUid);
+ }
+ }
+ }
+
+ @Override
public void setAccessibilityServiceUids(IntArray uids) {
synchronized (mAccessibilityServiceUidsLock) {
if (uids.size() == 0) {
diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
index 973fbd2bba17..6d567807f357 100644
--- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java
+++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
@@ -367,6 +367,14 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback {
}
/**
+ * Same as {@link AudioSystem#setHotwordDetectionServiceUid(int)}
+ * Communicate UID of current HotwordDetectionService to audio policy service.
+ */
+ public int setHotwordDetectionServiceUid(int uid) {
+ return AudioSystem.setHotwordDetectionServiceUid(uid);
+ }
+
+ /**
* Same as {@link AudioSystem#setCurrentImeUid(int)}
* Communicate UID of current InputMethodService to audio policy service.
*/
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 4973d45293e3..b1d300cd838e 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -1106,6 +1106,11 @@ public class BiometricService extends SystemService {
return Settings.Secure.getInt(context.getContentResolver(),
CoexCoordinator.SETTING_ENABLE_NAME, 1) != 0;
}
+
+ public boolean isCoexFaceNonBypassHapticsDisabled(Context context) {
+ return Settings.Secure.getInt(context.getContentResolver(),
+ CoexCoordinator.FACE_HAPTIC_DISABLE, 1) != 0;
+ }
}
/**
@@ -1137,6 +1142,8 @@ public class BiometricService extends SystemService {
// by default.
CoexCoordinator coexCoordinator = CoexCoordinator.getInstance();
coexCoordinator.setAdvancedLogicEnabled(injector.isAdvancedCoexLogicEnabled(context));
+ coexCoordinator.setFaceHapticDisabledWhenNonBypass(
+ injector.isCoexFaceNonBypassHapticsDisabled(context));
try {
injector.getActivityManagerService().registerUserSwitchObserver(
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 013c74d10d00..6f38ed04cd96 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -54,12 +54,18 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
public static final int STATE_NEW = 0;
// Framework/HAL have started this operation
public static final int STATE_STARTED = 1;
- // Operation is started, but requires some user action (such as finger lift & re-touch)
+ // Operation is started, but requires some user action to start (such as finger lift & re-touch)
public static final int STATE_STARTED_PAUSED = 2;
+ // Same as above, except auth was attempted (rejected, timed out, etc).
+ public static final int STATE_STARTED_PAUSED_ATTEMPTED = 3;
// Done, errored, canceled, etc. HAL/framework are not running this sensor anymore.
- public static final int STATE_STOPPED = 3;
+ public static final int STATE_STOPPED = 4;
- @IntDef({STATE_NEW, STATE_STARTED, STATE_STARTED_PAUSED, STATE_STOPPED})
+ @IntDef({STATE_NEW,
+ STATE_STARTED,
+ STATE_STARTED_PAUSED,
+ STATE_STARTED_PAUSED_ATTEMPTED,
+ STATE_STOPPED})
@interface State {}
private final boolean mIsStrongBiometric;
@@ -76,7 +82,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
private long mStartTimeMs;
- protected boolean mAuthAttempted;
+ private boolean mAuthAttempted;
// TODO: This is currently hard to maintain, as each AuthenticationClient subclass must update
// the state. We should think of a way to improve this in the future.
@@ -92,6 +98,12 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
*/
protected abstract void handleLifecycleAfterAuth(boolean authenticated);
+ /**
+ * @return true if a user was detected (i.e. face was found, fingerprint sensor was touched.
+ * etc)
+ */
+ public abstract boolean wasUserDetected();
+
public AuthenticationClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
int targetUserId, long operationId, boolean restricted, @NonNull String owner,
@@ -174,7 +186,8 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
+ ", isBP: " + isBiometricPrompt()
+ ", listener: " + listener
+ ", requireConfirmation: " + mRequireConfirmation
- + ", user: " + getTargetUserId());
+ + ", user: " + getTargetUserId()
+ + ", clientMonitor: " + toString());
final PerformanceTracker pm = PerformanceTracker.getInstanceForSensorId(getSensorId());
if (isCryptoOperation()) {
@@ -298,6 +311,11 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
public void handleLifecycleAfterAuth() {
AuthenticationClient.this.handleLifecycleAfterAuth(true /* authenticated */);
}
+
+ @Override
+ public void sendAuthenticationCanceled() {
+ sendCancelOnly(listener);
+ }
});
} else {
// Allow system-defined limit of number of attempts before giving up
@@ -332,10 +350,30 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
public void handleLifecycleAfterAuth() {
AuthenticationClient.this.handleLifecycleAfterAuth(false /* authenticated */);
}
+
+ @Override
+ public void sendAuthenticationCanceled() {
+ sendCancelOnly(listener);
+ }
});
}
}
+ private void sendCancelOnly(@Nullable ClientMonitorCallbackConverter listener) {
+ if (listener == null) {
+ Slog.e(TAG, "Unable to sendAuthenticationCanceled, listener null");
+ return;
+ }
+ try {
+ listener.onError(getSensorId(),
+ getCookie(),
+ BiometricConstants.BIOMETRIC_ERROR_CANCELED,
+ 0 /* vendorCode */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+
@Override
public void onAcquired(int acquiredInfo, int vendorCode) {
super.onAcquired(acquiredInfo, vendorCode);
@@ -349,9 +387,11 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
}
@Override
- public void onError(int errorCode, int vendorCode) {
+ public void onError(@BiometricConstants.Errors int errorCode, int vendorCode) {
super.onError(errorCode, vendorCode);
mState = STATE_STOPPED;
+
+ CoexCoordinator.getInstance().onAuthenticationError(this, errorCode, this::vibrateError);
}
/**
@@ -413,4 +453,8 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
public boolean interruptsPrecedingClients() {
return true;
}
+
+ public boolean wasAuthAttempted() {
+ return mAuthAttempted;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
index b576673111ae..25d4a38cd475 100644
--- a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
@@ -22,6 +22,7 @@ import static com.android.server.biometrics.sensors.BiometricScheduler.sensorTyp
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.hardware.biometrics.BiometricConstants;
import android.os.Handler;
import android.os.Looper;
import android.util.Slog;
@@ -45,6 +46,8 @@ public class CoexCoordinator {
private static final String TAG = "BiometricCoexCoordinator";
public static final String SETTING_ENABLE_NAME =
"com.android.server.biometrics.sensors.CoexCoordinator.enable";
+ public static final String FACE_HAPTIC_DISABLE =
+ "com.android.server.biometrics.sensors.CoexCoordinator.disable_face_haptics";
private static final boolean DEBUG = true;
// Successful authentications should be used within this amount of time.
@@ -52,7 +55,7 @@ public class CoexCoordinator {
/**
* Callback interface notifying the owner of "results" from the CoexCoordinator's business
- * logic.
+ * logic for accept and reject.
*/
interface Callback {
/**
@@ -71,6 +74,22 @@ public class CoexCoordinator {
* from scheduler if auth was successful).
*/
void handleLifecycleAfterAuth();
+
+ /**
+ * Requests the owner to notify the caller that authentication was canceled.
+ */
+ void sendAuthenticationCanceled();
+ }
+
+ /**
+ * Callback interface notifying the owner of "results" from the CoexCoordinator's business
+ * logic for errors.
+ */
+ interface ErrorCallback {
+ /**
+ * Requests the owner to initiate a vibration for this event.
+ */
+ void sendHapticFeedback();
}
private static CoexCoordinator sInstance;
@@ -144,6 +163,10 @@ public class CoexCoordinator {
mAdvancedLogicEnabled = enabled;
}
+ public void setFaceHapticDisabledWhenNonBypass(boolean disabled) {
+ mFaceHapticDisabledWhenNonBypass = disabled;
+ }
+
@VisibleForTesting
void reset() {
mClientMap.clear();
@@ -153,6 +176,7 @@ public class CoexCoordinator {
private final Map<Integer, AuthenticationClient<?>> mClientMap;
@VisibleForTesting final LinkedList<SuccessfulAuth> mSuccessfulAuths;
private boolean mAdvancedLogicEnabled;
+ private boolean mFaceHapticDisabledWhenNonBypass;
private final Handler mHandler;
private CoexCoordinator() {
@@ -191,6 +215,9 @@ public class CoexCoordinator {
mClientMap.remove(sensorType);
}
+ /**
+ * Notify the coordinator that authentication succeeded (accepted)
+ */
public void onAuthenticationSucceeded(long currentTimeMillis,
@NonNull AuthenticationClient<?> client,
@NonNull Callback callback) {
@@ -225,7 +252,11 @@ public class CoexCoordinator {
mSuccessfulAuths.add(new SuccessfulAuth(mHandler, mSuccessfulAuths,
currentTimeMillis, SENSOR_TYPE_FACE, client, callback));
} else {
- callback.sendHapticFeedback();
+ if (mFaceHapticDisabledWhenNonBypass && !face.isKeyguardBypassEnabled()) {
+ Slog.w(TAG, "Skipping face success haptic");
+ } else {
+ callback.sendHapticFeedback();
+ }
callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
callback.handleLifecycleAfterAuth();
}
@@ -257,6 +288,9 @@ public class CoexCoordinator {
}
}
+ /**
+ * Notify the coordinator that a rejection has occurred.
+ */
public void onAuthenticationRejected(long currentTimeMillis,
@NonNull AuthenticationClient<?> client,
@LockoutTracker.LockoutMode int lockoutMode,
@@ -278,12 +312,23 @@ public class CoexCoordinator {
// BiometricScheduler do not get stuck.
Slog.d(TAG, "Face rejected in multi-sensor auth, udfps: " + udfps);
callback.handleLifecycleAfterAuth();
- } else {
- // UDFPS is not actively authenticating (finger not touching, already
- // rejected, etc).
+ } else if (isUdfpsAuthAttempted(udfps)) {
+ // If UDFPS is STATE_STARTED_PAUSED (e.g. finger rejected but can still
+ // auth after pointer goes down, it means UDFPS encountered a rejection. In
+ // this case, we need to play the final reject haptic since face auth is
+ // also done now.
callback.sendHapticFeedback();
callback.handleLifecycleAfterAuth();
}
+ else {
+ // UDFPS auth has never been attempted.
+ if (mFaceHapticDisabledWhenNonBypass && !face.isKeyguardBypassEnabled()) {
+ Slog.w(TAG, "Skipping face reject haptic");
+ } else {
+ callback.sendHapticFeedback();
+ }
+ callback.handleLifecycleAfterAuth();
+ }
} else if (isCurrentUdfps(client)) {
// Face should either be running, or have already finished
SuccessfulAuth auth = popSuccessfulFaceAuthIfExists(currentTimeMillis);
@@ -330,11 +375,63 @@ public class CoexCoordinator {
}
}
+ /**
+ * Notify the coordinator that an error has occurred.
+ */
+ public void onAuthenticationError(@NonNull AuthenticationClient<?> client,
+ @BiometricConstants.Errors int error, @NonNull ErrorCallback callback) {
+ // Figure out non-coex state
+ final boolean shouldUsuallyVibrate;
+ if (isCurrentFaceAuth(client)) {
+ final boolean notDetectedOnKeyguard = client.isKeyguard() && !client.wasUserDetected();
+ final boolean authAttempted = client.wasAuthAttempted();
+
+ switch (error) {
+ case BiometricConstants.BIOMETRIC_ERROR_TIMEOUT:
+ case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT:
+ case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT:
+ shouldUsuallyVibrate = authAttempted && !notDetectedOnKeyguard;
+ break;
+ default:
+ shouldUsuallyVibrate = false;
+ break;
+ }
+ } else {
+ shouldUsuallyVibrate = false;
+ }
+
+ // Figure out coex state
+ final boolean keyguardAdvancedLogic = mAdvancedLogicEnabled && client.isKeyguard();
+ final boolean hapticSuppressedByCoex;
+
+ if (keyguardAdvancedLogic) {
+ if (isSingleAuthOnly(client)) {
+ hapticSuppressedByCoex = false;
+ } else {
+ hapticSuppressedByCoex = isCurrentFaceAuth(client)
+ && !client.isKeyguardBypassEnabled();
+ }
+ } else {
+ hapticSuppressedByCoex = false;
+ }
+
+ // Combine and send feedback if appropriate
+ Slog.d(TAG, "shouldUsuallyVibrate: " + shouldUsuallyVibrate
+ + ", hapticSuppressedByCoex: " + hapticSuppressedByCoex);
+ if (shouldUsuallyVibrate && !hapticSuppressedByCoex) {
+ callback.sendHapticFeedback();
+ }
+ }
+
@Nullable
private SuccessfulAuth popSuccessfulFaceAuthIfExists(long currentTimeMillis) {
for (SuccessfulAuth auth : mSuccessfulAuths) {
if (currentTimeMillis - auth.mAuthTimestamp >= SUCCESSFUL_AUTH_VALID_DURATION_MS) {
- Slog.d(TAG, "Removing stale auth: " + auth);
+ // TODO(b/193089985): This removes the auth but does not notify the client with
+ // an appropriate lifecycle event (such as ERROR_CANCELED), and violates the
+ // API contract. However, this might be OK for now since the validity duration
+ // is way longer than the time it takes to auth with fingerprint.
+ Slog.e(TAG, "Removing stale auth: " + auth);
mSuccessfulAuths.remove(auth);
} else if (auth.mSensorType == SENSOR_TYPE_FACE) {
mSuccessfulAuths.remove(auth);
@@ -345,9 +442,13 @@ public class CoexCoordinator {
}
private void removeAndFinishAllFaceFromQueue() {
+ // Note that these auth are all successful, but have never notified the client (e.g.
+ // keyguard). To comply with the authentication lifecycle, we must notify the client that
+ // auth is "done". The safest thing to do is to send ERROR_CANCELED.
for (SuccessfulAuth auth : mSuccessfulAuths) {
if (auth.mSensorType == SENSOR_TYPE_FACE) {
- Slog.d(TAG, "Removing from queue and finishing: " + auth);
+ Slog.d(TAG, "Removing from queue, canceling, and finishing: " + auth);
+ auth.mCallback.sendAuthenticationCanceled();
auth.mCallback.handleLifecycleAfterAuth();
mSuccessfulAuths.remove(auth);
}
@@ -374,6 +475,13 @@ public class CoexCoordinator {
return false;
}
+ private static boolean isUdfpsAuthAttempted(@Nullable AuthenticationClient<?> client) {
+ if (client instanceof Udfps) {
+ return client.getState() == AuthenticationClient.STATE_STARTED_PAUSED_ATTEMPTED;
+ }
+ return false;
+ }
+
private boolean isUnknownClient(@NonNull AuthenticationClient<?> client) {
for (AuthenticationClient<?> c : mClientMap.values()) {
if (c == client) {
@@ -400,6 +508,7 @@ public class CoexCoordinator {
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Enabled: ").append(mAdvancedLogicEnabled);
+ sb.append(", Face Haptic Disabled: ").append(mFaceHapticDisabledWhenNonBypass);
sb.append(", Queue size: " ).append(mSuccessfulAuths.size());
for (SuccessfulAuth auth : mSuccessfulAuths) {
sb.append(", Auth: ").append(auth.toString());
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index f7fd8d0972f6..d66a27920f49 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -127,7 +127,8 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
}
}
- private boolean wasUserDetected() {
+ @Override
+ public boolean wasUserDetected() {
// Do not provide haptic feedback if the user was not detected, and an error (usually
// ERROR_TIMEOUT) is received.
return mLastAcquire != FaceManager.FACE_ACQUIRED_NOT_DETECTED
@@ -160,7 +161,7 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
}
@Override
- public void onError(int error, int vendorCode) {
+ public void onError(@BiometricConstants.Errors int error, int vendorCode) {
mUsageStats.addEvent(new UsageStats.AuthenticationEvent(
getStartTimeMs(),
System.currentTimeMillis() - getStartTimeMs() /* latency */,
@@ -169,25 +170,8 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
vendorCode,
getTargetUserId()));
- switch (error) {
- case BiometricConstants.BIOMETRIC_ERROR_TIMEOUT:
- if (!wasUserDetected() && !isBiometricPrompt()) {
- // No vibration if user was not detected on keyguard
- break;
- }
- case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT:
- case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT:
- if (mAuthAttempted) {
- // Only vibrate if auth was attempted. If the user was already locked out prior
- // to starting authentication, do not vibrate.
- vibrateError();
- }
- break;
- case BiometricConstants.BIOMETRIC_ERROR_RE_ENROLL:
- BiometricNotificationUtils.showReEnrollmentNotification(getContext());
- break;
- default:
- break;
+ if (error == BiometricConstants.BIOMETRIC_ERROR_RE_ENROLL) {
+ BiometricNotificationUtils.showReEnrollmentNotification(getContext());
}
super.onError(error, vendorCode);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
index c33b957223a4..33950af2216f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
@@ -115,7 +115,8 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
}
}
- private boolean wasUserDetected() {
+ @Override
+ public boolean wasUserDetected() {
// Do not provide haptic feedback if the user was not detected, and an error (usually
// ERROR_TIMEOUT) is received.
return mLastAcquire != FaceManager.FACE_ACQUIRED_NOT_DETECTED
@@ -147,7 +148,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
}
@Override
- public void onError(int error, int vendorCode) {
+ public void onError(@BiometricConstants.Errors int error, int vendorCode) {
mUsageStats.addEvent(new UsageStats.AuthenticationEvent(
getStartTimeMs(),
System.currentTimeMillis() - getStartTimeMs() /* latency */,
@@ -156,24 +157,6 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
vendorCode,
getTargetUserId()));
- switch (error) {
- case BiometricConstants.BIOMETRIC_ERROR_TIMEOUT:
- if (!wasUserDetected() && !isBiometricPrompt()) {
- // No vibration if user was not detected on keyguard
- break;
- }
- case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT:
- case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT:
- if (mAuthAttempted) {
- // Only vibrate if auth was attempted. If the user was already locked out prior
- // to starting authentication, do not vibrate.
- vibrateError();
- }
- break;
- default:
- break;
- }
-
super.onError(error, vendorCode);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 99e6e626f5fe..37ee76adeece 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -106,6 +106,12 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp
}
@Override
+ public boolean wasUserDetected() {
+ // TODO: Update if it needs to be used for fingerprint, i.e. success/reject, error_timeout
+ return false;
+ }
+
+ @Override
public void onAuthenticated(BiometricAuthenticator.Identifier identifier,
boolean authenticated, ArrayList<Byte> token) {
super.onAuthenticated(identifier, authenticated, token);
@@ -114,7 +120,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp
mState = STATE_STOPPED;
UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
} else {
- mState = STATE_STARTED_PAUSED;
+ mState = STATE_STARTED_PAUSED_ATTEMPTED;
}
}
@@ -188,7 +194,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp
public void onPointerUp() {
try {
mIsPointerDown = false;
- mState = STATE_STARTED_PAUSED;
+ mState = STATE_STARTED_PAUSED_ATTEMPTED;
mALSProbeCallback.getProbe().disable();
getFreshDaemon().onPointerUp(0 /* pointerId */);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index 7558d15fbe32..5060744bb33e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -112,7 +112,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
resetFailedAttempts(getTargetUserId());
UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
} else {
- mState = STATE_STARTED_PAUSED;
+ mState = STATE_STARTED_PAUSED_ATTEMPTED;
final @LockoutTracker.LockoutMode int lockoutMode =
mLockoutFrameworkImpl.getLockoutModeForUser(getTargetUserId());
if (lockoutMode != LockoutTracker.LOCKOUT_NONE) {
@@ -153,6 +153,12 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
}
@Override
+ public boolean wasUserDetected() {
+ // TODO: Update if it needs to be used for fingerprint, i.e. success/reject, error_timeout
+ return false;
+ }
+
+ @Override
public @LockoutTracker.LockoutMode int handleFailedAttempt(int userId) {
mLockoutFrameworkImpl.addFailedAttemptForUser(userId);
return super.handleFailedAttempt(userId);
@@ -206,7 +212,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
@Override
public void onPointerUp() {
mIsPointerDown = false;
- mState = STATE_STARTED_PAUSED;
+ mState = STATE_STARTED_PAUSED_ATTEMPTED;
mALSProbeCallback.getProbe().disable();
UdfpsHelper.onFingerUp(getFreshDaemon());
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index ed7d185a5ef0..6610e8c4392b 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -20,9 +20,14 @@ import static android.os.Build.VERSION_CODES.M;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
+import android.app.compat.CompatChanges;
import android.app.TaskStackListener;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.Disabled;
+import android.compat.annotation.Overridable;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -49,6 +54,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.os.UserManager;
import android.stats.camera.nano.CameraProtos.CameraStreamProto;
import android.util.ArrayMap;
@@ -97,6 +103,95 @@ public class CameraServiceProxy extends SystemService
public static final String CAMERA_SERVICE_PROXY_BINDER_NAME = "media.camera.proxy";
+ /**
+ * When enabled this change id forces the packages it is applied to override the default
+ * camera rotate & crop behavior. The default behavior along with all possible override
+ * combinations is discussed in the table below.
+ */
+ @ChangeId
+ @Overridable
+ @Disabled
+ @TestApi
+ public static final long OVERRIDE_CAMERA_ROTATE_AND_CROP_DEFAULTS = 189229956L; // buganizer id
+
+ /**
+ * When enabled this change id forces the packages it is applied to ignore the current value of
+ * 'android:resizeableActivity' as well as target SDK equal to or below M and consider the
+ * activity as non-resizeable. In this case, the value of camera rotate & crop will only depend
+ * on potential mismatches between the orientation of the camera and the fixed orientation of
+ * the activity. You can check the table below for further details on the possible override
+ * combinations.
+ */
+ @ChangeId
+ @Overridable
+ @Disabled
+ @TestApi
+ public static final long OVERRIDE_CAMERA_RESIZABLE_AND_SDK_CHECK = 191513214L; // buganizer id
+
+ /**
+ * This change id forces the packages it is applied to override the default camera rotate & crop
+ * behavior. Enabling it will set the crop & rotate parameter to
+ * {@link android.hardware.camera2.CaptureRequest#SCALER_ROTATE_AND_CROP_90} and disabling it
+ * will reset the parameter to
+ * {@link android.hardware.camera2.CaptureRequest#SCALER_ROTATE_AND_CROP_NONE} as long as camera
+ * clients include {@link android.hardware.camera2.CaptureRequest#SCALER_ROTATE_AND_CROP_AUTO}
+ * in their capture requests.
+ *
+ * This treatment only takes effect if OVERRIDE_CAMERA_ROTATE_AND_CROP_DEFAULTS is also enabled.
+ * The table below includes further information about the possible override combinations.
+ */
+ @ChangeId
+ @Overridable
+ @Disabled
+ @TestApi
+ public static final long OVERRIDE_CAMERA_ROTATE_AND_CROP = 190069291L; //buganizer id
+
+ /**
+ * Possible override combinations
+ *
+ * |OVERRIDE | |OVERRIDE_
+ * |CAMERA_ |OVERRIDE |CAMERA_
+ * |ROTATE_ |CAMERA_ |RESIZEABLE_
+ * |AND_CROP_ |ROTATE_ |AND_SDK_
+ * |DEFAULTS |AND_CROP |CHECK
+ * ______________________________________________
+ * Default | | |
+ * Behavior | D |D |D
+ * ______________________________________________
+ * Ignore | | |
+ * SDK&Resize | D |D |E
+ * ______________________________________________
+ * Default | | |
+ * Behavior | D |E |D
+ * ______________________________________________
+ * Ignore | | |
+ * SDK&Resize | D |E |E
+ * ______________________________________________
+ * Rotate&Crop| | |
+ * disabled | E |D |D
+ * ______________________________________________
+ * Rotate&Crop| | |
+ * disabled | E |D |E
+ * ______________________________________________
+ * Rotate&Crop| | |
+ * enabled | E |E |D
+ * ______________________________________________
+ * Rotate&Crop| | |
+ * enabled | E |E |E
+ * ______________________________________________
+ * Where:
+ * E -> Override enabled
+ * D -> Override disabled
+ * Default behavior -> Rotate&crop will be enabled only in cases
+ * where the fixed app orientation mismatches
+ * with the orientation of the camera.
+ * Additionally the app must either target M (or below)
+ * or is declared as non-resizeable.
+ * Ignore SDK&Resize -> Rotate&crop will be enabled only in cases
+ * where the fixed app orientation mismatches
+ * with the orientation of the camera.
+ */
+
// Flags arguments to NFC adapter to enable/disable NFC
public static final int DISABLE_POLLING_FLAGS = 0x1000;
public static final int ENABLE_POLLING_FLAGS = 0x0000;
@@ -257,6 +352,7 @@ public class CameraServiceProxy extends SystemService
private boolean isFixedOrientationLandscape;
private boolean isFixedOrientationPortrait;
private int displayId;
+ private int userId;
}
private final class TaskStateHandler extends TaskStackListener {
@@ -273,6 +369,7 @@ public class CameraServiceProxy extends SystemService
info.frontTaskId = taskInfo.taskId;
info.isResizeable = taskInfo.isResizeable;
info.displayId = taskInfo.displayId;
+ info.userId = taskInfo.userId;
info.isFixedOrientationLandscape = ActivityInfo.isFixedOrientationLandscape(
taskInfo.topActivityInfo.screenOrientation);
info.isFixedOrientationPortrait = ActivityInfo.isFixedOrientationPortrait(
@@ -303,7 +400,7 @@ public class CameraServiceProxy extends SystemService
Log.e(TAG, "Top task with package name: " + packageName + " not found!");
return null;
}
- };
+ }
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
@@ -345,7 +442,8 @@ public class CameraServiceProxy extends SystemService
* Gets whether crop-rotate-scale is needed.
*/
private boolean getNeedCropRotateScale(@NonNull Context ctx, @NonNull String packageName,
- @Nullable TaskInfo taskInfo, int sensorOrientation, int lensFacing) {
+ @Nullable TaskInfo taskInfo, int sensorOrientation, int lensFacing,
+ boolean ignoreResizableAndSdkCheck) {
if (taskInfo == null) {
return false;
}
@@ -357,9 +455,11 @@ public class CameraServiceProxy extends SystemService
return false;
}
- // Only enable the crop-rotate-scale workaround if the app targets M or below and is not
+ // In case the activity behavior is not explicitly overridden, enable the
+ // crop-rotate-scale workaround if the app targets M (or below) or is not
// resizeable.
- if (!isMOrBelow(ctx, packageName) && taskInfo.isResizeable) {
+ if (!ignoreResizableAndSdkCheck && !isMOrBelow(ctx, packageName) &&
+ taskInfo.isResizeable) {
Slog.v(TAG,
"The activity is N or above and claims to support resizeable-activity. "
+ "Crop-rotate-scale is disabled.");
@@ -367,22 +467,32 @@ public class CameraServiceProxy extends SystemService
}
DisplayManager displayManager = ctx.getSystemService(DisplayManager.class);
- Display display = displayManager.getDisplay(taskInfo.displayId);
- int rotation = display.getRotation();
int rotationDegree = 0;
- switch (rotation) {
- case Surface.ROTATION_0:
- rotationDegree = 0;
- break;
- case Surface.ROTATION_90:
- rotationDegree = 90;
- break;
- case Surface.ROTATION_180:
- rotationDegree = 180;
- break;
- case Surface.ROTATION_270:
- rotationDegree = 270;
- break;
+ if (displayManager != null) {
+ Display display = displayManager.getDisplay(taskInfo.displayId);
+ if (display == null) {
+ Slog.e(TAG, "Invalid display id: " + taskInfo.displayId);
+ return false;
+ }
+
+ int rotation = display.getRotation();
+ switch (rotation) {
+ case Surface.ROTATION_0:
+ rotationDegree = 0;
+ break;
+ case Surface.ROTATION_90:
+ rotationDegree = 90;
+ break;
+ case Surface.ROTATION_180:
+ rotationDegree = 180;
+ break;
+ case Surface.ROTATION_270:
+ rotationDegree = 270;
+ break;
+ }
+ } else {
+ Slog.e(TAG, "Failed to query display manager!");
+ return false;
}
// Here we only need to know whether the camera is landscape or portrait. Therefore we
@@ -414,9 +524,28 @@ public class CameraServiceProxy extends SystemService
// regions in capture requests/results to account for thea physical rotation. The
// former is somewhat tricky as it assumes that camera clients always check for the
// current value by retrieving the camera characteristics from the camera device.
- return getNeedCropRotateScale(mContext, packageName,
- mTaskStackListener.getFrontTaskInfo(packageName), sensorOrientation,
- lensFacing);
+ TaskInfo taskInfo = mTaskStackListener.getFrontTaskInfo(packageName);
+ if ((taskInfo != null) && (CompatChanges.isChangeEnabled(
+ OVERRIDE_CAMERA_ROTATE_AND_CROP_DEFAULTS, packageName,
+ UserHandle.getUserHandleForUid(taskInfo.userId)))) {
+ if (CompatChanges.isChangeEnabled(OVERRIDE_CAMERA_ROTATE_AND_CROP, packageName,
+ UserHandle.getUserHandleForUid(taskInfo.userId))) {
+ Slog.v(TAG, "OVERRIDE_CAMERA_ROTATE_AND_CROP enabled!");
+ return true;
+ } else {
+ Slog.v(TAG, "OVERRIDE_CAMERA_ROTATE_AND_CROP disabled!");
+ return false;
+ }
+ }
+ boolean ignoreResizableAndSdkCheck = false;
+ if ((taskInfo != null) && (CompatChanges.isChangeEnabled(
+ OVERRIDE_CAMERA_RESIZABLE_AND_SDK_CHECK, packageName,
+ UserHandle.getUserHandleForUid(taskInfo.userId)))) {
+ Slog.v(TAG, "OVERRIDE_CAMERA_RESIZABLE_AND_SDK_CHECK enabled!");
+ ignoreResizableAndSdkCheck = true;
+ }
+ return getNeedCropRotateScale(mContext, packageName, taskInfo, sensorOrientation,
+ lensFacing, ignoreResizableAndSdkCheck);
}
@Override
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index afd18894f531..a0944c021b92 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -63,8 +63,6 @@ import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal.DisplayGroupListener;
import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener;
-import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
-import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
import android.hardware.display.DisplayViewport;
import android.hardware.display.DisplayedContentSample;
import android.hardware.display.DisplayedContentSamplingAttributes;
@@ -636,6 +634,9 @@ public final class DisplayManagerService extends SystemService {
synchronized (mSyncRoot) {
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
if (display != null) {
+ // Do not let constrain be overwritten by override from WindowManager.
+ info.shouldConstrainMetricsForLauncher =
+ display.getDisplayInfoLocked().shouldConstrainMetricsForLauncher;
if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) {
handleLogicalDisplayChangedLocked(display);
scheduleTraversalLocked(false);
@@ -1723,6 +1724,21 @@ public final class DisplayManagerService extends SystemService {
}
}
+ void setShouldConstrainMetricsForLauncher(boolean constrain) {
+ // Apply constrain for every display.
+ synchronized (mSyncRoot) {
+ int[] displayIds = mLogicalDisplayMapper.getDisplayIdsLocked(Process.myUid());
+ for (int i : displayIds) {
+ final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(i);
+ if (display == null) {
+ return;
+ }
+ display.getDisplayInfoLocked().shouldConstrainMetricsForLauncher = constrain;
+ setDisplayInfoOverrideFromWindowManagerInternal(i, display.getDisplayInfoLocked());
+ }
+ }
+ }
+
private void clearViewportsLocked() {
mViewports.clear();
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
index 48edb73ac81d..94e64f070ef8 100644
--- a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
+++ b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
@@ -58,6 +58,8 @@ class DisplayManagerShellCommand extends ShellCommand {
return setDisplayModeDirectorLoggingEnabled(false);
case "dwb-set-cct":
return setAmbientColorTemperatureOverride();
+ case "constrain-launcher-metrics":
+ return setConstrainLauncherMetrics();
default:
return handleDefaultCommands(cmd);
}
@@ -88,6 +90,9 @@ class DisplayManagerShellCommand extends ShellCommand {
pw.println(" Disable display mode director logging.");
pw.println(" dwb-set-cct CCT");
pw.println(" Sets the ambient color temperature override to CCT (use -1 to disable).");
+ pw.println(" constrain-launcher-metrics [true|false]");
+ pw.println(" Sets if Display#getRealSize and getRealMetrics should be constrained for ");
+ pw.println(" Launcher.");
pw.println();
Intent.printIntentArgsHelp(pw , "");
}
@@ -150,4 +155,15 @@ class DisplayManagerShellCommand extends ShellCommand {
mService.setAmbientColorTemperatureOverride(cct);
return 0;
}
+
+ private int setConstrainLauncherMetrics() {
+ String constrainText = getNextArg();
+ if (constrainText == null) {
+ getErrPrintWriter().println("Error: no value specified");
+ return 1;
+ }
+ boolean constrain = Boolean.parseBoolean(constrainText);
+ mService.setShouldConstrainMetricsForLauncher(constrain);
+ return 0;
+ }
}
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index f23ae6e2340c..d66d7ee99f2e 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -52,6 +52,7 @@ import android.view.Display;
import android.view.DisplayInfo;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.server.LocalServices;
@@ -153,7 +154,7 @@ public class DisplayModeDirector {
updateVoteLocked(displayId, priority, vote);
}
};
- mSensorObserver = new SensorObserver(context, ballotBox);
+ mSensorObserver = new SensorObserver(context, ballotBox, injector);
mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler());
mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
mDeviceConfig = injector.getDeviceConfig();
@@ -2127,27 +2128,36 @@ public class DisplayModeDirector {
}
}
- private static class SensorObserver implements ProximityActiveListener {
- private static final String PROXIMITY_SENSOR_NAME = null;
- private static final String PROXIMITY_SENSOR_TYPE = Sensor.STRING_TYPE_PROXIMITY;
+ private static final class SensorObserver implements ProximityActiveListener,
+ DisplayManager.DisplayListener {
+ private final String mProximitySensorName = null;
+ private final String mProximitySensorType = Sensor.STRING_TYPE_PROXIMITY;
private final BallotBox mBallotBox;
private final Context mContext;
+ private final Injector mInjector;
+ @GuardedBy("mSensorObserverLock")
+ private final SparseBooleanArray mDozeStateByDisplay = new SparseBooleanArray();
+ private final Object mSensorObserverLock = new Object();
private DisplayManager mDisplayManager;
private DisplayManagerInternal mDisplayManagerInternal;
+ @GuardedBy("mSensorObserverLock")
private boolean mIsProxActive = false;
- SensorObserver(Context context, BallotBox ballotBox) {
+ SensorObserver(Context context, BallotBox ballotBox, Injector injector) {
mContext = context;
mBallotBox = ballotBox;
+ mInjector = injector;
}
@Override
public void onProximityActive(boolean isActive) {
- if (mIsProxActive != isActive) {
- mIsProxActive = isActive;
- recalculateVotes();
+ synchronized (mSensorObserverLock) {
+ if (mIsProxActive != isActive) {
+ mIsProxActive = isActive;
+ recalculateVotesLocked();
+ }
}
}
@@ -2158,17 +2168,27 @@ public class DisplayModeDirector {
final SensorManagerInternal sensorManager =
LocalServices.getService(SensorManagerInternal.class);
sensorManager.addProximityActiveListener(BackgroundThread.getExecutor(), this);
+
+ synchronized (mSensorObserverLock) {
+ for (Display d : mDisplayManager.getDisplays()) {
+ mDozeStateByDisplay.put(d.getDisplayId(), mInjector.isDozeState(d));
+ }
+ }
+ mInjector.registerDisplayListener(this, BackgroundThread.getHandler(),
+ DisplayManager.EVENT_FLAG_DISPLAY_ADDED
+ | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
+ | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
}
- private void recalculateVotes() {
+ private void recalculateVotesLocked() {
final Display[] displays = mDisplayManager.getDisplays();
for (Display d : displays) {
int displayId = d.getDisplayId();
Vote vote = null;
- if (mIsProxActive) {
+ if (mIsProxActive && !mDozeStateByDisplay.get(displayId)) {
final RefreshRateRange rate =
mDisplayManagerInternal.getRefreshRateForDisplayAndSensor(
- displayId, PROXIMITY_SENSOR_NAME, PROXIMITY_SENSOR_TYPE);
+ displayId, mProximitySensorName, mProximitySensorType);
if (rate != null) {
vote = Vote.forRefreshRates(rate.min, rate.max);
}
@@ -2179,7 +2199,44 @@ public class DisplayModeDirector {
void dumpLocked(PrintWriter pw) {
pw.println(" SensorObserver");
- pw.println(" mIsProxActive=" + mIsProxActive);
+ synchronized (mSensorObserverLock) {
+ pw.println(" mIsProxActive=" + mIsProxActive);
+ pw.println(" mDozeStateByDisplay:");
+ for (int i = 0; i < mDozeStateByDisplay.size(); i++) {
+ final int id = mDozeStateByDisplay.keyAt(i);
+ final boolean dozed = mDozeStateByDisplay.valueAt(i);
+ pw.println(" " + id + " -> " + dozed);
+ }
+ }
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ boolean isDozeState = mInjector.isDozeState(mDisplayManager.getDisplay(displayId));
+ synchronized (mSensorObserverLock) {
+ mDozeStateByDisplay.put(displayId, isDozeState);
+ recalculateVotesLocked();
+ }
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ boolean wasDozeState = mDozeStateByDisplay.get(displayId);
+ synchronized (mSensorObserverLock) {
+ mDozeStateByDisplay.put(displayId,
+ mInjector.isDozeState(mDisplayManager.getDisplay(displayId)));
+ if (wasDozeState != mDozeStateByDisplay.get(displayId)) {
+ recalculateVotesLocked();
+ }
+ }
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ synchronized (mSensorObserverLock) {
+ mDozeStateByDisplay.delete(displayId);
+ recalculateVotesLocked();
+ }
}
}
@@ -2411,6 +2468,8 @@ public class DisplayModeDirector {
Handler handler, long flags);
BrightnessInfo getBrightnessInfo(int displayId);
+
+ boolean isDozeState(Display d);
}
@VisibleForTesting
@@ -2463,6 +2522,14 @@ public class DisplayModeDirector {
return null;
}
+ @Override
+ public boolean isDozeState(Display d) {
+ if (d == null) {
+ return false;
+ }
+ return Display.isDozeState(d.getState());
+ }
+
private DisplayManager getDisplayManager() {
if (mDisplayManager == null) {
mDisplayManager = mContext.getSystemService(DisplayManager.class);
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 5186744d5c27..86c9ca937482 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -233,6 +233,8 @@ final class LogicalDisplay {
info.physicalXDpi = mOverrideDisplayInfo.physicalXDpi;
info.physicalYDpi = mOverrideDisplayInfo.physicalYDpi;
info.roundedCorners = mOverrideDisplayInfo.roundedCorners;
+ info.shouldConstrainMetricsForLauncher =
+ mOverrideDisplayInfo.shouldConstrainMetricsForLauncher;
}
mInfo.set(info);
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 6fb9e58a49d1..b0b8be2c9677 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -189,7 +189,7 @@ public class InputManagerService extends IInputManager.Stub
private final InputManagerHandler mHandler;
// Context cache used for loading pointer resources.
- private Context mDisplayContext;
+ private Context mPointerIconDisplayContext;
private final File mDoubleTouchGestureEnableFile;
@@ -839,21 +839,31 @@ public class InputManagerService extends IInputManager.Stub
throw new IllegalArgumentException("mode is invalid");
}
if (ENABLE_PER_WINDOW_INPUT_ROTATION) {
- if (event instanceof MotionEvent) {
- final Context dispCtx = getContextForDisplay(event.getDisplayId());
- final Display display = dispCtx.getDisplay();
+ // Motion events that are pointer events or relative mouse events will need to have the
+ // inverse display rotation applied to them.
+ if (event instanceof MotionEvent
+ && (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
+ || event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE))) {
+ Context displayContext = getContextForDisplay(event.getDisplayId());
+ if (displayContext == null) {
+ displayContext = Objects.requireNonNull(
+ getContextForDisplay(Display.DEFAULT_DISPLAY));
+ }
+ final Display display = displayContext.getDisplay();
final int rotation = display.getRotation();
if (rotation != ROTATION_0) {
final MotionEvent motion = (MotionEvent) event;
// Injections are currently expected to be in the space of the injector (ie.
- // usually assumed to be post-rotated). Thus we need to unrotate into raw
+ // usually assumed to be post-rotated). Thus we need to un-rotate into raw
// input coordinates for dispatch.
final Point sz = new Point();
- display.getRealSize(sz);
- if ((rotation % 2) != 0) {
- final int tmpX = sz.x;
- sz.x = sz.y;
- sz.y = tmpX;
+ if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
+ display.getRealSize(sz);
+ if ((rotation % 2) != 0) {
+ final int tmpX = sz.x;
+ sz.x = sz.y;
+ sz.y = tmpX;
+ }
}
motion.applyTransform(MotionEvent.createRotateMatrix(
(4 - rotation), sz.x, sz.y));
@@ -1742,6 +1752,11 @@ public class InputManagerService extends IInputManager.Stub
/** Clean up input window handles of the given display. */
public void onDisplayRemoved(int displayId) {
+ if (mPointerIconDisplayContext != null
+ && mPointerIconDisplayContext.getDisplay().getDisplayId() == displayId) {
+ mPointerIconDisplayContext = null;
+ }
+
nativeDisplayRemoved(mPtr, displayId);
}
@@ -2971,24 +2986,43 @@ public class InputManagerService extends IInputManager.Stub
// Native callback.
private PointerIcon getPointerIcon(int displayId) {
- return PointerIcon.getDefaultIcon(getContextForDisplay(displayId));
+ return PointerIcon.getDefaultIcon(getContextForPointerIcon(displayId));
}
- private Context getContextForDisplay(int displayId) {
- if (mDisplayContext != null && mDisplayContext.getDisplay().getDisplayId() == displayId) {
- return mDisplayContext;
+ @NonNull
+ private Context getContextForPointerIcon(int displayId) {
+ if (mPointerIconDisplayContext != null
+ && mPointerIconDisplayContext.getDisplay().getDisplayId() == displayId) {
+ return mPointerIconDisplayContext;
+ }
+
+ // Create and cache context for non-default display.
+ mPointerIconDisplayContext = getContextForDisplay(displayId);
+
+ // Fall back to default display if the requested displayId does not exist.
+ if (mPointerIconDisplayContext == null) {
+ mPointerIconDisplayContext = getContextForDisplay(Display.DEFAULT_DISPLAY);
}
+ return mPointerIconDisplayContext;
+ }
+ @Nullable
+ private Context getContextForDisplay(int displayId) {
+ if (displayId == Display.INVALID_DISPLAY) {
+ return null;
+ }
if (mContext.getDisplay().getDisplayId() == displayId) {
- mDisplayContext = mContext;
- return mDisplayContext;
+ return mContext;
}
- // Create and cache context for non-default display.
- final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+ final DisplayManager displayManager = Objects.requireNonNull(
+ mContext.getSystemService(DisplayManager.class));
final Display display = displayManager.getDisplay(displayId);
- mDisplayContext = mContext.createDisplayContext(display);
- return mDisplayContext;
+ if (display == null) {
+ return null;
+ }
+
+ return mContext.createDisplayContext(display);
}
// Native callback.
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 4ee867b7d051..097b0711eff7 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -289,8 +289,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private String mActiveIface;
/** Set of any ifaces associated with mobile networks since boot. */
- @GuardedBy("mStatsLock")
- private String[] mMobileIfaces = new String[0];
+ private volatile String[] mMobileIfaces = new String[0];
/** Set of all ifaces currently used by traffic that does not explicitly specify a Network. */
@GuardedBy("mStatsLock")
@@ -935,7 +934,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@Override
public String[] getMobileIfaces() {
- return mMobileIfaces;
+ // TODO (b/192758557): Remove debug log.
+ if (ArrayUtils.contains(mMobileIfaces, null)) {
+ throw new NullPointerException(
+ "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces));
+ }
+ return mMobileIfaces.clone();
}
@Override
@@ -1084,7 +1088,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
@Override
- public long getIfaceStats(String iface, int type) {
+ public long getIfaceStats(@NonNull String iface, int type) {
+ Objects.requireNonNull(iface);
long nativeIfaceStats = nativeGetIfaceStat(iface, type, checkBpfStatsEnable());
if (nativeIfaceStats == -1) {
return nativeIfaceStats;
@@ -1382,7 +1387,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
}
- mMobileIfaces = mobileIfaces.toArray(new String[mobileIfaces.size()]);
+ mMobileIfaces = mobileIfaces.toArray(new String[0]);
+ // TODO (b/192758557): Remove debug log.
+ if (ArrayUtils.contains(mMobileIfaces, null)) {
+ throw new NullPointerException(
+ "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces));
+ }
}
private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) {
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 06ff69176bb7..ed9b539c05df 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -1287,20 +1287,6 @@ public class AppsFilter implements Watchable, Snappable {
}
}
- // This package isn't technically installed and won't be written to settings, so we can
- // treat it as filtered until it's available again.
- final AndroidPackage targetPkg = targetPkgSetting.pkg;
- if (targetPkg == null) {
- if (DEBUG_LOGGING) {
- Slog.wtf(TAG, "shouldFilterApplication: " + "targetPkg is null");
- }
- return true;
- }
- if (targetPkg.isStaticSharedLibrary()) {
- // not an app, this filtering takes place at a higher level
- return false;
- }
- final String targetName = targetPkg.getPackageName();
if (DEBUG_TRACING) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "getAppId");
}
@@ -1343,6 +1329,21 @@ public class AppsFilter implements Watchable, Snappable {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
+
+ // This package isn't technically installed and won't be written to settings, so we can
+ // treat it as filtered until it's available again.
+ final AndroidPackage targetPkg = targetPkgSetting.pkg;
+ if (targetPkg == null) {
+ if (DEBUG_LOGGING) {
+ Slog.wtf(TAG, "shouldFilterApplication: " + "targetPkg is null");
+ }
+ return true;
+ }
+ if (targetPkg.isStaticSharedLibrary()) {
+ // not an app, this filtering takes place at a higher level
+ return false;
+ }
+
try {
if (DEBUG_TRACING) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mForceQueryable");
@@ -1415,6 +1416,7 @@ public class AppsFilter implements Watchable, Snappable {
if (DEBUG_TRACING) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mOverlayReferenceMapper");
}
+ final String targetName = targetPkg.getPackageName();
if (callingSharedPkgSettings != null) {
int size = callingSharedPkgSettings.size();
for (int index = 0; index < size; index++) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ee44c10edbf3..904a1f0d6f4f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -24838,11 +24838,11 @@ public class PackageManagerService extends IPackageManager.Stub
pw.println("vers,1");
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_VERSION)
- && packageName == null) {
- // dump version information for all volumes with installed packages
- dump(DumpState.DUMP_VERSION, fd, pw, dumpState);
+ // reader
+ if (dumpState.isDumping(DumpState.DUMP_VERSION) && packageName == null) {
+ if (!checkin) {
+ dump(DumpState.DUMP_VERSION, fd, pw, dumpState);
+ }
}
if (!checkin
@@ -24873,8 +24873,7 @@ public class PackageManagerService extends IPackageManager.Stub
ipw.decreaseIndent();
}
- if (dumpState.isDumping(DumpState.DUMP_VERIFIERS)
- && packageName == null) {
+ if (dumpState.isDumping(DumpState.DUMP_VERIFIERS) && packageName == null) {
final String requiredVerifierPackage = mRequiredVerifierPackage;
if (!checkin) {
if (dumpState.onTitlePrinted()) {
@@ -24895,8 +24894,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- if (dumpState.isDumping(DumpState.DUMP_DOMAIN_VERIFIER)
- && packageName == null) {
+ if (dumpState.isDumping(DumpState.DUMP_DOMAIN_VERIFIER) && packageName == null) {
final DomainVerificationProxy proxy = mDomainVerificationManager.getProxy();
final ComponentName verifierComponent = proxy.getComponentName();
if (verifierComponent != null) {
@@ -24923,13 +24921,11 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- if (dumpState.isDumping(DumpState.DUMP_LIBS)
- && packageName == null) {
+ if (dumpState.isDumping(DumpState.DUMP_LIBS) && packageName == null) {
dump(DumpState.DUMP_LIBS, fd, pw, dumpState);
}
- if (dumpState.isDumping(DumpState.DUMP_FEATURES)
- && packageName == null) {
+ if (dumpState.isDumping(DumpState.DUMP_FEATURES) && packageName == null) {
if (dumpState.onTitlePrinted()) {
pw.println();
}
@@ -24939,7 +24935,12 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mAvailableFeatures) {
for (FeatureInfo feat : mAvailableFeatures.values()) {
- if (!checkin) {
+ if (checkin) {
+ pw.print("feat,");
+ pw.print(feat.name);
+ pw.print(",");
+ pw.println(feat.version);
+ } else {
pw.print(" ");
pw.print(feat.name);
if (feat.version > 0) {
@@ -24947,73 +24948,55 @@ public class PackageManagerService extends IPackageManager.Stub
pw.print(feat.version);
}
pw.println();
- } else {
- pw.print("feat,");
- pw.print(feat.name);
- pw.print(",");
- pw.println(feat.version);
}
}
}
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_ACTIVITY_RESOLVERS)) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_ACTIVITY_RESOLVERS)) {
synchronized (mLock) {
mComponentResolver.dumpActivityResolvers(pw, dumpState, packageName);
}
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_RECEIVER_RESOLVERS)) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_RECEIVER_RESOLVERS)) {
synchronized (mLock) {
mComponentResolver.dumpReceiverResolvers(pw, dumpState, packageName);
}
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_SERVICE_RESOLVERS)) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_RESOLVERS)) {
synchronized (mLock) {
mComponentResolver.dumpServiceResolvers(pw, dumpState, packageName);
}
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_CONTENT_RESOLVERS)) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_CONTENT_RESOLVERS)) {
synchronized (mLock) {
mComponentResolver.dumpProviderResolvers(pw, dumpState, packageName);
}
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_PREFERRED)
- && packageName == null) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
dump(DumpState.DUMP_PREFERRED, fd, pw, dumpState);
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)
- && packageName == null) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)) {
dump(DumpState.DUMP_PREFERRED_XML, fd, pw, dumpState);
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)
- && packageName == null) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)) {
dump(DumpState.DUMP_DOMAIN_PREFERRED, fd, pw, dumpState);
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
mSettings.dumpPermissions(pw, packageName, permissionNames, dumpState);
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) {
synchronized (mLock) {
mComponentResolver.dumpContentProviders(pw, dumpState, packageName);
}
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_KEYSETS)) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_KEYSETS)) {
synchronized (mLock) {
mSettings.getKeySetManagerService().dumpLPr(pw, packageName, dumpState);
}
@@ -25028,15 +25011,11 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_QUERIES)
- && packageName == null) {
+ if (dumpState.isDumping(DumpState.DUMP_QUERIES)) {
dump(DumpState.DUMP_QUERIES, fd, pw, dumpState);
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_SHARED_USERS)
- && packageName == null) {
+ if (dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) {
// This cannot be moved to ComputerEngine since the set of packages in the
// SharedUserSetting do not have a copy.
synchronized (mLock) {
@@ -25044,9 +25023,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_CHANGES)
- && packageName == null) {
+ if (dumpState.isDumping(DumpState.DUMP_CHANGES)) {
if (dumpState.onTitlePrinted()) pw.println();
pw.println("Package Changes:");
synchronized (mLock) {
@@ -25073,9 +25050,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_FROZEN)
- && packageName == null) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_FROZEN) && packageName == null) {
// XXX should handle packageName != null by dumping only install data that
// the given package is involved with.
if (dumpState.onTitlePrinted()) pw.println();
@@ -25096,9 +25071,7 @@ public class PackageManagerService extends IPackageManager.Stub
ipw.decreaseIndent();
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_VOLUMES)
- && packageName == null) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_VOLUMES) && packageName == null) {
if (dumpState.onTitlePrinted()) pw.println();
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
@@ -25117,61 +25090,50 @@ public class PackageManagerService extends IPackageManager.Stub
ipw.decreaseIndent();
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS)
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS)
&& packageName == null) {
synchronized (mLock) {
mComponentResolver.dumpServicePermissions(pw, dumpState);
}
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_DEXOPT)
- && packageName == null) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_DEXOPT)) {
if (dumpState.onTitlePrinted()) pw.println();
dump(DumpState.DUMP_DEXOPT, fd, pw, dumpState);
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_COMPILER_STATS)
- && packageName == null) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_COMPILER_STATS)) {
if (dumpState.onTitlePrinted()) pw.println();
dump(DumpState.DUMP_COMPILER_STATS, fd, pw, dumpState);
}
- if (dumpState.isDumping(DumpState.DUMP_MESSAGES)
- && packageName == null) {
- if (!checkin) {
- if (dumpState.onTitlePrinted()) pw.println();
- synchronized (mLock) {
- mSettings.dumpReadMessagesLPr(pw, dumpState);
- }
- pw.println();
- pw.println("Package warning messages:");
- dumpCriticalInfo(pw, null);
- } else {
- dumpCriticalInfo(pw, "msg,");
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) {
+ if (dumpState.onTitlePrinted()) pw.println();
+ synchronized (mLock) {
+ mSettings.dumpReadMessagesLPr(pw, dumpState);
}
+ pw.println();
+ pw.println("Package warning messages:");
+ dumpCriticalInfo(pw, null);
+ }
+
+ if (checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES)) {
+ dumpCriticalInfo(pw, "msg,");
}
// PackageInstaller should be called outside of mPackages lock
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_INSTALLS)
- && packageName == null) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_INSTALLS) && packageName == null) {
// XXX should handle packageName != null by dumping only install data that
// the given package is involved with.
if (dumpState.onTitlePrinted()) pw.println();
mInstallerService.dump(new IndentingPrintWriter(pw, " ", 120));
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_APEX)
- && packageName == null) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_APEX)) {
mApexManager.dump(pw, packageName);
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_PER_UID_READ_TIMEOUTS)
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_PER_UID_READ_TIMEOUTS)
&& packageName == null) {
pw.println();
pw.println("Per UID read timeouts:");
@@ -25190,9 +25152,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- if (!checkin
- && dumpState.isDumping(DumpState.DUMP_SNAPSHOT_STATISTICS)
- && packageName == null) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_SNAPSHOT_STATISTICS)) {
pw.println("Snapshot statistics");
if (!mSnapshotEnabled) {
pw.println(" Snapshots disabled");
@@ -26533,7 +26493,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
boolean readPermissionStateForUser(@UserIdInt int userId) {
- synchronized (mPackages) {
+ synchronized (mLock) {
mPermissionManager.writeLegacyPermissionStateTEMP();
mSettings.readPermissionStateForUserSyncLPr(userId);
mPermissionManager.readLegacyPermissionStateTEMP();
@@ -26609,7 +26569,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (packageName == null || alias == null) {
return null;
}
- synchronized(mLock) {
+ synchronized (mLock) {
final AndroidPackage pkg = mPackages.get(packageName);
if (pkg == null
|| shouldFilterApplicationLocked(getPackageSetting(pkg.getPackageName()),
@@ -26656,7 +26616,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (packageName == null || ks == null) {
return false;
}
- synchronized(mLock) {
+ synchronized (mLock) {
final AndroidPackage pkg = mPackages.get(packageName);
if (pkg == null
|| shouldFilterApplicationLocked(getPackageSetting(pkg.getPackageName()),
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index bf82bd8b09d5..88dd03333262 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -176,6 +176,10 @@ public abstract class PackageSettingBase extends SettingBase {
name = orig.name;
realName = orig.realName;
doCopy(orig);
+ // Clone the user states.
+ for (int i = 0; i < mUserState.size(); i++) {
+ mUserState.put(mUserState.keyAt(i), new PackageUserState(mUserState.valueAt(i)));
+ }
}
public void setInstallerPackageName(String packageName) {
@@ -314,6 +318,7 @@ public abstract class PackageSettingBase extends SettingBase {
void setInstalled(boolean inst, int userId) {
modifyUserState(userId).installed = inst;
+ onChanged();
}
boolean getInstalled(int userId) {
@@ -326,6 +331,7 @@ public abstract class PackageSettingBase extends SettingBase {
void setInstallReason(int installReason, int userId) {
modifyUserState(userId).installReason = installReason;
+ onChanged();
}
int getUninstallReason(int userId) {
@@ -334,10 +340,13 @@ public abstract class PackageSettingBase extends SettingBase {
void setUninstallReason(@UninstallReason int uninstallReason, int userId) {
modifyUserState(userId).uninstallReason = uninstallReason;
+ onChanged();
}
boolean setOverlayPaths(OverlayPaths overlayPaths, int userId) {
- return modifyUserState(userId).setOverlayPaths(overlayPaths);
+ boolean returnValue = modifyUserState(userId).setOverlayPaths(overlayPaths);
+ onChanged();
+ return returnValue;
}
OverlayPaths getOverlayPaths(int userId) {
@@ -346,7 +355,10 @@ public abstract class PackageSettingBase extends SettingBase {
boolean setOverlayPathsForLibrary(String libName, OverlayPaths overlayPaths,
int userId) {
- return modifyUserState(userId).setSharedLibraryOverlayPaths(libName, overlayPaths);
+ boolean returnValue = modifyUserState(userId)
+ .setSharedLibraryOverlayPaths(libName, overlayPaths);
+ onChanged();
+ return returnValue;
}
Map<String, OverlayPaths> getOverlayPathsForLibrary(int userId) {
@@ -395,6 +407,7 @@ public abstract class PackageSettingBase extends SettingBase {
void setCeDataInode(long ceDataInode, int userId) {
modifyUserState(userId).ceDataInode = ceDataInode;
+ onChanged();
}
boolean getStopped(int userId) {
@@ -403,6 +416,7 @@ public abstract class PackageSettingBase extends SettingBase {
void setStopped(boolean stop, int userId) {
modifyUserState(userId).stopped = stop;
+ onChanged();
}
boolean getNotLaunched(int userId) {
@@ -411,6 +425,7 @@ public abstract class PackageSettingBase extends SettingBase {
void setNotLaunched(boolean stop, int userId) {
modifyUserState(userId).notLaunched = stop;
+ onChanged();
}
boolean getHidden(int userId) {
@@ -419,6 +434,7 @@ public abstract class PackageSettingBase extends SettingBase {
void setHidden(boolean hidden, int userId) {
modifyUserState(userId).hidden = hidden;
+ onChanged();
}
int getDistractionFlags(int userId) {
@@ -427,6 +443,7 @@ public abstract class PackageSettingBase extends SettingBase {
void setDistractionFlags(int distractionFlags, int userId) {
modifyUserState(userId).distractionFlags = distractionFlags;
+ onChanged();
}
boolean getSuspended(int userId) {
@@ -487,6 +504,7 @@ public abstract class PackageSettingBase extends SettingBase {
void setInstantApp(boolean instantApp, int userId) {
modifyUserState(userId).instantApp = instantApp;
+ onChanged();
}
boolean getVirtulalPreload(int userId) {
@@ -495,6 +513,7 @@ public abstract class PackageSettingBase extends SettingBase {
void setVirtualPreload(boolean virtualPreload, int userId) {
modifyUserState(userId).virtualPreload = virtualPreload;
+ onChanged();
}
void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped,
@@ -547,20 +566,24 @@ public abstract class PackageSettingBase extends SettingBase {
void setEnabledComponents(ArraySet<String> components, int userId) {
modifyUserState(userId).enabledComponents = components;
+ onChanged();
}
void setDisabledComponents(ArraySet<String> components, int userId) {
modifyUserState(userId).disabledComponents = components;
+ onChanged();
}
void setEnabledComponentsCopy(ArraySet<String> components, int userId) {
modifyUserState(userId).enabledComponents = components != null
? new ArraySet<String>(components) : null;
+ onChanged();
}
void setDisabledComponentsCopy(ArraySet<String> components, int userId) {
modifyUserState(userId).disabledComponents = components != null
? new ArraySet<String>(components) : null;
+ onChanged();
}
PackageUserState modifyUserStateComponents(int userId, boolean disabled, boolean enabled) {
@@ -582,10 +605,12 @@ public abstract class PackageSettingBase extends SettingBase {
void addDisabledComponent(String componentClassName, int userId) {
modifyUserStateComponents(userId, true, false).disabledComponents.add(componentClassName);
+ onChanged();
}
void addEnabledComponent(String componentClassName, int userId) {
modifyUserStateComponents(userId, false, true).enabledComponents.add(componentClassName);
+ onChanged();
}
boolean enableComponentLPw(String componentClassName, int userId) {
@@ -593,6 +618,9 @@ public abstract class PackageSettingBase extends SettingBase {
boolean changed = state.disabledComponents != null
? state.disabledComponents.remove(componentClassName) : false;
changed |= state.enabledComponents.add(componentClassName);
+ if (changed) {
+ onChanged();
+ }
return changed;
}
@@ -601,6 +629,9 @@ public abstract class PackageSettingBase extends SettingBase {
boolean changed = state.enabledComponents != null
? state.enabledComponents.remove(componentClassName) : false;
changed |= state.disabledComponents.add(componentClassName);
+ if (changed) {
+ onChanged();
+ }
return changed;
}
@@ -610,6 +641,9 @@ public abstract class PackageSettingBase extends SettingBase {
? state.disabledComponents.remove(componentClassName) : false;
changed |= state.enabledComponents != null
? state.enabledComponents.remove(componentClassName) : false;
+ if (changed) {
+ onChanged();
+ }
return changed;
}
@@ -701,6 +735,7 @@ public abstract class PackageSettingBase extends SettingBase {
PackageSettingBase setPath(@NonNull File path) {
this.mPath = path;
this.mPathString = path.toString();
+ onChanged();
return this;
}
@@ -722,7 +757,9 @@ public abstract class PackageSettingBase extends SettingBase {
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public boolean overrideNonLocalizedLabelAndIcon(@NonNull ComponentName component,
@Nullable String label, @Nullable Integer icon, @UserIdInt int userId) {
- return modifyUserState(userId).overrideLabelAndIcon(component, label, icon);
+ boolean returnValue = modifyUserState(userId).overrideLabelAndIcon(component, label, icon);
+ onChanged();
+ return returnValue;
}
/**
@@ -732,6 +769,7 @@ public abstract class PackageSettingBase extends SettingBase {
*/
public void resetOverrideComponentLabelIcon(@UserIdInt int userId) {
modifyUserState(userId).resetOverrideComponentLabelIcon();
+ onChanged();
}
/**
@@ -741,6 +779,7 @@ public abstract class PackageSettingBase extends SettingBase {
*/
public void setSplashScreenTheme(@UserIdInt int userId, @Nullable String themeName) {
modifyUserState(userId).splashScreenTheme = themeName;
+ onChanged();
}
/**
@@ -776,6 +815,7 @@ public abstract class PackageSettingBase extends SettingBase {
*/
public void setStatesOnCommit() {
incrementalStates.onCommit(IncrementalManager.isIncrementalPath(getPathString()));
+ onChanged();
}
/**
@@ -783,6 +823,7 @@ public abstract class PackageSettingBase extends SettingBase {
*/
public void setIncrementalStatesCallback(IncrementalStates.Callback callback) {
incrementalStates.setCallback(callback);
+ onChanged();
}
/**
@@ -791,6 +832,7 @@ public abstract class PackageSettingBase extends SettingBase {
*/
public void setLoadingProgress(float progress) {
incrementalStates.setProgress(progress);
+ onChanged();
}
public long getFirstInstallTime() {
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index 6014d0cee171..2491565dd376 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -255,7 +255,11 @@ public final class HintManagerService extends SystemService {
private boolean checkTidValid(int uid, int tgid, int [] tids) {
// Make sure all tids belongs to the same UID (including isolated UID),
// tids can belong to different application processes.
- List<Integer> eligiblePids = mAmInternal.getIsolatedProcesses(uid);
+ List<Integer> eligiblePids = null;
+ // To avoid deadlock, do not call into AMS if the call is from system.
+ if (uid != Process.SYSTEM_UID) {
+ eligiblePids = mAmInternal.getIsolatedProcesses(uid);
+ }
if (eligiblePids == null) {
eligiblePids = new ArrayList<>();
}
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index e85fa234a4ce..0f4f58b32c1b 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -228,17 +228,20 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
Vibration.Status status = null;
while (!mStepQueue.isEmpty()) {
- long waitTime = mStepQueue.calculateWaitTime();
- if (waitTime <= 0) {
- mStepQueue.consumeNext();
- } else {
- synchronized (mLock) {
+ long waitTime;
+ synchronized (mLock) {
+ waitTime = mStepQueue.calculateWaitTime();
+ if (waitTime > 0) {
try {
mLock.wait(waitTime);
} catch (InterruptedException e) {
}
}
}
+ // If we waited, the queue may have changed, so let the loop run again.
+ if (waitTime <= 0) {
+ mStepQueue.consumeNext();
+ }
Vibration.Status currentStatus = mStop ? Vibration.Status.CANCELLED
: mStepQueue.calculateVibrationStatus(sequentialEffectSize);
if (status == null && currentStatus != Vibration.Status.RUNNING) {
@@ -387,15 +390,13 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
}
/** Returns the time in millis to wait before calling {@link #consumeNext()}. */
+ @GuardedBy("mLock")
public long calculateWaitTime() {
- Step nextStep;
- synchronized (mLock) {
- if (!mPendingOnVibratorCompleteSteps.isEmpty()) {
- // Steps anticipated by vibrator complete callback should be played right away.
- return 0;
- }
- nextStep = mNextSteps.peek();
+ if (!mPendingOnVibratorCompleteSteps.isEmpty()) {
+ // Steps anticipated by vibrator complete callback should be played right away.
+ return 0;
}
+ Step nextStep = mNextSteps.peek();
return nextStep == null ? 0 : nextStep.calculateWaitTime();
}
@@ -603,7 +604,10 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
return false;
}
- /** Returns the time in millis to wait before playing this step. */
+ /**
+ * Returns the time in millis to wait before playing this step. This is performed
+ * while holding the queue lock, so should not rely on potentially slow operations.
+ */
public long calculateWaitTime() {
if (startTime == Long.MAX_VALUE) {
// This step don't have a predefined start time, it's just marked to be executed
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 331b8dee4870..675c7eb23f2c 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -1197,10 +1197,10 @@ class ActivityClientController extends IActivityClientController.Stub {
final Task task = r.getTask();
isLastRunningActivity = task.topRunningActivity() == r;
- final Intent baseIntent = task.getBaseIntent();
- final boolean activityIsBaseActivity = baseIntent != null
- && r.mActivityComponent.equals(baseIntent.getComponent());
- baseActivityIntent = activityIsBaseActivity ? r.intent : null;
+
+ final boolean isBaseActivity = r.mActivityComponent.equals(task.realActivity);
+ baseActivityIntent = isBaseActivity ? r.intent : null;
+
launchedFromHome = r.isLaunchSourceType(ActivityRecord.LAUNCH_SOURCE_TYPE_HOME);
}
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 005a62a208eb..20958aa1c9b1 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -633,6 +633,7 @@ class ActivityMetricsLogger {
if (crossPackage) {
startLaunchTrace(info);
}
+ scheduleCheckActivityToBeDrawnIfSleeping(launchedActivity);
return;
}
@@ -654,13 +655,7 @@ class ActivityMetricsLogger {
// As abort for no process switch.
launchObserverNotifyIntentFailed();
}
- if (launchedActivity.mDisplayContent.isSleeping()) {
- // It is unknown whether the activity can be drawn or not, e.g. it depends on the
- // keyguard states and the attributes or flags set by the activity. If the activity
- // keeps invisible in the grace period, the tracker will be cancelled so it won't get
- // a very long launch time that takes unlocking as the end of launch.
- scheduleCheckActivityToBeDrawn(launchedActivity, UNKNOWN_VISIBILITY_CHECK_DELAY_MS);
- }
+ scheduleCheckActivityToBeDrawnIfSleeping(launchedActivity);
// If the previous transitions are no longer visible, abort them to avoid counting the
// launch time when resuming from back stack. E.g. launch 2 independent tasks in a short
@@ -675,6 +670,16 @@ class ActivityMetricsLogger {
}
}
+ private void scheduleCheckActivityToBeDrawnIfSleeping(@NonNull ActivityRecord r) {
+ if (r.mDisplayContent.isSleeping()) {
+ // It is unknown whether the activity can be drawn or not, e.g. it depends on the
+ // keyguard states and the attributes or flags set by the activity. If the activity
+ // keeps invisible in the grace period, the tracker will be cancelled so it won't get
+ // a very long launch time that takes unlocking as the end of launch.
+ scheduleCheckActivityToBeDrawn(r, UNKNOWN_VISIBILITY_CHECK_DELAY_MS);
+ }
+ }
+
/**
* Notifies the tracker that all windows of the app have been drawn.
*
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 5970f622955e..54c660e93c42 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -330,8 +330,6 @@ import com.android.internal.policy.AttributeCache;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ToBooleanFunction;
import com.android.internal.util.XmlUtils;
-import com.android.internal.util.function.pooled.PooledFunction;
-import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.am.AppTimeTracker;
import com.android.server.am.PendingIntentRecord;
@@ -704,8 +702,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private boolean mInSizeCompatModeForBounds = false;
// Whether the aspect ratio restrictions applied to the activity bounds in applyAspectRatio().
- // TODO(b/182268157): Aspect ratio can also be applie in resolveFixedOrientationConfiguration
- // but that isn't reflected in this boolean.
private boolean mIsAspectRatioApplied = false;
// Bounds populated in resolveFixedOrientationConfiguration when this activity is letterboxed
@@ -746,6 +742,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
boolean startingDisplayed;
boolean startingMoved;
+ /**
+ * If it is non-null, it requires all activities who have the same starting data to be drawn
+ * to remove the starting window.
+ * TODO(b/189385912): Remove starting window related fields after migrating them to task.
+ */
+ private StartingData mSharedStartingData;
+
boolean mHandleExitSplashScreen;
@TransferSplashScreenState
int mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_IDLE;
@@ -1085,6 +1088,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn);
pw.print(" mIsExiting="); pw.println(mIsExiting);
}
+ if (mSharedStartingData != null) {
+ pw.println(prefix + "mSharedStartingData=" + mSharedStartingData);
+ }
if (mStartingWindow != null || mStartingSurface != null
|| startingDisplayed || startingMoved || mVisibleSetFromTransferredStartingWindow) {
pw.print(prefix); pw.print("startingWindow="); pw.print(mStartingWindow);
@@ -1173,7 +1179,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
header.run();
}
- String innerPrefix = prefix + " ";
+ String innerPrefix = prefix + " ";
String[] args = new String[0];
if (lastTask != r.getTask()) {
lastTask = r.getTask();
@@ -1379,9 +1385,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
@Override
- void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
- final Task oldTask = oldParent != null ? ((TaskFragment) oldParent).getTask() : null;
- final Task newTask = newParent != null ? ((TaskFragment) newParent).getTask() : null;
+ void onParentChanged(ConfigurationContainer rawNewParent, ConfigurationContainer rawOldParent) {
+ final TaskFragment oldParent = (TaskFragment) rawOldParent;
+ final TaskFragment newParent = (TaskFragment) rawNewParent;
+ final Task oldTask = oldParent != null ? oldParent.getTask() : null;
+ final Task newTask = newParent != null ? newParent.getTask() : null;
this.task = newTask;
super.onParentChanged(newParent, oldParent);
@@ -1440,11 +1448,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
updateColorTransform();
if (oldParent != null) {
- ((TaskFragment) oldParent).cleanUpActivityReferences(this);
+ oldParent.cleanUpActivityReferences(this);
}
if (newParent != null && isState(RESUMED)) {
- ((TaskFragment) newParent).setResumedActivity(this, "onParentChanged");
+ newParent.setResumedActivity(this, "onParentChanged");
+ if (mStartingWindow != null && mStartingData != null
+ && mStartingData.mAssociatedTask == null && newParent.isEmbedded()) {
+ // The starting window should keep covering its task when the activity is
+ // reparented to a task fragment that may not fill the task bounds.
+ associateStartingDataWithTask();
+ overrideConfigurationPropagation(mStartingWindow, task);
+ }
}
if (rootTask != null && rootTask.topRunningActivity() == this) {
@@ -2005,7 +2020,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@VisibleForTesting
boolean addStartingWindow(String pkg, int resolvedTheme, CompatibilityInfo compatInfo,
CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
- IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
+ ActivityRecord from, boolean newTask, boolean taskSwitch, boolean processRunning,
boolean allowTaskSnapshot, boolean activityCreated, boolean useEmpty) {
// If the display is frozen, we won't do anything until the actual window is
// displayed so there is no reason to put in the starting window.
@@ -2064,7 +2079,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
applyStartingWindowTheme(pkg, resolvedTheme);
- if (transferStartingWindow(transferFrom)) {
+ if (from != null && transferStartingWindow(from)) {
return true;
}
@@ -2089,6 +2104,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SnapshotStartingData");
mStartingData = new SnapshotStartingData(mWmService, snapshot, typeParams);
+ if (task.forAllLeafTaskFragments(TaskFragment::isEmbedded)) {
+ // Associate with the task so if this activity is resized by task fragment later, the
+ // starting window can keep the same bounds as the task.
+ associateStartingDataWithTask();
+ }
scheduleAddStartingWindow();
return true;
}
@@ -2337,6 +2357,23 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
+ void attachStartingWindow(@NonNull WindowState startingWindow) {
+ mStartingWindow = startingWindow;
+ if (mStartingData != null && mStartingData.mAssociatedTask != null) {
+ // Associate the configuration of starting window with the task.
+ overrideConfigurationPropagation(startingWindow, mStartingData.mAssociatedTask);
+ }
+ }
+
+ private void associateStartingDataWithTask() {
+ mStartingData.mAssociatedTask = task;
+ task.forAllActivities(r -> {
+ if (r.mVisibleRequested && !r.firstWindowDrawn) {
+ r.mSharedStartingData = mStartingData;
+ }
+ });
+ }
+
void removeStartingWindow() {
if (transferSplashScreenIfNeeded()) {
return;
@@ -2346,6 +2383,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
void removeStartingWindowAnimation(boolean prepareAnimation) {
mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_IDLE;
+ if (mSharedStartingData != null) {
+ mSharedStartingData.mAssociatedTask.forAllActivities(r -> {
+ r.mSharedStartingData = null;
+ });
+ }
if (mStartingWindow == null) {
if (mStartingData != null) {
// Starting window has not been added yet, but it is scheduled to be added.
@@ -2402,20 +2444,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- private void removeAppTokenFromDisplay() {
- if (mWmService.mRoot == null) return;
-
- final DisplayContent dc = mWmService.mRoot.getDisplayContent(getDisplayId());
- if (dc == null) {
- Slog.w(TAG, "removeAppTokenFromDisplay: Attempted to remove token: "
- + appToken + " from non-existing displayId=" + getDisplayId());
- return;
- }
- // Resume key dispatching if it is currently paused before we remove the container.
- resumeKeyDispatchingLocked();
- dc.removeAppToken(appToken.asBinder());
- }
-
/**
* Reparents this activity into {@param newTaskFrag} at the provided {@param position}. The
* caller should ensure that the {@param newTaskFrag} is not already the parent of this
@@ -2826,7 +2854,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
/**
* @return Whether AppOps allows this package to enter picture-in-picture.
*/
- private boolean checkEnterPictureInPictureAppOpsState() {
+ boolean checkEnterPictureInPictureAppOpsState() {
return mAtmService.getAppOpsManager().checkOpNoThrow(
OP_PICTURE_IN_PICTURE, info.applicationInfo.uid, packageName) == MODE_ALLOWED;
}
@@ -2966,7 +2994,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@interface FinishRequest {}
/**
- * See {@link #finishIfPossible(int, Intent, String, boolean)}
+ * See {@link #finishIfPossible(int, Intent, NeededUriGrants, String, boolean)}
*/
@FinishRequest int finishIfPossible(String reason, boolean oomAdj) {
return finishIfPossible(Activity.RESULT_CANCELED,
@@ -3428,7 +3456,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
setState(DESTROYED, "removeFromHistory");
if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + this);
detachFromProcess();
- removeAppTokenFromDisplay();
+ // Resume key dispatching if it is currently paused before we remove the container.
+ resumeKeyDispatchingLocked();
+ mDisplayContent.removeAppToken(appToken);
cleanUpActivityServices();
removeUriPermissionsLocked();
@@ -3453,7 +3483,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (stopped) {
abortAndClearOptionsAnimation();
}
- mAtmService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CLOSE, this);
+ if (mAtmService.getTransitionController().isCollecting()) {
+ // We don't want the finishing to change the transition ready state since there will not
+ // be corresponding setReady for finishing.
+ mAtmService.getTransitionController().collectExistenceChange(this);
+ } else {
+ mAtmService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CLOSE, this);
+ }
}
/**
@@ -3639,12 +3675,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@Override
void removeImmediately() {
- if (!finishing) {
+ if (mState != DESTROYED) {
+ Slog.w(TAG, "Force remove immediately " + this + " state=" + mState);
// If Task#removeImmediately is called directly with alive activities, ensure that the
// activities are destroyed and detached from process.
destroyImmediately("removeImmediately");
+ // Complete the destruction immediately because this activity will not be found in
+ // hierarchy, it is unable to report completion.
+ destroyed("removeImmediately");
+ } else {
+ onRemovedFromDisplay();
}
- onRemovedFromDisplay();
super.removeImmediately();
}
@@ -3858,12 +3899,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- boolean transferStartingWindow(IBinder transferFrom) {
- final ActivityRecord fromActivity = getDisplayContent().getActivityRecord(transferFrom);
- if (fromActivity == null) {
- return false;
- }
-
+ private boolean transferStartingWindow(@NonNull ActivityRecord fromActivity) {
final WindowState tStartingWindow = fromActivity.mStartingWindow;
if (tStartingWindow != null && fromActivity.mStartingSurface != null) {
// In this case, the starting icon has already been displayed, so start
@@ -3884,6 +3920,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Transfer the starting window over to the new token.
mStartingData = fromActivity.mStartingData;
+ mSharedStartingData = fromActivity.mSharedStartingData;
mStartingSurface = fromActivity.mStartingSurface;
startingDisplayed = fromActivity.startingDisplayed;
fromActivity.startingDisplayed = false;
@@ -3946,6 +3983,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
"Moving pending starting from %s to %s", fromActivity, this);
mStartingData = fromActivity.mStartingData;
+ mSharedStartingData = fromActivity.mSharedStartingData;
fromActivity.mStartingData = null;
fromActivity.startingMoved = true;
scheduleAddStartingWindow();
@@ -3964,16 +4002,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* immediately finishes after, so we have to transfer T to M.
*/
void transferStartingWindowFromHiddenAboveTokenIfNeeded() {
- final PooledFunction p = PooledLambda.obtainFunction(ActivityRecord::transferStartingWindow,
- this, PooledLambda.__(ActivityRecord.class));
- task.forAllActivities(p);
- p.recycle();
- }
-
- private boolean transferStartingWindow(ActivityRecord fromActivity) {
- if (fromActivity == this) return true;
-
- return !fromActivity.mVisibleRequested && transferStartingWindow(fromActivity.token);
+ task.forAllActivities(fromActivity -> {
+ if (fromActivity == this) return true;
+ return !fromActivity.mVisibleRequested && transferStartingWindow(fromActivity);
+ });
}
void checkKeyguardFlagsChanged() {
@@ -5154,6 +5186,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
void notifyAppStopped() {
ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppStopped: %s", this);
mAppStopped = true;
+ firstWindowDrawn = false;
// This is to fix the edge case that auto-enter-pip is finished in Launcher but app calls
// setAutoEnterEnabled(false) and transitions to STOPPED state, see b/191930787.
// Clear any surface transactions and content overlay in this case.
@@ -5917,7 +5950,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) {
+ void onFirstWindowDrawn(WindowState win) {
firstWindowDrawn = true;
// stop tracking
mSplashScreenStyleEmpty = true;
@@ -5933,7 +5966,22 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// own stuff.
win.cancelAnimation();
}
- removeStartingWindow();
+
+ // Remove starting window directly if is in a pure task. Otherwise if it is associated with
+ // a task (e.g. nested task fragment), then remove only if all visible windows in the task
+ // are drawn.
+ final Task associatedTask =
+ mSharedStartingData != null ? mSharedStartingData.mAssociatedTask : null;
+ if (associatedTask == null) {
+ removeStartingWindow();
+ } else if (associatedTask.getActivity(
+ r -> r.mVisibleRequested && !r.firstWindowDrawn) == null) {
+ // The last drawn activity may not be the one that owns the starting window.
+ final ActivityRecord r = associatedTask.topActivityContainsStartingWindow();
+ if (r != null) {
+ r.removeStartingWindow();
+ }
+ }
updateReportedVisibilityLocked();
}
@@ -6504,8 +6552,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final boolean scheduled = addStartingWindow(packageName, resolvedTheme,
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
- prev != null ? prev.appToken : null,
- newTask || newSingleActivity, taskSwitch, isProcessRunning(),
+ prev, newTask || newSingleActivity, taskSwitch, isProcessRunning(),
allowTaskSnapshot(), activityCreated, mSplashScreenStyleEmpty);
if (DEBUG_STARTING_WINDOW_VERBOSE && scheduled) {
Slog.d(TAG, "Scheduled starting window for " + this);
@@ -6570,17 +6617,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- boolean hasWindowsAlive() {
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- // No need to loop through child windows as the answer should be the same as that of the
- // parent window.
- if (!(mChildren.get(i)).mAppDied) {
- return true;
- }
- }
- return false;
- }
-
void setWillReplaceWindows(boolean animate) {
ProtoLog.d(WM_DEBUG_ADD_REMOVE,
"Marking app token %s with replacing windows.", this);
@@ -7448,11 +7484,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* requested orientation. If not, it may be necessary to letterbox the window.
* @param parentBounds are the new parent bounds passed down to the activity and should be used
* to compute the stable bounds.
- * @param outBounds will store the stable bounds, which are the bounds with insets applied.
- * These should be used to compute letterboxed bounds if orientation is not
- * respected when insets are applied.
+ * @param outStableBounds will store the stable bounds, which are the bounds with insets
+ * applied, if orientation is not respected when insets are applied.
+ * Otherwise outStableBounds will be empty. Stable bounds should be used
+ * to compute letterboxed bounds if orientation is not respected when
+ * insets are applied.
*/
- private boolean orientationRespectedWithInsets(Rect parentBounds, Rect outBounds) {
+ private boolean orientationRespectedWithInsets(Rect parentBounds, Rect outStableBounds) {
+ outStableBounds.setEmpty();
if (mDisplayContent == null) {
return true;
}
@@ -7467,17 +7506,21 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Compute orientation from stable parent bounds (= parent bounds with insets applied)
final Task task = getTask();
task.calculateInsetFrames(mTmpOutNonDecorBounds /* outNonDecorBounds */,
- outBounds /* outStableBounds */, parentBounds /* bounds */,
+ outStableBounds /* outStableBounds */, parentBounds /* bounds */,
mDisplayContent.getDisplayInfo());
- final int orientationWithInsets = outBounds.height() >= outBounds.width()
+ final int orientationWithInsets = outStableBounds.height() >= outStableBounds.width()
? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
// If orientation does not match the orientation with insets applied, then a
// display rotation will not be enough to respect orientation. However, even if they do
// not match but the orientation with insets applied matches the requested orientation, then
// there is no need to modify the bounds because when insets are applied, the activity will
// have the desired orientation.
- return orientation == orientationWithInsets
+ final boolean orientationRespectedWithInsets = orientation == orientationWithInsets
|| orientationWithInsets == requestedOrientation;
+ if (orientationRespectedWithInsets) {
+ outStableBounds.setEmpty();
+ }
+ return orientationRespectedWithInsets;
}
/**
@@ -7495,9 +7538,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
int windowingMode) {
mLetterboxBoundsForFixedOrientationAndAspectRatio = null;
final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
- final Rect containerBounds = new Rect(parentBounds);
+ final Rect stableBounds = new Rect();
+ // If orientation is respected when insets are applied, then stableBounds will be empty.
boolean orientationRespectedWithInsets =
- orientationRespectedWithInsets(parentBounds, containerBounds);
+ orientationRespectedWithInsets(parentBounds, stableBounds);
if (handlesOrientationChangeFromDescendant() && orientationRespectedWithInsets) {
// No need to letterbox because of fixed orientation. Display will handle
// fixed-orientation requests and a display rotation is enough to respect requested
@@ -7534,71 +7578,68 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return;
}
- // TODO(b/182268157) merge aspect ratio logic here and in
- // {@link ActivityRecord#applyAspectRatio}
- // if no aspect ratio constraints are provided, parent aspect ratio is used
- float aspectRatio = computeAspectRatio(parentBounds);
-
- // Override from config_fixedOrientationLetterboxAspectRatio or via ADB with
- // set-fixed-orientation-letterbox-aspect-ratio.
- final float letterboxAspectRatioOverride =
- mWmService.mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
- aspectRatio = letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
- ? letterboxAspectRatioOverride : aspectRatio;
-
- // Adjust the fixed orientation letterbox bounds to fit the app request aspect ratio in
- // order to use the extra available space.
- final float maxAspectRatio = info.getMaxAspectRatio();
- final float minAspectRatio = info.getMinAspectRatio();
- if (aspectRatio > maxAspectRatio && maxAspectRatio != 0) {
- aspectRatio = maxAspectRatio;
- } else if (aspectRatio < minAspectRatio) {
- aspectRatio = minAspectRatio;
+ // TODO(b/182268157): Explore using only one type of parentBoundsWithInsets, either app
+ // bounds or stable bounds to unify aspect ratio logic.
+ final Rect parentBoundsWithInsets = orientationRespectedWithInsets
+ ? newParentConfig.windowConfiguration.getAppBounds() : stableBounds;
+ final Rect containingBounds = new Rect();
+ final Rect containingBoundsWithInsets = new Rect();
+ // Need to shrink the containing bounds into a square because the parent orientation
+ // does not match the activity requested orientation.
+ if (forcedOrientation == ORIENTATION_LANDSCAPE) {
+ // Landscape is defined as width > height. Make the container respect landscape
+ // orientation by shrinking height to one less than width. Landscape activity will be
+ // vertically centered within parent bounds with insets, so position vertical bounds
+ // within parent bounds with insets to prevent insets from unnecessarily trimming
+ // vertical bounds.
+ final int bottom = Math.min(parentBoundsWithInsets.top + parentBounds.width() - 1,
+ parentBoundsWithInsets.bottom);
+ containingBounds.set(parentBounds.left, parentBoundsWithInsets.top, parentBounds.right,
+ bottom);
+ containingBoundsWithInsets.set(parentBoundsWithInsets.left, parentBoundsWithInsets.top,
+ parentBoundsWithInsets.right, bottom);
+ } else {
+ // Portrait is defined as width <= height. Make the container respect portrait
+ // orientation by shrinking width to match height. Portrait activity will be
+ // horizontally centered within parent bounds with insets, so position horizontal bounds
+ // within parent bounds with insets to prevent insets from unnecessarily trimming
+ // horizontal bounds.
+ final int right = Math.min(parentBoundsWithInsets.left + parentBounds.height(),
+ parentBoundsWithInsets.right);
+ containingBounds.set(parentBoundsWithInsets.left, parentBounds.top, right,
+ parentBounds.bottom);
+ containingBoundsWithInsets.set(parentBoundsWithInsets.left, parentBoundsWithInsets.top,
+ right, parentBoundsWithInsets.bottom);
}
// Store the current bounds to be able to revert to size compat mode values below if needed.
final Rect prevResolvedBounds = new Rect(resolvedBounds);
+ resolvedBounds.set(containingBounds);
- // Compute other dimension based on aspect ratio. Use bounds intersected with insets, stored
- // in containerBounds after calling {@link ActivityRecord#orientationRespectedWithInsets()},
- // to ensure that aspect ratio is respected after insets are applied.
- int activityWidth;
- int activityHeight;
+ // Override from config_fixedOrientationLetterboxAspectRatio or via ADB with
+ // set-fixed-orientation-letterbox-aspect-ratio.
+ final float letterboxAspectRatioOverride =
+ mWmService.mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
+ final float desiredAspectRatio =
+ letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
+ ? letterboxAspectRatioOverride : computeAspectRatio(parentBounds);
+ // Apply aspect ratio to resolved bounds
+ mIsAspectRatioApplied = applyAspectRatio(resolvedBounds, containingBoundsWithInsets,
+ containingBounds, desiredAspectRatio, true);
+
+ // Vertically center if orientation is landscape. Center within parent bounds with insets
+ // to ensure that insets do not trim height. Bounds will later be horizontally centered in
+ // {@link updateResolvedBoundsHorizontalPosition()} regardless of orientation.
if (forcedOrientation == ORIENTATION_LANDSCAPE) {
- activityWidth = parentBounds.width();
- // Compute height from stable bounds width to ensure orientation respected after insets.
- activityHeight = (int) Math.rint(containerBounds.width() / aspectRatio);
- // Landscape is defined as width > height. To ensure activity is landscape when aspect
- // ratio is close to 1, reduce the height by one pixel.
- if (activityWidth == activityHeight) {
- activityHeight -= 1;
- }
- // Center vertically within stable bounds in landscape to ensure insets do not trim
- // height.
- final int top = containerBounds.centerY() - activityHeight / 2;
- resolvedBounds.set(parentBounds.left, top, parentBounds.right, top + activityHeight);
- } else {
- activityHeight = parentBounds.height();
- // Compute width from stable bounds height to ensure orientation respected after insets.
- activityWidth = (int) Math.rint(containerBounds.height() / aspectRatio);
- // Center horizontally in portrait. For now, align to left and allow
- // {@link ActivityRecord#updateResolvedBoundsHorizontalPosition()} to center
- // horizontally. Exclude left insets from parent to ensure cutout does not trim width.
- final Rect parentAppBounds = newParentConfig.windowConfiguration.getAppBounds();
- resolvedBounds.set(parentAppBounds.left, parentBounds.top,
- parentAppBounds.left + activityWidth, parentBounds.bottom);
+ final int offsetY = parentBoundsWithInsets.centerY() - resolvedBounds.centerY();
+ resolvedBounds.offset(0, offsetY);
}
if (mCompatDisplayInsets != null) {
mCompatDisplayInsets.getBoundsByRotation(
mTmpBounds, newParentConfig.windowConfiguration.getRotation());
- // Insets may differ between different rotations, for example in the case of a display
- // cutout. To ensure consistent bounds across rotations, compare the activity dimensions
- // minus insets from the rotation the compat bounds were computed in.
- Task.intersectWithInsetsIfFits(mTmpBounds, parentBounds,
- mCompatDisplayInsets.mStableInsets[mCompatDisplayInsets.mOriginalRotation]);
- if (activityWidth != mTmpBounds.width()
- || activityHeight != mTmpBounds.height()) {
+ if (resolvedBounds.width() != mTmpBounds.width()
+ || resolvedBounds.height() != mTmpBounds.height()) {
// The app shouldn't be resized, we only do fixed orientation letterboxing if the
// compat bounds are also from the same fixed orientation letterbox. Otherwise,
// clear the fixed orientation bounds to show app in size compat mode.
@@ -7634,8 +7675,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// then they should be aligned later in #updateResolvedBoundsHorizontalPosition().
if (!mTmpBounds.isEmpty()) {
resolvedBounds.set(mTmpBounds);
- // Exclude the horizontal decor area.
- resolvedBounds.left = parentAppBounds.left;
}
if (!resolvedBounds.isEmpty() && !resolvedBounds.equals(parentBounds)) {
// Compute the configuration based on the resolved bounds. If aspect ratio doesn't
@@ -7696,13 +7735,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mIsAspectRatioApplied =
applyAspectRatio(resolvedBounds, containingAppBounds, containingBounds);
}
- // If the bounds are restricted by fixed aspect ratio, the resolved bounds should be put in
- // the container app bounds. Otherwise the entire container bounds are available.
- final boolean fillContainer = resolvedBounds.equals(containingBounds);
- if (!fillContainer) {
- // The horizontal position should not cover insets.
- resolvedBounds.left = containingAppBounds.left;
- }
// Use resolvedBounds to compute other override configurations such as appBounds. The bounds
// are calculated in compat container space. The actual position on screen will be applied
@@ -7769,6 +7801,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Align to top of parent (bounds) - this is a UX choice and exclude the horizontal decor
// if needed. Horizontal position is adjusted in updateResolvedBoundsHorizontalPosition.
// Above coordinates are in "@" space, now place "*" and "#" to screen space.
+ final boolean fillContainer = resolvedBounds.equals(containingBounds);
final int screenPosX = fillContainer ? containerBounds.left : containerAppBounds.left;
final int screenPosY = containerBounds.top;
if (screenPosX != 0 || screenPosY != 0) {
@@ -8010,6 +8043,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return true;
}
+ private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
+ Rect containingBounds) {
+ return applyAspectRatio(outBounds, containingAppBounds, containingBounds,
+ 0 /* desiredAspectRatio */, false /* fixedOrientationLetterboxed */);
+ }
+
/**
* Applies aspect ratio restrictions to outBounds. If no restrictions, then no change is
* made to outBounds.
@@ -8018,17 +8057,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
*/
// TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
- Rect containingBounds) {
+ Rect containingBounds, float desiredAspectRatio, boolean fixedOrientationLetterboxed) {
final float maxAspectRatio = info.getMaxAspectRatio();
final Task rootTask = getRootTask();
final float minAspectRatio = info.getMinAspectRatio();
if (task == null || rootTask == null
- || (inMultiWindowMode() && !shouldCreateCompatDisplayInsets())
- || (maxAspectRatio == 0 && minAspectRatio == 0)
+ || (inMultiWindowMode() && !shouldCreateCompatDisplayInsets()
+ && !fixedOrientationLetterboxed)
+ || (maxAspectRatio < 1 && minAspectRatio < 1 && desiredAspectRatio < 1)
|| isInVrUiMode(getConfiguration())) {
- // We don't enforce aspect ratio if the activity task is in multiwindow unless it
- // is in size-compat mode. We also don't set it if we are in VR mode.
+ // We don't enforce aspect ratio if the activity task is in multiwindow unless it is in
+ // size-compat mode or is letterboxed from fixed orientation. We also don't set it if we
+ // are in VR mode.
return false;
}
@@ -8036,20 +8077,30 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final int containingAppHeight = containingAppBounds.height();
final float containingRatio = computeAspectRatio(containingAppBounds);
+ if (desiredAspectRatio < 1) {
+ desiredAspectRatio = containingRatio;
+ }
+
+ if (maxAspectRatio >= 1 && desiredAspectRatio > maxAspectRatio) {
+ desiredAspectRatio = maxAspectRatio;
+ } else if (minAspectRatio >= 1 && desiredAspectRatio < minAspectRatio) {
+ desiredAspectRatio = minAspectRatio;
+ }
+
int activityWidth = containingAppWidth;
int activityHeight = containingAppHeight;
- if (containingRatio > maxAspectRatio && maxAspectRatio != 0) {
+ if (containingRatio > desiredAspectRatio) {
if (containingAppWidth < containingAppHeight) {
// Width is the shorter side, so we use that to figure-out what the max. height
// should be given the aspect ratio.
- activityHeight = (int) ((activityWidth * maxAspectRatio) + 0.5f);
+ activityHeight = (int) ((activityWidth * desiredAspectRatio) + 0.5f);
} else {
// Height is the shorter side, so we use that to figure-out what the max. width
// should be given the aspect ratio.
- activityWidth = (int) ((activityHeight * maxAspectRatio) + 0.5f);
+ activityWidth = (int) ((activityHeight * desiredAspectRatio) + 0.5f);
}
- } else if (containingRatio < minAspectRatio) {
+ } else if (containingRatio < desiredAspectRatio) {
boolean adjustWidth;
switch (getRequestedConfigurationOrientation()) {
case ORIENTATION_LANDSCAPE:
@@ -8077,9 +8128,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
break;
}
if (adjustWidth) {
- activityWidth = (int) ((activityHeight / minAspectRatio) + 0.5f);
+ activityWidth = (int) ((activityHeight / desiredAspectRatio) + 0.5f);
} else {
- activityHeight = (int) ((activityWidth / minAspectRatio) + 0.5f);
+ activityHeight = (int) ((activityWidth / desiredAspectRatio) + 0.5f);
}
}
@@ -8103,6 +8154,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
outBounds.set(containingBounds.left, containingBounds.top, right, bottom);
+ // If the bounds are restricted by fixed aspect ratio, then out bounds should be put in the
+ // container app bounds. Otherwise the entire container bounds are available.
+ if (!outBounds.equals(containingBounds)) {
+ // The horizontal position should not cover insets (e.g. display cutout).
+ outBounds.left = containingAppBounds.left;
+ }
+
return true;
}
@@ -9069,7 +9127,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
record.mAdapter.mRootTaskBounds, task.getWindowConfiguration(),
false /*isNotInRecents*/,
record.mThumbnailAdapter != null ? record.mThumbnailAdapter.mCapturedLeash : null,
- record.mStartBounds, task.getTaskInfo());
+ record.mStartBounds, task.getTaskInfo(), checkEnterPictureInPictureAppOpsState());
}
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 4e73bf342054..c9f335618013 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -194,7 +194,6 @@ class ActivityStarter {
private Task mTargetTask;
private boolean mMovedToFront;
private boolean mNoAnimation;
- private boolean mKeepCurTransition;
private boolean mAvoidMoveToFront;
private boolean mFrozeTaskList;
private boolean mTransientLaunch;
@@ -593,7 +592,6 @@ class ActivityStarter {
mTargetRootTask = starter.mTargetRootTask;
mMovedToFront = starter.mMovedToFront;
mNoAnimation = starter.mNoAnimation;
- mKeepCurTransition = starter.mKeepCurTransition;
mAvoidMoveToFront = starter.mAvoidMoveToFront;
mFrozeTaskList = starter.mFrozeTaskList;
@@ -1708,6 +1706,8 @@ class ActivityStarter {
mIntent.setFlags(mLaunchFlags);
+ // Get top task at beginning because the order may be changed when reusing existing task.
+ final Task prevTopTask = mPreferredTaskDisplayArea.getFocusedRootTask();
final Task reusedTask = getReusableTask();
// If requested, freeze the task list
@@ -1787,24 +1787,23 @@ class ActivityStarter {
UserHandle.getAppId(mStartActivity.info.applicationInfo.uid) /*recipient*/,
resultToUid /*visible*/, true /*direct*/);
}
+ final Task startedTask = mStartActivity.getTask();
if (newTask) {
- EventLogTags.writeWmCreateTask(mStartActivity.mUserId,
- mStartActivity.getTask().mTaskId);
+ EventLogTags.writeWmCreateTask(mStartActivity.mUserId, startedTask.mTaskId);
}
- mStartActivity.logStartActivity(
- EventLogTags.WM_CREATE_ACTIVITY, mStartActivity.getTask());
+ mStartActivity.logStartActivity(EventLogTags.WM_CREATE_ACTIVITY, startedTask);
mStartActivity.getTaskFragment().clearLastPausedActivity();
mRootWindowContainer.startPowerModeLaunchIfNeeded(
false /* forceSend */, mStartActivity);
+ final boolean isTaskSwitch = startedTask != prevTopTask;
mTargetRootTask.startActivityLocked(mStartActivity,
topRootTask != null ? topRootTask.getTopNonFinishingActivity() : null, newTask,
- mKeepCurTransition, mOptions, sourceRecord);
+ isTaskSwitch, mOptions, sourceRecord);
if (mDoResume) {
- final ActivityRecord topTaskActivity =
- mStartActivity.getTask().topRunningActivityLocked();
+ final ActivityRecord topTaskActivity = startedTask.topRunningActivityLocked();
if (!mTargetRootTask.isTopActivityFocusable()
|| (topTaskActivity != null && topTaskActivity.isTaskOverlay()
&& mStartActivity != topTaskActivity)) {
@@ -1838,8 +1837,8 @@ class ActivityStarter {
mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetRootTask);
// Update the recent tasks list immediately when the activity starts
- mSupervisor.mRecentTasks.add(mStartActivity.getTask());
- mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(),
+ mSupervisor.mRecentTasks.add(startedTask);
+ mSupervisor.handleNonResizableTaskIfNeeded(startedTask,
mPreferredWindowingMode, mPreferredTaskDisplayArea, mTargetRootTask);
return START_SUCCESS;
@@ -2278,7 +2277,6 @@ class ActivityStarter {
mTargetTask = null;
mMovedToFront = false;
mNoAnimation = false;
- mKeepCurTransition = false;
mAvoidMoveToFront = false;
mFrozeTaskList = false;
mTransientLaunch = false;
@@ -2386,6 +2384,11 @@ class ActivityStarter {
}
mTransientLaunch = mOptions.getTransientLaunch();
mTargetRootTask = Task.fromWindowContainerToken(mOptions.getLaunchRootTask());
+
+ if (inTaskFragment == null) {
+ inTaskFragment = TaskFragment.fromTaskFragmentToken(
+ mOptions.getLaunchTaskFragmentToken(), mService);
+ }
}
mNotTop = (mLaunchFlags & FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? sourceRecord : null;
@@ -2781,7 +2784,8 @@ class ActivityStarter {
}
} else {
// Use the child TaskFragment (if any) as the new parent if the activity can be embedded
- final ActivityRecord top = task.topRunningActivity();
+ final ActivityRecord top = task.topRunningActivity(false /* focusableOnly */,
+ false /* includingEmbeddedTask */);
newParent = top != null ? top.getTaskFragment() : task;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 83c83e7b5f39..081c618b62aa 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1909,15 +1909,15 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (r.moveFocusableActivityToTop("setFocusedTask")) {
mRootWindowContainer.resumeFocusedTasksTopActivities();
- } else if (touchedActivity != null && touchedActivity != r
- && touchedActivity.getTask() == r.getTask()
- && touchedActivity.getTaskFragment() != r.getTaskFragment()) {
- // Set the focused app directly since the focused window is not on the
- // top-most TaskFragment of the top-most Task
- final DisplayContent displayContent = touchedActivity.getDisplayContent();
- displayContent.setFocusedApp(touchedActivity);
- mWindowManager.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
- true /* updateInputWindows */);
+ } else if (touchedActivity != null && touchedActivity.isFocusable()) {
+ final TaskFragment parent = touchedActivity.getTaskFragment();
+ if (parent != null && parent.isEmbedded()) {
+ // Set the focused app directly if the focused window is currently embedded
+ final DisplayContent displayContent = touchedActivity.getDisplayContent();
+ displayContent.setFocusedApp(touchedActivity);
+ mWindowManager.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
+ true /* updateInputWindows */);
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index f728a481dd52..50ac4330facd 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -352,6 +352,12 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
*/
private int mVisibilityTransactionDepth;
+ /**
+ * Whether to the visibility updates that started from {@code RootWindowContainer} should be
+ * deferred.
+ */
+ private boolean mDeferRootVisibilityUpdate;
+
private ActivityMetricsLogger mActivityMetricsLogger;
/** Check if placing task or activity on specified display is allowed. */
@@ -841,6 +847,10 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
proc.getThread(), r.appToken);
final boolean isTransitionForward = r.isTransitionForward();
+ IBinder fragmentToken = null;
+ if (r.getTaskFragment().getTaskFragmentOrganizerPid() == r.getPid()) {
+ fragmentToken = r.getTaskFragment().getFragmentToken();
+ }
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
@@ -852,7 +862,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
r.takeOptions(), isTransitionForward,
proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
r.createFixedRotationAdjustmentsIfNeeded(), r.shareableActivityToken,
- r.getLaunchedFromBubble()));
+ r.getLaunchedFromBubble(), fragmentToken));
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
@@ -1551,7 +1561,13 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
return;
}
if (task.isVisible()) {
- mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CLOSE, task);
+ if (mService.getTransitionController().isCollecting()) {
+ // We don't want the finishing to change the transition ready state since there will
+ // not be corresponding setReady for finishing.
+ mService.getTransitionController().collectExistenceChange(task);
+ } else {
+ mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CLOSE, task);
+ }
} else {
// Removing a non-visible task doesn't require a transition, but if there is one
// collecting, this should be a member just in case.
@@ -2287,6 +2303,14 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
return mVisibilityTransactionDepth > 0;
}
+ void setDeferRootVisibilityUpdate(boolean deferUpdate) {
+ mDeferRootVisibilityUpdate = deferUpdate;
+ }
+
+ boolean isRootVisibilityUpdateDeferred() {
+ return mDeferRootVisibilityUpdate;
+ }
+
/**
* Called when the state or visibility of an attached activity is changed.
*
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index c869ec67776d..d6b0086d8dd9 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -464,7 +464,8 @@ public class AppTransitionController {
}
final RemoteAnimationAdapter adapter =
getRemoteAnimationOverride(animLpActivity, transit, activityTypes);
- if (adapter != null) {
+ if (adapter != null
+ && mDisplayContent.mAppTransition.getRemoteAnimationController() == null) {
mDisplayContent.mAppTransition.overridePendingAppTransitionRemote(adapter);
}
}
diff --git a/services/core/java/com/android/server/wm/BlurController.java b/services/core/java/com/android/server/wm/BlurController.java
index 03639449c3df..41d9dbf894f4 100644
--- a/services/core/java/com/android/server/wm/BlurController.java
+++ b/services/core/java/com/android/server/wm/BlurController.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.os.PowerManager.THERMAL_STATUS_CRITICAL;
import static android.view.CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED;
import android.content.BroadcastReceiver;
@@ -45,6 +46,7 @@ final class BlurController {
private final Object mLock = new Object();
private volatile boolean mBlurEnabled;
private boolean mInPowerSaveMode;
+ private boolean mCriticalThermalStatus;
private boolean mBlurDisabledSetting;
private boolean mTunnelModeEnabled = false;
@@ -89,6 +91,12 @@ final class BlurController {
});
mBlurDisabledSetting = getBlurDisabledSetting();
+ powerManager.addThermalStatusListener((status) -> {
+ mCriticalThermalStatus = status >= THERMAL_STATUS_CRITICAL;
+ updateBlurEnabled();
+ });
+ mCriticalThermalStatus = powerManager.getCurrentThermalStatus() >= THERMAL_STATUS_CRITICAL;
+
TunnelModeEnabledListener.register(mTunnelModeListener);
updateBlurEnabled();
@@ -112,7 +120,7 @@ final class BlurController {
private void updateBlurEnabled() {
synchronized (mLock) {
final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED && !mBlurDisabledSetting
- && !mInPowerSaveMode && !mTunnelModeEnabled;
+ && !mInPowerSaveMode && !mTunnelModeEnabled && !mCriticalThermalStatus;
if (mBlurEnabled == newEnabled) {
return;
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 3f25350ced48..256d818061ba 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -134,7 +134,6 @@ import static com.android.server.wm.WindowManagerService.H.REPORT_HARD_KEYBOARD_
import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT;
import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
-import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_REMOVING_FOCUS;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_ASSIGN_LAYERS;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
@@ -434,6 +433,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// Accessed directly by all users.
private boolean mLayoutNeeded;
int pendingLayoutChanges;
+ boolean mLayoutAndAssignWindowLayersScheduled;
/**
* Used to gate application window layout until we have sent the complete configuration.
@@ -738,15 +738,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// dismissing during the task switching to keep the window focus because IME window has
// higher window hierarchy, we don't give it focus if the next IME layering target
// doesn't request IME visible.
- if (w.mIsImWindow && (mImeLayeringTarget == null
+ if (w.mIsImWindow && w.isChildWindow() && (mImeLayeringTarget == null
|| !mImeLayeringTarget.getRequestedVisibility(ITYPE_IME))) {
- if (w.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) {
- return false;
- }
-
- if (w.isChildWindow()) {
- return false;
- }
+ return false;
+ }
+ if (w.mAttrs.type == TYPE_INPUT_METHOD_DIALOG && mImeLayeringTarget != null
+ && !mImeLayeringTarget.getRequestedVisibility(ITYPE_IME)
+ && mImeLayeringTarget.isAnimating(PARENTS | TRANSITION,
+ ANIMATION_TYPE_APP_TRANSITION)) {
+ return false;
}
final ActivityRecord activity = w.mActivityRecord;
@@ -777,10 +777,19 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return true;
}
- if (focusedApp.getTask() == activity.getTask()
- && focusedApp.getTaskFragment() != activity.getTaskFragment()) {
- // Do not use the activity window of another TaskFragment in the same leaf Task
- return false;
+ // If the candidate activity is currently being embedded in the focused task, the
+ // activity cannot be focused unless it is on the same TaskFragment as the focusedApp's.
+ TaskFragment parent = activity.getTaskFragment();
+ if (parent != null && parent.isEmbedded()) {
+ Task hostTask = focusedApp.getTask();
+ if (hostTask.isEmbedded()) {
+ // Use the hosting task if the current task is embedded.
+ hostTask = hostTask.getParent().asTaskFragment().getTask();
+ }
+ if (activity.isDescendantOf(hostTask)
+ && activity.getTaskFragment() != focusedApp.getTaskFragment()) {
+ return false;
+ }
}
}
@@ -3431,13 +3440,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
}
- int focusChanged = getDisplayPolicy().focusChangedLw(oldFocus, newFocus);
+ getDisplayPolicy().focusChangedLw(oldFocus, newFocus);
if (imWindowChanged && oldFocus != mInputMethodWindow) {
// Focus of the input method window changed. Perform layout if needed.
if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
performLayout(true /*initial*/, updateInputWindows);
- focusChanged &= ~FINISH_LAYOUT_REDO_LAYOUT;
} else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
// Client will do the layout, but we need to assign layers
// for handleNewWindowLocked() below.
@@ -3445,16 +3453,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
}
- if ((focusChanged & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
- // The change in focus caused us to need to do a layout. Okay.
- setLayoutNeeded();
- if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
- performLayout(true /*initial*/, updateInputWindows);
- } else if (mode == UPDATE_FOCUS_REMOVING_FOCUS) {
- mWmService.mRoot.performSurfacePlacement();
- }
- }
-
if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
// If we defer assigning layers, then the caller is responsible for doing this part.
getInputMonitor().setInputFocusLw(newFocus, updateInputWindows);
@@ -4602,7 +4600,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return true;
}
- if (task.isOrganized()) {
+ // TODO(b/165794880): Freeform task organizer doesn't support drag-resize yet. Remove
+ // the special case when it does.
+ if (task.isOrganized() && task.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
return true;
}
@@ -4955,10 +4955,18 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
}
+ /**
+ * @deprecated new transition should use {@link #requestTransitionAndLegacyPrepare(int, int)}
+ */
+ @Deprecated
void prepareAppTransition(@WindowManager.TransitionType int transit) {
prepareAppTransition(transit, 0 /* flags */);
}
+ /**
+ * @deprecated new transition should use {@link #requestTransitionAndLegacyPrepare(int, int)}
+ */
+ @Deprecated
void prepareAppTransition(@WindowManager.TransitionType int transit,
@WindowManager.TransitionFlags int flags) {
final boolean prepared = mAppTransition.prepareAppTransition(transit, flags);
@@ -4971,7 +4979,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
* Helper that both requests a transition (using the new transition system) and prepares
* the legacy transition system. Use this when both systems have the same start-point.
*
- * @see TransitionController#requestTransitionIfNeeded(int, int, WindowContainer)
+ * @see TransitionController#requestTransitionIfNeeded(int, int, WindowContainer,
+ * WindowContainer)
* @see AppTransition#prepareAppTransition
*/
void requestTransitionAndLegacyPrepare(@WindowManager.TransitionType int transit,
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 686472f71fb4..c1d6c1765a7a 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1984,11 +1984,7 @@ public class DisplayPolicy {
mTopIsFullscreen = topIsFullscreen;
}
- if (updateSystemUiVisibilityLw()) {
- // If the navigation bar has been hidden or shown, we need to do another
- // layout pass to update that window.
- changes |= FINISH_LAYOUT_REDO_LAYOUT;
- }
+ updateSystemBarAttributes();
if (mShowingDream != mLastShowingDream) {
mLastShowingDream = mShowingDream;
@@ -2524,18 +2520,13 @@ public class DisplayPolicy {
/**
* A new window has been focused.
*/
- public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
+ public void focusChangedLw(WindowState lastFocus, WindowState newFocus) {
mFocusedWindow = newFocus;
mLastFocusedWindow = lastFocus;
if (mDisplayContent.isDefaultDisplay) {
mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus);
}
- if (updateSystemUiVisibilityLw()) {
- // If the navigation bar has been hidden or shown, we need to do another
- // layout pass to update that window.
- return FINISH_LAYOUT_REDO_LAYOUT;
- }
- return 0;
+ updateSystemBarAttributes();
}
private void requestTransientBars(WindowState swipeTarget) {
@@ -2611,21 +2602,18 @@ public class DisplayPolicy {
return mDisplayContent.getInsetsPolicy();
}
- void resetSystemUiVisibilityLw() {
+ void resetSystemBarAttributes() {
mLastDisableFlags = 0;
- updateSystemUiVisibilityLw();
+ updateSystemBarAttributes();
}
- /**
- * @return {@code true} if the update may affect the layout.
- */
- boolean updateSystemUiVisibilityLw() {
+ void updateSystemBarAttributes() {
// If there is no window focused, there will be nobody to handle the events
// anyway, so just hang on in whatever state we're in until things settle down.
WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
: mTopFullscreenOpaqueWindowState;
if (winCandidate == null) {
- return false;
+ return;
}
// The immersive mode confirmation should never affect the system bar visibility, otherwise
@@ -2641,7 +2629,7 @@ public class DisplayPolicy {
: lastFocusCanReceiveKeys ? mLastFocusedWindow
: mTopFullscreenOpaqueWindowState;
if (winCandidate == null) {
- return false;
+ return;
}
}
final WindowState win = winCandidate;
@@ -2680,7 +2668,7 @@ public class DisplayPolicy {
&& Objects.equals(mFocusedApp, focusedApp)
&& mLastFocusIsFullscreen == isFullscreen
&& Arrays.equals(mLastStatusBarAppearanceRegions, appearanceRegions)) {
- return false;
+ return;
}
if (mDisplayContent.isDefaultDisplay && mLastFocusIsFullscreen != isFullscreen
&& ((mLastAppearance ^ appearance) & APPEARANCE_LOW_PROFILE_BARS) != 0) {
@@ -2698,7 +2686,6 @@ public class DisplayPolicy {
callStatusBarSafely(statusBar -> statusBar.onSystemBarAttributesChanged(displayId,
appearance, appearanceRegions, isNavbarColorManagedByIme, behavior,
requestedVisibilities, focusedApp));
- return true;
}
private int getStatusBarAppearance(WindowState opaque, WindowState opaqueOrDimming) {
@@ -2970,7 +2957,7 @@ public class DisplayPolicy {
return;
}
mPendingPanicGestureUptime = SystemClock.uptimeMillis();
- updateSystemUiVisibilityLw();
+ updateSystemBarAttributes();
}
}
};
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 8c781a13f7db..d819557006a6 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -307,7 +307,10 @@ final class InputMonitor {
boolean useSurfaceCrop = false;
final Task task = w.getTask();
if (task != null) {
- if (task.isOrganized() && task.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
+ // TODO(b/165794636): Remove the special case for freeform window once drag resizing is
+ // handled by WM shell.
+ if (task.isOrganized() && task.getWindowingMode() != WINDOWING_MODE_FULLSCREEN
+ && !task.inFreeformWindowingMode()) {
// If the window is in a TaskManaged by a TaskOrganizer then most cropping will
// be applied using the SurfaceControl hierarchy from the Organizer. This means
// we need to make sure that these changes in crop are reflected in the input
@@ -539,7 +542,8 @@ final class InputMonitor {
if (mAddRecentsAnimationInputConsumerHandle && shouldApplyRecentsInputConsumer) {
if (recentsAnimationController.updateInputConsumerForApp(
mRecentsAnimationInputConsumer.mWindowHandle)) {
- mRecentsAnimationInputConsumer.show(mInputTransaction, w.mActivityRecord);
+ mRecentsAnimationInputConsumer.show(mInputTransaction,
+ recentsAnimationController.getHighestLayerTask());
mAddRecentsAnimationInputConsumerHandle = false;
}
}
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index cbd1314b104a..f3e52f28ba8b 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -376,8 +376,11 @@ class InsetsSourceProvider {
return;
}
mClientVisible = clientVisible;
- mDisplayContent.mWmService.mH.obtainMessage(
- LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED, mDisplayContent).sendToTarget();
+ if (!mDisplayContent.mLayoutAndAssignWindowLayersScheduled) {
+ mDisplayContent.mLayoutAndAssignWindowLayersScheduled = true;
+ mDisplayContent.mWmService.mH.obtainMessage(
+ LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED, mDisplayContent).sendToTarget();
+ }
updateVisibility();
}
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 655007cf3cd1..2c4adcbf1404 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -385,7 +385,7 @@ class InsetsStateController {
if (changed) {
notifyInsetsChanged();
mDisplayContent.updateSystemGestureExclusion();
- mDisplayContent.getDisplayPolicy().updateSystemUiVisibilityLw();
+ mDisplayContent.getDisplayPolicy().updateSystemBarAttributes();
}
}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 9cd8c2d8ee53..d67d5fa7db4f 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -378,15 +378,17 @@ class KeyguardController {
mService.deferWindowLayout();
try {
mRootWindowContainer.getDefaultDisplay()
- .prepareAppTransition(
+ .requestTransitionAndLegacyPrepare(
isDisplayOccluded(DEFAULT_DISPLAY)
? TRANSIT_KEYGUARD_OCCLUDE
- : TRANSIT_KEYGUARD_UNOCCLUDE);
+ : TRANSIT_KEYGUARD_UNOCCLUDE, 0 /* flags */);
// When the occluding activity also turns on the display, visibility of the activity
// can be committed before KEYGUARD_OCCLUDE transition is handled.
// Set mRequestForceTransition flag to make sure that the app transition animation
// is applied for such case.
- if (topActivity != null) {
+ // TODO(b/194243906): Fix this before enabling the remote keyguard animation.
+ if (WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation
+ && topActivity != null) {
topActivity.mRequestForceTransition = true;
}
updateKeyguardSleepToken(DEFAULT_DISPLAY);
diff --git a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
index d230936b5d51..88941eb4d369 100644
--- a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
@@ -138,7 +138,7 @@ class NonAppWindowAnimationAdapter implements AnimationAdapter {
mTarget = new RemoteAnimationTarget(-1, -1, getLeash(), false,
new Rect(), null, mWindowContainer.getPrefixOrderIndex(),
mWindowContainer.getLastSurfacePosition(), mWindowContainer.getBounds(), null,
- mWindowContainer.getWindowConfiguration(), true, null, null, null,
+ mWindowContainer.getWindowConfiguration(), true, null, null, null, false,
mWindowContainer.getWindowType());
return mTarget;
}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index ede4c2ef7835..dca0bbda78cf 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1346,7 +1346,8 @@ class RecentTasks {
+ " activityType=" + task.getActivityType()
+ " windowingMode=" + task.getWindowingMode()
+ " isAlwaysOnTopWhenVisible=" + task.isAlwaysOnTopWhenVisible()
- + " intentFlags=" + task.getBaseIntent().getFlags());
+ + " intentFlags=" + task.getBaseIntent().getFlags()
+ + " isEmbedded=" + task.isEmbedded());
}
switch (task.getActivityType()) {
@@ -1392,6 +1393,11 @@ class RecentTasks {
return false;
}
+ // Ignore the task if it is a embedded task
+ if (task.isEmbedded()) {
+ return false;
+ }
+
return true;
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index e346e3ec7db9..c457df9f6e86 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -1102,6 +1102,23 @@ public class RecentsAnimationController implements DeathRecipient {
return mTargetActivityRecord.findMainWindow();
}
+ /**
+ * Returns the task with the highest layer, or null if none is found.
+ */
+ public Task getHighestLayerTask() {
+ int highestLayer = Integer.MIN_VALUE;
+ Task highestLayerTask = null;
+ for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
+ TaskAnimationAdapter adapter = mPendingAnimations.get(i);
+ int layer = adapter.mTask.getPrefixOrderIndex();
+ if (layer > highestLayer) {
+ highestLayer = layer;
+ highestLayerTask = adapter.mTask;
+ }
+ }
+ return highestLayerTask;
+ }
+
boolean isAnimatingTask(Task task) {
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
if (task == mPendingAnimations.get(i).mTask) {
@@ -1201,7 +1218,8 @@ public class RecentsAnimationController implements DeathRecipient {
!topApp.fillsParent(), new Rect(),
insets, mTask.getPrefixOrderIndex(), new Point(mBounds.left, mBounds.top),
mLocalBounds, mBounds, mTask.getWindowConfiguration(),
- mIsRecentTaskInvisible, null, null, mTask.getTaskInfo());
+ mIsRecentTaskInvisible, null, null, mTask.getTaskInfo(),
+ topApp.checkEnterPictureInPictureAppOpsState());
return mTarget;
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 24c5c82ef5c6..079868d0dec1 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -365,8 +365,26 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return false;
}
+ if (matchingCandidate(task)) {
+ return true;
+ }
+
+ // Looking for the embedded tasks (if any)
+ return !task.isLeafTaskFragment() && task.forAllLeafTaskFragments(
+ this::matchingCandidate);
+ }
+
+ boolean matchingCandidate(TaskFragment taskFragment) {
+ final Task task = taskFragment.asTask();
+ if (task == null) {
+ return false;
+ }
+
// Overlays should not be considered as the task's logical top activity.
- final ActivityRecord r = task.getTopNonFinishingActivity(false /* includeOverlays */);
+ // Activities of the tasks that embedded from this one should not be used.
+ final ActivityRecord r = task.getTopNonFinishingActivity(false /* includeOverlays */,
+ false /* includingEmbeddedTask */);
+
if (r == null || r.finishing || r.mUserId != userId
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
ProtoLog.d(WM_DEBUG_TASKS, "Skipping %s: mismatch root %s", task, r);
@@ -1980,7 +1998,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
*/
void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
boolean preserveWindows, boolean notifyClients) {
- if (mTaskSupervisor.inActivityVisibilityUpdate()) {
+ if (mTaskSupervisor.inActivityVisibilityUpdate()
+ || mTaskSupervisor.isRootVisibilityUpdateDeferred()) {
// Don't do recursive work.
return;
}
@@ -2811,7 +2830,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
r.detachFromProcess();
- r.mDisplayContent.prepareAppTransition(TRANSIT_CLOSE, TRANSIT_FLAG_APP_CRASHED);
r.mDisplayContent.requestTransitionAndLegacyPrepare(TRANSIT_CLOSE,
TRANSIT_FLAG_APP_CRASHED);
r.destroyIfPossible("handleAppCrashed");
diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
index c671e3835abc..8b1befbefd99 100644
--- a/services/core/java/com/android/server/wm/StartingData.java
+++ b/services/core/java/com/android/server/wm/StartingData.java
@@ -32,6 +32,12 @@ public abstract class StartingData {
*/
boolean mIsTransitionForward;
+ /**
+ * Non-null if the starting window should cover the bounds of associated task. It is assigned
+ * when the parent activity of starting window may be put in a partial area of the task.
+ */
+ Task mAssociatedTask;
+
protected StartingData(WindowManagerService service, int typeParams) {
mService = service;
mTypeParams = typeParams;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 2355dde0486e..138117c81aa1 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -125,7 +125,6 @@ import static com.android.server.wm.TaskProto.SURFACE_HEIGHT;
import static com.android.server.wm.TaskProto.SURFACE_WIDTH;
import static com.android.server.wm.TaskProto.TASK_FRAGMENT;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
-import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainerChildProto.TASK;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
@@ -628,7 +627,7 @@ class Task extends TaskFragment {
IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
boolean _createdByOrganizer, IBinder _launchCookie, boolean _deferTaskAppear,
boolean _removeWithTaskOrganizer) {
- super(atmService, null /* fragmentToken */, _createdByOrganizer);
+ super(atmService, null /* fragmentToken */, _createdByOrganizer, false /* isEmbedded */);
mTaskId = _taskId;
mUserId = _userId;
@@ -707,13 +706,13 @@ class Task extends TaskFragment {
return this;
}
- private void cleanUpResourcesForDestroy(ConfigurationContainer oldParent) {
+ private void cleanUpResourcesForDestroy(WindowContainer<?> oldParent) {
if (hasChild()) {
return;
}
// This task is going away, so save the last state if necessary.
- saveLaunchingStateIfNeeded(((WindowContainer) oldParent).getDisplayContent());
+ saveLaunchingStateIfNeeded(oldParent.getDisplayContent());
// TODO: VI what about activity?
final boolean isVoiceSession = voiceSession != null;
@@ -1144,11 +1143,11 @@ class Task extends TaskFragment {
}
@Override
- void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
- final DisplayContent display = newParent != null
- ? ((WindowContainer) newParent).getDisplayContent() : null;
- final DisplayContent oldDisplay = oldParent != null
- ? ((WindowContainer) oldParent).getDisplayContent() : null;
+ void onParentChanged(ConfigurationContainer rawNewParent, ConfigurationContainer rawOldParent) {
+ final WindowContainer<?> newParent = (WindowContainer<?>) rawNewParent;
+ final WindowContainer<?> oldParent = (WindowContainer<?>) rawOldParent;
+ final DisplayContent display = newParent != null ? newParent.getDisplayContent() : null;
+ final DisplayContent oldDisplay = oldParent != null ? oldParent.getDisplayContent() : null;
mPrevDisplayId = (oldDisplay != null) ? oldDisplay.mDisplayId : INVALID_DISPLAY;
@@ -1189,7 +1188,7 @@ class Task extends TaskFragment {
}
if (oldParent != null) {
- final Task oldParentTask = ((WindowContainer) oldParent).asTask();
+ final Task oldParentTask = oldParent.asTask();
if (oldParentTask != null) {
final PooledConsumer c = PooledLambda.obtainConsumer(
Task::cleanUpActivityReferences, oldParentTask,
@@ -1394,14 +1393,6 @@ class Task extends TaskFragment {
return mFindRootHelper.findRoot(ignoreRelinquishIdentity, setToBottomIfNone);
}
- ActivityRecord getTopNonFinishingActivity() {
- return getTopNonFinishingActivity(true /* includeOverlays */);
- }
-
- ActivityRecord getTopNonFinishingActivity(boolean includeOverlays) {
- return getTopActivity(false /*includeFinishing*/, includeOverlays);
- }
-
ActivityRecord topRunningActivityLocked() {
if (getParent() == null) {
return null;
@@ -1521,7 +1512,7 @@ class Task extends TaskFragment {
if (DEBUG_TASK_MOVEMENT) {
Slog.d(TAG_WM, "removeChild: child=" + r + " reason=" + reason);
}
- super.removeChild(r);
+ super.removeChild(r, false /* removeSelfIfPossible */);
if (inPinnedWindowingMode()) {
// We normally notify listeners of task stack changes on pause, however root pinned task
@@ -1551,7 +1542,10 @@ class Task extends TaskFragment {
// Remove entire task if it doesn't have any activity left and it isn't marked for reuse
// or created by task organizer.
if (!isRootTask()) {
- getRootTask().removeChild(this, reason);
+ final WindowContainer<?> parent = getParent();
+ if (parent != null) {
+ parent.asTaskFragment().removeChild(this);
+ }
}
EventLogTags.writeWmTaskRemoved(mTaskId,
"removeChild:" + reason + " last r=" + r + " in t=" + this);
@@ -2602,25 +2596,12 @@ class Task extends TaskFragment {
}
}
- @VisibleForTesting
- boolean hasWindowsAlive() {
- return getActivity(ActivityRecord::hasWindowsAlive) != null;
- }
-
- @VisibleForTesting
- boolean shouldDeferRemoval() {
- if (mChildren.isEmpty()) {
- // No reason to defer removal of a Task that doesn't have any child.
- return false;
- }
- return hasWindowsAlive() && getRootTask().isAnimating(TRANSITION | CHILDREN);
- }
-
@Override
void removeImmediately() {
removeImmediately("removeTask");
}
+ @Override
void removeImmediately(String reason) {
if (DEBUG_ROOT_TASK) Slog.i(TAG, "removeTask:" + reason + " removing taskId=" + mTaskId);
if (mRemoving) {
@@ -2976,11 +2957,54 @@ class Task extends TaskFragment {
/** Returns the top-most activity that occludes the given one, or {@code null} if none. */
@Nullable
ActivityRecord getOccludingActivityAbove(ActivityRecord activity) {
- final ActivityRecord top = getActivity(ActivityRecord::occludesParent,
- true /* traverseTopToBottom */, activity);
+ final ActivityRecord top = getActivity(r -> {
+ if (r == activity) {
+ // Reached the given activity, return the activity to stop searching.
+ return true;
+ }
+
+ if (!r.occludesParent()) {
+ return false;
+ }
+
+ TaskFragment parent = r.getTaskFragment();
+ if (parent == activity.getTaskFragment()) {
+ // Found it. This activity on top of the given activity on the same TaskFragment.
+ return true;
+ }
+ if (isSelfOrNonEmbeddedTask(parent.asTask())) {
+ // Found it. This activity is the direct child of a leaf Task without being
+ // embedded.
+ return true;
+ }
+ // The candidate activity is being embedded. Checking if the bounds of the containing
+ // TaskFragment equals to the outer TaskFragment.
+ TaskFragment grandParent = parent.getParent().asTaskFragment();
+ while (grandParent != null) {
+ if (!parent.getBounds().equals(grandParent.getBounds())) {
+ // Not occluding the grandparent.
+ break;
+ }
+ if (isSelfOrNonEmbeddedTask(grandParent.asTask())) {
+ // Found it. The activity occludes its parent TaskFragment and the parent
+ // TaskFragment also occludes its parent all the way up.
+ return true;
+ }
+ parent = grandParent;
+ grandParent = parent.getParent().asTaskFragment();
+ }
+ return false;
+ });
return top != activity ? top : null;
}
+ private boolean isSelfOrNonEmbeddedTask(Task task) {
+ if (task == this) {
+ return true;
+ }
+ return task != null && !task.isEmbedded();
+ }
+
@Override
public SurfaceControl.Builder makeAnimationLeash() {
return super.makeAnimationLeash().setMetadata(METADATA_TASK_ID, mTaskId);
@@ -3217,7 +3241,7 @@ class Task extends TaskFragment {
boolean consumed = false;
if (traverseTopToBottom) {
for (int i = task.mChildren.size() - 1; i >= 0; --i) {
- final WindowContainer child = mChildren.get(i);
+ final WindowContainer child = task.mChildren.get(i);
if (child.asTaskFragment() != null) {
child.forAllLeafTaskFragments(callback, traverseTopToBottom);
} else if (child.asActivityRecord() != null && !consumed) {
@@ -3227,7 +3251,7 @@ class Task extends TaskFragment {
}
} else {
for (int i = 0; i < task.mChildren.size(); i++) {
- final WindowContainer child = mChildren.get(i);
+ final WindowContainer child = task.mChildren.get(i);
if (child.asTaskFragment() != null) {
child.forAllLeafTaskFragments(callback, traverseTopToBottom);
} else if (child.asActivityRecord() != null && !consumed) {
@@ -3358,19 +3382,9 @@ class Task extends TaskFragment {
@Override
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
super.dump(pw, prefix, dumpAll);
- pw.println(prefix + "bounds=" + getBounds().toShortString());
- final String doublePrefix = prefix + " ";
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowContainer<?> child = mChildren.get(i);
- pw.println(prefix + "* " + child);
- // Only dump non-activity because full activity info is already printed by
- // RootWindowContainer#dumpActivities.
- if (child.asActivityRecord() == null) {
- child.dump(pw, doublePrefix, dumpAll);
- }
- }
if (!mExitingActivities.isEmpty()) {
+ final String doublePrefix = prefix + " ";
pw.println();
pw.println(prefix + "Exiting application tokens:");
for (int i = mExitingActivities.size() - 1; i >= 0; i--) {
@@ -4139,8 +4153,7 @@ class Task extends TaskFragment {
}
private boolean canBeOrganized() {
- if (mForceNotOrganized || !mAtmService.mTaskOrganizerController
- .isSupportedWindowingMode(getWindowingMode())) {
+ if (mForceNotOrganized) {
return false;
}
// All root tasks can be organized
@@ -4297,7 +4310,7 @@ class Task extends TaskFragment {
final int windowingMode = getWindowingMode();
final TaskOrganizerController controller = mWmService.mAtmService.mTaskOrganizerController;
- final ITaskOrganizer organizer = controller.getTaskOrganizer(windowingMode);
+ final ITaskOrganizer organizer = controller.getTaskOrganizer();
if (!forceUpdate && mTaskOrganizer == organizer) {
return false;
}
@@ -4631,8 +4644,10 @@ class Task extends TaskFragment {
mAtmService.continueWindowLayout();
}
- mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
- mRootWindowContainer.resumeFocusedTasksTopActivities();
+ if (!mTaskSupervisor.isRootVisibilityUpdateDeferred()) {
+ mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
+ }
}
void resumeNextFocusAfterReparent() {
@@ -5058,7 +5073,7 @@ class Task extends TaskFragment {
}
void startActivityLocked(ActivityRecord r, @Nullable ActivityRecord focusedTopActivity,
- boolean newTask, boolean keepCurTransition, ActivityOptions options,
+ boolean newTask, boolean isTaskSwitch, ActivityOptions options,
@Nullable ActivityRecord sourceRecord) {
Task rTask = r.getTask();
final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
@@ -5164,22 +5179,18 @@ class Task extends TaskFragment {
// "has the same starting icon" as the next one. This allows the
// window manager to keep the previous window it had previously
// created, if it still had one.
- Task prevTask = r.getTask();
- ActivityRecord prev = prevTask.getActivity(
- a -> a.mStartingData != null && a.okToShowLocked());
- if (prev != null) {
- // We don't want to reuse the previous starting preview if:
- // (1) The current activity is in a different task.
- if (prev.getTask() != prevTask) {
- prev = null;
- }
- // (2) The current activity is already displayed.
- else if (prev.nowVisible) {
- prev = null;
- }
+ Task baseTask = r.getTask();
+ if (baseTask.isEmbedded()) {
+ // If the task is embedded in a task fragment, there may have an existing
+ // starting window in the parent task. This allows the embedded activities
+ // to share the starting window and make sure that the window can have top
+ // z-order by transferring to the top activity.
+ baseTask = baseTask.getParent().asTaskFragment().getTask();
}
- r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity),
+ final ActivityRecord prev = baseTask.getActivity(
+ a -> a.mStartingData != null && a.okToShowLocked());
+ r.showStartingWindow(prev, newTask, isTaskSwitch,
true /* startActivity */, sourceRecord);
}
} else {
@@ -5213,10 +5224,6 @@ class Task extends TaskFragment {
return true;
}
- private boolean isTaskSwitch(ActivityRecord r, ActivityRecord topFocusedActivity) {
- return topFocusedActivity != null && r.getTask() != topFocusedActivity.getTask();
- }
-
/**
* Reset the task by reparenting the activities that have same affinity to the task or
* reparenting the activities that have different affinityies out of the task, while these
@@ -5274,7 +5281,6 @@ class Task extends TaskFragment {
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
Task finishedTask = r.getTask();
- mDisplayContent.prepareAppTransition(TRANSIT_CLOSE, TRANSIT_FLAG_APP_CRASHED);
mDisplayContent.requestTransitionAndLegacyPrepare(TRANSIT_CLOSE, TRANSIT_FLAG_APP_CRASHED);
r.finishIfPossible(reason, false /* oomAdj */);
@@ -5332,18 +5338,6 @@ class Task extends TaskFragment {
return true;
}
- /** Finish all activities in the root task without waiting. */
- void finishAllActivitiesImmediately() {
- if (!hasChild()) {
- removeIfPossible("finishAllActivitiesImmediately");
- return;
- }
- forAllActivities((r) -> {
- Slog.d(TAG, "finishAllActivitiesImmediatelyLocked: finishing " + r);
- r.destroyIfPossible("finishAllActivitiesImmediately");
- });
- }
-
/** @return true if the root task behind this one is a standard activity type. */
private boolean inFrontOfStandardRootTask() {
final TaskDisplayArea taskDisplayArea = getDisplayArea();
@@ -5654,7 +5648,6 @@ class Task extends TaskFragment {
// Skip the transition for pinned task.
if (!inPinnedWindowingMode()) {
- mDisplayContent.prepareAppTransition(TRANSIT_TO_BACK);
mDisplayContent.requestTransitionAndLegacyPrepare(TRANSIT_TO_BACK, tr);
}
moveToBack("moveTaskToBackLocked", tr);
@@ -5740,17 +5733,14 @@ class Task extends TaskFragment {
@Override
void dumpInner(String prefix, PrintWriter pw, boolean dumpAll, String dumpPackage) {
- pw.print(prefix); pw.print("* "); pw.println(this);
- pw.println(prefix + " mBounds=" + getRequestedOverrideBounds());
- pw.println(prefix + " mCreatedByOrganizer=" + mCreatedByOrganizer);
+ super.dumpInner(prefix, pw, dumpAll, dumpPackage);
+ if (mCreatedByOrganizer) {
+ pw.println(prefix + " mCreatedByOrganizer=true");
+ }
if (mLastNonFullscreenBounds != null) {
pw.print(prefix); pw.print(" mLastNonFullscreenBounds=");
pw.println(mLastNonFullscreenBounds);
}
- if (dumpAll) {
- printThisActivity(pw, mLastPausedActivity, dumpPackage, false,
- prefix + " mLastPausedActivity: ", null);
- }
if (isLeafTask()) {
pw.println(prefix + " isSleeping=" + shouldSleepActivities());
printThisActivity(pw, getTopPausingActivity(), dumpPackage, false,
@@ -6147,16 +6137,6 @@ class Task extends TaskFragment {
getDisplayContent().getPinnedTaskController().setActions(actions);
}
- /** Returns true if a removal action is still being deferred. */
- boolean handleCompleteDeferredRemoval() {
- if (isAnimating(TRANSITION | CHILDREN)
- || mAtmService.getTransitionController().inTransition(this)) {
- return true;
- }
-
- return super.handleCompleteDeferredRemoval();
- }
-
public DisplayInfo getDisplayInfo() {
return mDisplayContent.getDisplayInfo();
}
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 6c8cde433481..cfad93692f09 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -2104,7 +2104,7 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
if (destroyContentOnRemoval
|| !task.isActivityTypeStandardOrUndefined()
|| task.mCreatedByOrganizer) {
- task.finishAllActivitiesImmediately();
+ task.remove(false /* withTransition */, "removeTaskDisplayArea");
} else {
// Reparent task to corresponding launch root or display area.
final WindowContainer launchRoot =
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 1eec6aa7df99..6c31716f8634 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -61,6 +61,8 @@ import static com.android.server.wm.TaskFragmentProto.DISPLAY_ID;
import static com.android.server.wm.TaskFragmentProto.MIN_HEIGHT;
import static com.android.server.wm.TaskFragmentProto.MIN_WIDTH;
import static com.android.server.wm.TaskFragmentProto.WINDOW_CONTAINER;
+import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainerChildProto.TASK_FRAGMENT;
import android.annotation.IntDef;
@@ -158,10 +160,11 @@ class TaskFragment extends WindowContainer<WindowContainer> {
*/
int mMinHeight;
- /** Avoid reentrant of {@link #removeImmediately()}. */
- private boolean mRemoving;
+ /** This task fragment will be removed when the cleanup of its children are done. */
+ private boolean mIsRemovalRequested;
- // The TaskFragment that adjacent to this one.
+ /** The TaskFragment that is adjacent to this one. */
+ @Nullable
private TaskFragment mAdjacentTaskFragment;
/**
@@ -206,6 +209,9 @@ class TaskFragment extends WindowContainer<WindowContainer> {
@VisibleForTesting
boolean mCreatedByOrganizer;
+ /** Whether this TaskFragment is embedded in a task. */
+ private final boolean mIsEmbedded;
+
/** Organizer that organizing this TaskFragment. */
@Nullable
private ITaskFragmentOrganizer mTaskFragmentOrganizer;
@@ -268,23 +274,51 @@ class TaskFragment extends WindowContainer<WindowContainer> {
}
}
+ /** Creates an embedded task fragment. */
TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken,
boolean createdByOrganizer) {
+ this(atmService, fragmentToken, createdByOrganizer, true /* isEmbedded */);
+ }
+
+ TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken,
+ boolean createdByOrganizer, boolean isEmbedded) {
super(atmService.mWindowManager);
mAtmService = atmService;
mTaskSupervisor = mAtmService.mTaskSupervisor;
mRootWindowContainer = mAtmService.mRootWindowContainer;
mCreatedByOrganizer = createdByOrganizer;
+ mIsEmbedded = isEmbedded;
mTaskFragmentOrganizerController =
mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController;
mFragmentToken = fragmentToken;
mRemoteToken = new RemoteToken(this);
}
- void setAdjacentTaskFragment(TaskFragment taskFragment) {
- mAdjacentTaskFragment = taskFragment;
- taskFragment.mAdjacentTaskFragment = this;
+ @NonNull
+ static TaskFragment fromTaskFragmentToken(@Nullable IBinder token,
+ @NonNull ActivityTaskManagerService service) {
+ if (token == null) return null;
+ return service.mWindowOrganizerController.getTaskFragment(token);
+ }
+
+ void setAdjacentTaskFragment(@Nullable TaskFragment taskFragment) {
+ if (mAdjacentTaskFragment == taskFragment) {
+ return;
+ }
+ resetAdjacentTaskFragment();
+ if (taskFragment != null) {
+ mAdjacentTaskFragment = taskFragment;
+ taskFragment.setAdjacentTaskFragment(this);
+ }
+ }
+
+ private void resetAdjacentTaskFragment() {
+ // Reset the adjacent TaskFragment if its adjacent TaskFragment is also this TaskFragment.
+ if (mAdjacentTaskFragment != null && mAdjacentTaskFragment.mAdjacentTaskFragment == this) {
+ mAdjacentTaskFragment.mAdjacentTaskFragment = null;
+ }
+ mAdjacentTaskFragment = null;
}
void setTaskFragmentOrganizer(TaskFragmentOrganizerToken organizer, int pid) {
@@ -374,6 +408,18 @@ class TaskFragment extends WindowContainer<WindowContainer> {
return this;
}
+ /** Returns {@code true} if this is a container for embedded activities or tasks. */
+ boolean isEmbedded() {
+ if (mIsEmbedded) {
+ return true;
+ }
+ final WindowContainer<?> parent = getParent();
+ if (parent != null) {
+ final TaskFragment taskFragment = parent.asTaskFragment();
+ return taskFragment != null && taskFragment.isEmbedded();
+ }
+ return false;
+ }
/**
* Simply check and give warning logs if this is not operated on leaf {@link TaskFragment}.
@@ -570,17 +616,68 @@ class TaskFragment extends WindowContainer<WindowContainer> {
return false;
}
+ ActivityRecord getTopNonFinishingActivity() {
+ return getTopNonFinishingActivity(true /* includeOverlays */);
+ }
+
+ ActivityRecord getTopNonFinishingActivity(boolean includeOverlays) {
+ return getTopNonFinishingActivity(includeOverlays, true /* includingEmbeddedTask */);
+ }
+
+ /**
+ * Returns the top-most non-finishing activity, even if the activity is NOT ok to show to
+ * the current user.
+ * @param includeOverlays whether the task overlay activity should be included.
+ * @param includingEmbeddedTask whether the activity in a task that being embedded from this
+ * one should be included.
+ * @see #topRunningActivity(boolean, boolean)
+ * @see ActivityRecord#okToShowLocked()
+ */
+ ActivityRecord getTopNonFinishingActivity(boolean includeOverlays,
+ boolean includingEmbeddedTask) {
+ // Split into 4 to avoid object creation due to variable capture.
+ if (includeOverlays) {
+ if (includingEmbeddedTask) {
+ return getActivity((r) -> !r.finishing);
+ }
+ return getActivity((r) -> !r.finishing && r.getTask() == this.getTask());
+ }
+
+ if (includingEmbeddedTask) {
+ return getActivity((r) -> !r.finishing && !r.isTaskOverlay());
+ }
+ return getActivity(
+ (r) -> !r.finishing && !r.isTaskOverlay() && r.getTask() == this.getTask());
+ }
+
ActivityRecord topRunningActivity() {
return topRunningActivity(false /* focusableOnly */);
}
ActivityRecord topRunningActivity(boolean focusableOnly) {
- // Split into 2 to avoid object creation due to variable capture.
+ return topRunningActivity(focusableOnly, true /* includingEmbeddedTask */);
+ }
+
+ /**
+ * Returns the top-most running activity, which the activity is non-finishing and ok to show
+ * to the current user.
+ *
+ * @see ActivityRecord#canBeTopRunning()
+ */
+ ActivityRecord topRunningActivity(boolean focusableOnly, boolean includingEmbeddedTask) {
+ // Split into 4 to avoid object creation due to variable capture.
if (focusableOnly) {
- return getActivity((r) -> r.canBeTopRunning() && r.isFocusable());
- } else {
+ if (includingEmbeddedTask) {
+ return getActivity((r) -> r.canBeTopRunning() && r.isFocusable());
+ }
+ return getActivity(
+ (r) -> r.canBeTopRunning() && r.isFocusable() && r.getTask() == this.getTask());
+ }
+
+ if (includingEmbeddedTask) {
return getActivity(ActivityRecord::canBeTopRunning);
}
+ return getActivity((r) -> r.canBeTopRunning() && r.getTask() == this.getTask());
}
boolean isTopActivityFocusable() {
@@ -1303,6 +1400,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
} else {
prev.schedulePauseTimeout();
+ // Unset readiness since we now need to wait until this pause is complete.
+ mAtmService.getTransitionController().setReady(this, false /* ready */);
return true;
}
@@ -1887,6 +1986,10 @@ class TaskFragment extends WindowContainer<WindowContainer> {
}
}
+ int getTaskFragmentOrganizerPid() {
+ return mTaskFragmentOrganizerPid;
+ }
+
/**
* Returns a {@link TaskFragmentInfo} with information from this TaskFragment. Should not be
* called from {@link Task}.
@@ -1946,14 +2049,67 @@ class TaskFragment extends WindowContainer<WindowContainer> {
}
@Override
- void removeImmediately() {
- if (mRemoving) {
+ void removeChild(WindowContainer child) {
+ removeChild(child, true /* removeSelfIfPossible */);
+ }
+
+ void removeChild(WindowContainer child, boolean removeSelfIfPossible) {
+ super.removeChild(child);
+ if (removeSelfIfPossible && (!mCreatedByOrganizer || mIsRemovalRequested) && !hasChild()) {
+ removeImmediately("removeLastChild " + child);
+ }
+ }
+
+ /**
+ * Requests to remove this task fragment. If it doesn't have children, it is removed
+ * immediately. Otherwise it will be removed until all activities are destroyed.
+ *
+ * @param withTransition Whether to use transition animation when removing activities. Set to
+ * {@code false} if this is invisible to user, e.g. display removal.
+ */
+ void remove(boolean withTransition, String reason) {
+ if (!hasChild()) {
+ removeImmediately(reason);
return;
}
- mRemoving = true;
+ mIsRemovalRequested = true;
+ forAllActivities(r -> {
+ if (withTransition) {
+ r.finishIfPossible(reason, false /* oomAdj */);
+ } else {
+ r.destroyIfPossible(reason);
+ }
+ });
+ }
+
+ boolean shouldDeferRemoval() {
+ if (!hasChild()) {
+ return false;
+ }
+ return isAnimating(TRANSITION | CHILDREN, WindowState.EXIT_ANIMATING_TYPES)
+ || mAtmService.getTransitionController().inTransition(this);
+ }
+
+ @Override
+ boolean handleCompleteDeferredRemoval() {
+ if (shouldDeferRemoval()) {
+ return true;
+ }
+ return super.handleCompleteDeferredRemoval();
+ }
+
+ /** The overridden method must call {@link #removeImmediately()} instead of super. */
+ void removeImmediately(String reason) {
+ Slog.d(TAG, "Remove task fragment: " + reason);
+ removeImmediately();
+ }
+
+ @Override
+ void removeImmediately() {
+ mIsRemovalRequested = false;
+ resetAdjacentTaskFragment();
super.removeImmediately();
sendTaskFragmentVanished();
- mRemoving = false;
}
boolean dump(String prefix, FileDescriptor fd, PrintWriter pw, boolean dumpAll,
@@ -1981,10 +2137,10 @@ class TaskFragment extends WindowContainer<WindowContainer> {
for (int i = mChildren.size() - 1; i >= 0; --i) {
WindowContainer child = mChildren.get(i);
if (child.asTaskFragment() != null) {
- printed |= child.asTaskFragment().dump(prefix + " ", fd, pw, dumpAll,
+ printed |= child.asTaskFragment().dump(prefix + " ", fd, pw, dumpAll,
dumpClient, dumpPackage, needSep, headerPrinter);
} else if (child.asActivityRecord() != null) {
- ActivityRecord.dumpActivity(fd, pw, i, child.asActivityRecord(), prefix + " ",
+ ActivityRecord.dumpActivity(fd, pw, i, child.asActivityRecord(), prefix + " ",
"Hist ", true, !dumpAll, dumpClient, dumpPackage, false, headerPrinter,
getTask());
}
@@ -1995,7 +2151,13 @@ class TaskFragment extends WindowContainer<WindowContainer> {
void dumpInner(String prefix, PrintWriter pw, boolean dumpAll, String dumpPackage) {
pw.print(prefix); pw.print("* "); pw.println(this);
- pw.println(prefix + " mBounds=" + getRequestedOverrideBounds());
+ final Rect bounds = getRequestedOverrideBounds();
+ if (!bounds.isEmpty()) {
+ pw.println(prefix + " mBounds=" + bounds);
+ }
+ if (mIsRemovalRequested) {
+ pw.println(prefix + " mIsRemovalRequested=true");
+ }
if (dumpAll) {
printThisActivity(pw, mLastPausedActivity, dumpPackage, false,
prefix + " mLastPausedActivity: ", null);
@@ -2003,6 +2165,22 @@ class TaskFragment extends WindowContainer<WindowContainer> {
}
@Override
+ void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+ super.dump(pw, prefix, dumpAll);
+ pw.println(prefix + "bounds=" + getBounds().toShortString());
+ final String doublePrefix = prefix + " ";
+ for (int i = mChildren.size() - 1; i >= 0; i--) {
+ final WindowContainer<?> child = mChildren.get(i);
+ pw.println(prefix + "* " + child);
+ // Only dump non-activity because full activity info is already printed by
+ // RootWindowContainer#dumpActivities.
+ if (child.asActivityRecord() == null) {
+ child.dump(pw, doublePrefix, dumpAll);
+ }
+ }
+ }
+
+ @Override
void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(HASH_CODE, System.identityHashCode(this));
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index a32238434101..96860a23d3cf 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -230,11 +230,16 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
validateAndGetState(organizer);
final int pid = Binder.getCallingPid();
final long uid = Binder.getCallingUid();
- synchronized (mGlobalLock) {
- ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
- "Unregister task fragment organizer=%s uid=%d pid=%d",
- organizer.asBinder(), uid, pid);
- removeOrganizer(organizer);
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
+ "Unregister task fragment organizer=%s uid=%d pid=%d",
+ organizer.asBinder(), uid, pid);
+ removeOrganizer(organizer);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 9ca89cb79362..fa7b276bc418 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -16,9 +16,6 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
import static com.android.server.wm.ActivityTaskManagerService.enforceTaskPermission;
import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
@@ -67,14 +64,6 @@ import java.util.function.Consumer;
class TaskOrganizerController extends ITaskOrganizerController.Stub {
private static final String TAG = "TaskOrganizerController";
- // The set of modes that are currently supports
- // TODO: Remove once the task organizer can support all modes
- @VisibleForTesting
- static final int[] UNSUPPORTED_WINDOWING_MODES = {
- WINDOWING_MODE_UNDEFINED,
- WINDOWING_MODE_FREEFORM
- };
-
private class DeathRecipient implements IBinder.DeathRecipient {
ITaskOrganizer mTaskOrganizer;
@@ -113,109 +102,6 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
return mTaskOrganizer.asBinder();
}
- void addStartingWindow(Task task, ActivityRecord activity, int launchTheme,
- TaskSnapshot taskSnapshot) {
- final StartingWindowInfo info = task.getStartingWindowInfo(activity);
- if (launchTheme != 0) {
- info.splashScreenThemeResId = launchTheme;
- }
- info.mTaskSnapshot = taskSnapshot;
- // make this happen prior than prepare surface
- try {
- mTaskOrganizer.addStartingWindow(info, activity.token);
- } catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskStart callback", e);
- }
- }
-
- // Capture the animation surface control for activity's main window
- private class StartingWindowAnimationAdaptor implements AnimationAdapter {
- private SurfaceControl mAnimationLeash;
- @Override
- public boolean getShowWallpaper() {
- return false;
- }
-
- @Override
- public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t,
- int type, SurfaceAnimator.OnAnimationFinishedCallback finishCallback) {
- mAnimationLeash = animationLeash;
- }
-
- @Override
- public void onAnimationCancelled(SurfaceControl animationLeash) {
- if (mAnimationLeash == animationLeash) {
- mAnimationLeash = null;
- }
- }
-
- @Override
- public long getDurationHint() {
- return 0;
- }
-
- @Override
- public long getStatusBarTransitionsStartTime() {
- return 0;
- }
-
- @Override
- public void dump(PrintWriter pw, String prefix) {
- pw.print(prefix + "StartingWindowAnimationAdaptor mCapturedLeash=");
- pw.print(mAnimationLeash);
- pw.println();
- }
-
- @Override
- public void dumpDebug(ProtoOutputStream proto) {
- }
- }
-
- void removeStartingWindow(Task task, boolean prepareAnimation) {
- SurfaceControl windowAnimationLeash = null;
- Rect mainFrame = null;
- final boolean playShiftUpAnimation = !task.inMultiWindowMode();
- if (prepareAnimation && playShiftUpAnimation) {
- final ActivityRecord topActivity = task.topActivityContainsStartingWindow();
- if (topActivity != null) {
- final WindowState mainWindow =
- topActivity.findMainWindow(false/* includeStartingApp */);
- if (mainWindow != null) {
- final StartingWindowAnimationAdaptor adaptor =
- new StartingWindowAnimationAdaptor();
- final SurfaceControl.Transaction t = mainWindow.getPendingTransaction();
- mainWindow.startAnimation(t, adaptor, false,
- ANIMATION_TYPE_STARTING_REVEAL);
- windowAnimationLeash = adaptor.mAnimationLeash;
- mainFrame = mainWindow.getRelativeFrame();
- t.setPosition(windowAnimationLeash, mainFrame.left, mainFrame.top);
- }
- }
- }
- try {
- mTaskOrganizer.removeStartingWindow(task.mTaskId, windowAnimationLeash,
- mainFrame, prepareAnimation);
- } catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onStartTaskFinished callback", e);
- }
- }
-
- void copySplashScreenView(Task task) {
- try {
- mTaskOrganizer.copySplashScreenView(task.mTaskId);
- } catch (RemoteException e) {
- Slog.e(TAG, "Exception sending copyStartingWindowView callback", e);
- }
- }
-
- void onAppSplashScreenViewRemoved(Task task) {
- try {
- mTaskOrganizer.onAppSplashScreenViewRemoved(task.mTaskId);
- } catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onAppSplashScreenViewRemoved callback", e);
- }
- }
-
SurfaceControl prepareLeash(Task task, String reason) {
return new SurfaceControl(task.getSurfaceControl(), reason);
}
@@ -302,23 +188,6 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
mUid = uid;
}
- void addStartingWindow(Task t, ActivityRecord activity, int launchTheme,
- TaskSnapshot taskSnapshot) {
- mOrganizer.addStartingWindow(t, activity, launchTheme, taskSnapshot);
- }
-
- void removeStartingWindow(Task t, boolean prepareAnimation) {
- mOrganizer.removeStartingWindow(t, prepareAnimation);
- }
-
- void copySplashScreenView(Task t) {
- mOrganizer.copySplashScreenView(t);
- }
-
- public void onAppSplashScreenViewRemoved(Task t) {
- mOrganizer.onAppSplashScreenViewRemoved(t);
- }
-
/**
* Register this task with this state, but doesn't trigger the task appeared callback to
* the organizer.
@@ -493,11 +362,6 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
mService.mRootWindowContainer.forAllTasks((task) -> {
- if (ArrayUtils.contains(UNSUPPORTED_WINDOWING_MODES,
- task.getWindowingMode())) {
- return;
- }
-
boolean returnTask = !task.mCreatedByOrganizer;
task.updateTaskOrganizerState(true /* forceUpdate */,
returnTask /* skipTaskAppeared */);
@@ -553,46 +417,130 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
/**
* @return the task organizer key for a given windowing mode.
*/
- ITaskOrganizer getTaskOrganizer(int windowingMode) {
- return isSupportedWindowingMode(windowingMode)
- ? mTaskOrganizers.peekLast()
- : null;
+ ITaskOrganizer getTaskOrganizer() {
+ return mTaskOrganizers.peekLast();
}
- boolean isSupportedWindowingMode(int winMode) {
- return !ArrayUtils.contains(UNSUPPORTED_WINDOWING_MODES, winMode);
+ // Capture the animation surface control for activity's main window
+ private static class StartingWindowAnimationAdaptor implements AnimationAdapter {
+ private SurfaceControl mAnimationLeash;
+ @Override
+ public boolean getShowWallpaper() {
+ return false;
+ }
+
+ @Override
+ public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t,
+ int type, SurfaceAnimator.OnAnimationFinishedCallback finishCallback) {
+ mAnimationLeash = animationLeash;
+ }
+
+ @Override
+ public void onAnimationCancelled(SurfaceControl animationLeash) {
+ if (mAnimationLeash == animationLeash) {
+ mAnimationLeash = null;
+ }
+ }
+
+ @Override
+ public long getDurationHint() {
+ return 0;
+ }
+
+ @Override
+ public long getStatusBarTransitionsStartTime() {
+ return 0;
+ }
+
+ @Override
+ public void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix + "StartingWindowAnimationAdaptor mCapturedLeash=");
+ pw.print(mAnimationLeash);
+ pw.println();
+ }
+
+ @Override
+ public void dumpDebug(ProtoOutputStream proto) {
+ }
}
boolean addStartingWindow(Task task, ActivityRecord activity, int launchTheme,
TaskSnapshot taskSnapshot) {
final Task rootTask = task.getRootTask();
- if (rootTask == null || rootTask.mTaskOrganizer == null || activity.mStartingData == null) {
+ if (rootTask == null || activity.mStartingData == null) {
+ return false;
+ }
+ final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast();
+ if (lastOrganizer == null) {
+ return false;
+ }
+ final StartingWindowInfo info = task.getStartingWindowInfo(activity);
+ if (launchTheme != 0) {
+ info.splashScreenThemeResId = launchTheme;
+ }
+ info.mTaskSnapshot = taskSnapshot;
+ // make this happen prior than prepare surface
+ try {
+ lastOrganizer.addStartingWindow(info, activity.token);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception sending onTaskStart callback", e);
return false;
}
- final TaskOrganizerState state =
- mTaskOrganizerStates.get(rootTask.mTaskOrganizer.asBinder());
- state.addStartingWindow(task, activity, launchTheme, taskSnapshot);
return true;
}
void removeStartingWindow(Task task, boolean prepareAnimation) {
final Task rootTask = task.getRootTask();
- if (rootTask == null || rootTask.mTaskOrganizer == null) {
+ if (rootTask == null) {
+ return;
+ }
+ final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast();
+ if (lastOrganizer == null) {
return;
}
- final TaskOrganizerState state =
- mTaskOrganizerStates.get(rootTask.mTaskOrganizer.asBinder());
- state.removeStartingWindow(task, prepareAnimation);
+ SurfaceControl windowAnimationLeash = null;
+ Rect mainFrame = null;
+ final boolean playShiftUpAnimation = !task.inMultiWindowMode();
+ if (prepareAnimation && playShiftUpAnimation) {
+ final ActivityRecord topActivity = task.topActivityContainsStartingWindow();
+ if (topActivity != null) {
+ final WindowState mainWindow =
+ topActivity.findMainWindow(false/* includeStartingApp */);
+ if (mainWindow != null) {
+ final StartingWindowAnimationAdaptor adaptor =
+ new StartingWindowAnimationAdaptor();
+ final SurfaceControl.Transaction t = mainWindow.getPendingTransaction();
+ mainWindow.startAnimation(t, adaptor, false,
+ ANIMATION_TYPE_STARTING_REVEAL);
+ windowAnimationLeash = adaptor.mAnimationLeash;
+ mainFrame = mainWindow.getRelativeFrame();
+ t.setPosition(windowAnimationLeash, mainFrame.left, mainFrame.top);
+ }
+ }
+ }
+ try {
+ lastOrganizer.removeStartingWindow(task.mTaskId, windowAnimationLeash,
+ mainFrame, prepareAnimation);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception sending onStartTaskFinished callback", e);
+ }
}
boolean copySplashScreenView(Task task) {
final Task rootTask = task.getRootTask();
- if (rootTask == null || rootTask.mTaskOrganizer == null) {
+ if (rootTask == null) {
+ return false;
+ }
+ final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast();
+ if (lastOrganizer == null) {
+ return false;
+ }
+ try {
+ lastOrganizer.copySplashScreenView(task.mTaskId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception sending copyStartingWindowView callback", e);
return false;
}
- final TaskOrganizerState state =
- mTaskOrganizerStates.get(rootTask.mTaskOrganizer.asBinder());
- state.copySplashScreenView(task);
return true;
}
@@ -604,12 +552,18 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
*/
public void onAppSplashScreenViewRemoved(Task task) {
final Task rootTask = task.getRootTask();
- if (rootTask == null || rootTask.mTaskOrganizer == null) {
+ if (rootTask == null) {
+ return;
+ }
+ final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast();
+ if (lastOrganizer == null) {
return;
}
- final TaskOrganizerState state =
- mTaskOrganizerStates.get(rootTask.mTaskOrganizer.asBinder());
- state.onAppSplashScreenViewRemoved(task);
+ try {
+ lastOrganizer.onAppSplashScreenViewRemoved(task.mTaskId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception sending onAppSplashScreenViewRemoved callback", e);
+ }
}
void onTaskAppeared(ITaskOrganizer organizer, Task task) {
@@ -704,7 +658,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Delete root task display=%d winMode=%d",
task.getDisplayId(), task.getWindowingMode());
- task.removeImmediately("deleteRootTask");
+ task.remove(true /* withTransition */, "deleteRootTask");
return true;
}
} finally {
@@ -1017,9 +971,6 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
for (int k = 0; k < tasks.size(); k++) {
final Task task = tasks.get(k);
final int mode = task.getWindowingMode();
- if (ArrayUtils.contains(UNSUPPORTED_WINDOWING_MODES, mode)) {
- continue;
- }
pw.println(innerPrefix + " ("
+ WindowConfiguration.windowingModeToString(mode) + ") " + task);
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 43165f82d9de..da16de7d0226 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -20,6 +20,8 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS;
@@ -36,9 +38,11 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.TransitionFlags;
import static android.view.WindowManager.TransitionType;
import static android.view.WindowManager.transitTypeToString;
+import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.TransitionInfo.FLAG_IS_VOICE_INTERACTION;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
+import static android.window.TransitionInfo.FLAG_OCCLUDES_KEYGUARD;
import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
@@ -656,7 +660,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
ArrayMap<WindowContainer, Integer> reasons = new ArrayMap<>();
for (int i = mParticipants.size() - 1; i >= 0; --i) {
ActivityRecord r = mParticipants.valueAt(i).asActivityRecord();
- if (r == null) continue;
+ if (r == null || !r.mVisibleRequested) continue;
// At this point, r is "ready", but if it's not "ALL ready" then it is probably only
// ready due to starting-window.
reasons.put(r, (r.mStartingData instanceof SplashScreenStartingData
@@ -705,6 +709,22 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
return wc.asWallpaperToken() != null;
}
+ private static boolean occludesKeyguard(WindowContainer wc) {
+ final ActivityRecord ar = wc.asActivityRecord();
+ if (ar != null) {
+ return ar.canShowWhenLocked();
+ }
+ final Task t = wc.asTask();
+ if (t != null) {
+ // Get the top activity which was visible (since this is going away, it will remain
+ // client visible until the transition is finished).
+ // skip hidden (or about to hide) apps
+ final ActivityRecord top = t.getActivity(WindowToken::isClientVisible);
+ return top != null && top.canShowWhenLocked();
+ }
+ return false;
+ }
+
/**
* Under some conditions (eg. all visible targets within a parent container are transitioning
* the same way) the transition can be "promoted" to the parent container. This means an
@@ -1049,6 +1069,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
final ActivityManager.RunningTaskInfo tinfo = new ActivityManager.RunningTaskInfo();
task.fillTaskInfo(tinfo);
change.setTaskInfo(tinfo);
+ change.setRotationAnimation(getTaskRotationAnimation(task));
}
out.addChange(change);
}
@@ -1056,6 +1077,23 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
return out;
}
+ private static int getTaskRotationAnimation(@NonNull Task task) {
+ final ActivityRecord top = task.getTopVisibleActivity();
+ if (top == null) return ROTATION_ANIMATION_UNSPECIFIED;
+ final WindowState mainWin = top.findMainWindow(false);
+ if (mainWin == null) return ROTATION_ANIMATION_UNSPECIFIED;
+ int anim = mainWin.getRotationAnimationHint();
+ if (anim >= 0) return anim;
+ anim = mainWin.getAttrs().rotationAnimation;
+ if (anim != ROTATION_ANIMATION_SEAMLESS) return anim;
+ if (mainWin != task.mDisplayContent.getDisplayPolicy().getTopFullscreenOpaqueWindow()
+ || !top.matchParentBounds()) {
+ // At the moment, we only support seamless rotation if there is only one window showing.
+ return ROTATION_ANIMATION_UNSPECIFIED;
+ }
+ return mainWin.getAttrs().rotationAnimation;
+ }
+
boolean getLegacyIsReady() {
return mState == STATE_STARTED && mSyncId >= 0 && mSyncEngine.isReady(mSyncId);
}
@@ -1149,10 +1187,16 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
final DisplayContent dc = wc.asDisplayContent();
if (dc != null) {
flags |= FLAG_IS_DISPLAY;
+ if (dc.hasAlertWindowSurfaces()) {
+ flags |= FLAG_DISPLAY_HAS_ALERT_WINDOWS;
+ }
}
if (isWallpaper(wc)) {
flags |= FLAG_IS_WALLPAPER;
}
+ if (occludesKeyguard(wc)) {
+ flags |= FLAG_OCCLUDES_KEYGUARD;
+ }
return flags;
}
diff --git a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
index 416b9dfe50b4..25f7269effe8 100644
--- a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
@@ -93,7 +93,7 @@ class WallpaperAnimationAdapter implements AnimationAdapter {
RemoteAnimationTarget createRemoteAnimationTarget() {
mTarget = new RemoteAnimationTarget(-1, -1, getLeash(), false, null, null,
mWallpaperToken.getPrefixOrderIndex(), new Point(), null, null,
- mWallpaperToken.getWindowConfiguration(), true, null, null, null);
+ mWallpaperToken.getWindowConfiguration(), true, null, null, null, false);
return mTarget;
}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 95e5fc2e6b27..0f61f1af98bd 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.app.WallpaperManager.COMMAND_FREEZE;
+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;
@@ -79,6 +81,8 @@ class WallpaperController {
private int mLastWallpaperDisplayOffsetX = Integer.MIN_VALUE;
private int mLastWallpaperDisplayOffsetY = Integer.MIN_VALUE;
private final float mMaxWallpaperScale;
+ // Whether COMMAND_FREEZE was dispatched.
+ private boolean mLastFrozen = false;
// This is set when we are waiting for a wallpaper to tell us it is done
// changing its scroll position.
@@ -194,6 +198,7 @@ class WallpaperController {
if (DEBUG_WALLPAPER) Slog.v(TAG,
"Win " + w + ": token animating, looking behind.");
}
+ mFindResults.setIsWallpaperTargetForLetterbox(w.hasWallpaperForLetterboxBackground());
// Found a target! End search.
return true;
}
@@ -424,20 +429,25 @@ class WallpaperController {
Bundle sendWindowWallpaperCommand(
WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync) {
if (window == mWallpaperTarget || window == mPrevWallpaperTarget) {
- boolean doWait = sync;
- for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
- final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
- token.sendWindowWallpaperCommand(action, x, y, z, extras, sync);
- }
-
- if (doWait) {
- // TODO: Need to wait for result.
- }
+ sendWindowWallpaperCommand(action, x, y, z, extras, sync);
}
return null;
}
+ private void sendWindowWallpaperCommand(
+ String action, int x, int y, int z, Bundle extras, boolean sync) {
+ boolean doWait = sync;
+ for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
+ final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
+ token.sendWindowWallpaperCommand(action, x, y, z, extras, sync);
+ }
+
+ if (doWait) {
+ // TODO: Need to wait for result.
+ }
+ }
+
private void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) {
WindowState target = mWallpaperTarget;
if (target != null) {
@@ -641,6 +651,13 @@ class WallpaperController {
updateWallpaperTokens(visible);
+ if (visible && mLastFrozen != mFindResults.isWallpaperTargetForLetterbox) {
+ mLastFrozen = mFindResults.isWallpaperTargetForLetterbox;
+ sendWindowWallpaperCommand(
+ mFindResults.isWallpaperTargetForLetterbox ? COMMAND_FREEZE : COMMAND_UNFREEZE,
+ /* x= */ 0, /* y= */ 0, /* z= */ 0, /* extras= */ null, /* sync= */ false);
+ }
+
if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target=" + mWallpaperTarget
+ " prev=" + mPrevWallpaperTarget);
}
@@ -838,6 +855,7 @@ class WallpaperController {
boolean useTopWallpaperAsTarget = false;
WindowState wallpaperTarget = null;
boolean resetTopWallpaper = false;
+ boolean isWallpaperTargetForLetterbox = false;
void setTopWallpaper(WindowState win) {
topWallpaper = win;
@@ -851,11 +869,16 @@ class WallpaperController {
useTopWallpaperAsTarget = topWallpaperAsTarget;
}
+ void setIsWallpaperTargetForLetterbox(boolean isWallpaperTargetForLetterbox) {
+ this.isWallpaperTargetForLetterbox = isWallpaperTargetForLetterbox;
+ }
+
void reset() {
topWallpaper = null;
wallpaperTarget = null;
useTopWallpaperAsTarget = false;
resetTopWallpaper = false;
+ isWallpaperTargetForLetterbox = false;
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index ffee0b795aec..c48e9d1b4dea 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -3400,6 +3400,29 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
/**
+ * Forces the receiver container to always use the configuration of the supplier container as
+ * its requested override configuration. It allows to propagate configuration without changing
+ * the relationship between child and parent.
+ */
+ static void overrideConfigurationPropagation(WindowContainer<?> receiver,
+ WindowContainer<?> supplier) {
+ final ConfigurationContainerListener listener = new ConfigurationContainerListener() {
+ @Override
+ public void onMergedOverrideConfigurationChanged(Configuration mergedOverrideConfig) {
+ receiver.onRequestedOverrideConfigurationChanged(supplier.getConfiguration());
+ }
+ };
+ supplier.registerConfigurationChangeListener(listener);
+ receiver.registerWindowContainerListener(new WindowContainerListener() {
+ @Override
+ public void onRemoved() {
+ receiver.unregisterWindowContainerListener(this);
+ supplier.unregisterConfigurationChangeListener(listener);
+ }
+ });
+ }
+
+ /**
* Returns the {@link WindowManager.LayoutParams.WindowType}.
*/
@WindowManager.LayoutParams.WindowType int getWindowType() {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 7f6dce40fce8..36809b374525 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1769,9 +1769,8 @@ public class WindowManagerService extends IWindowManager.Stub
final boolean hideSystemAlertWindows = !mHidingNonSystemOverlayWindows.isEmpty();
win.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows);
- final ActivityRecord tokenActivity = token.asActivityRecord();
- if (type == TYPE_APPLICATION_STARTING && tokenActivity != null) {
- tokenActivity.mStartingWindow = win;
+ if (type == TYPE_APPLICATION_STARTING && activity != null) {
+ activity.attachStartingWindow(win);
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "addWindow: %s startingWindow=%s",
activity, win);
}
@@ -3050,7 +3049,7 @@ public class WindowManagerService extends IWindowManager.Stub
mSettingsObserver.updateSystemUiSettings(true /* handleChange */);
synchronized (mGlobalLock) {
// force a re-application of focused window sysui visibility on each display.
- mRoot.forAllDisplayPolicies(DisplayPolicy::resetSystemUiVisibilityLw);
+ mRoot.forAllDisplayPolicies(DisplayPolicy::resetSystemBarAttributes);
}
}
@@ -5292,6 +5291,7 @@ public class WindowManagerService extends IWindowManager.Stub
case LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED: {
synchronized (mGlobalLock) {
final DisplayContent displayContent = (DisplayContent) msg.obj;
+ displayContent.mLayoutAndAssignWindowLayersScheduled = false;
displayContent.layoutAndAssignWindowLayersIfNeeded();
}
break;
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index abf8afa8d3e0..aa147c4c8712 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -322,6 +322,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
int effects = 0;
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);
mService.deferWindowLayout();
+ mService.mTaskSupervisor.setDeferRootVisibilityUpdate(true /* deferUpdate */);
try {
if (transition != null) {
// First check if we have a display rotation transition and if so, update it.
@@ -411,6 +412,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
task.setMainWindowSizeChangeTransaction(sft);
}
if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) {
+ mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */);
// Already calls ensureActivityConfig
mService.mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
mService.mRootWindowContainer.resumeFocusedTasksTopActivities();
@@ -432,6 +434,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
mService.addWindowLayoutReasons(LAYOUT_REASON_CONFIG_CHANGED);
}
} finally {
+ mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */);
mService.continueWindowLayout();
}
}
@@ -472,7 +475,15 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
throw new UnsupportedOperationException("Not supported to set multi-window"
+ " windowing mode during locked task mode.");
}
+
+ final int prevMode = container.getWindowingMode();
container.setWindowingMode(windowingMode);
+ if (prevMode != container.getWindowingMode()) {
+ // The activity in the container may become focusable or non-focusable due to
+ // windowing modes changes (such as entering or leaving pinned windowing mode),
+ // so also apply the lifecycle effects to this transaction.
+ effects |= TRANSACT_EFFECTS_LIFECYCLE;
+ }
}
return effects;
}
@@ -720,8 +731,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
fragmentToken = hop.getContainer();
final IBinder adjacentFragmentToken = hop.getAdjacentRoot();
final TaskFragment tf1 = mLaunchTaskFragments.get(fragmentToken);
- final TaskFragment tf2 = mLaunchTaskFragments.get(adjacentFragmentToken);
- if (tf1 == null || tf2 == null) {
+ final TaskFragment tf2 = adjacentFragmentToken != null
+ ? mLaunchTaskFragments.get(adjacentFragmentToken)
+ : null;
+ if (tf1 == null || (adjacentFragmentToken != null && tf2 == null)) {
final Throwable exception = new IllegalArgumentException(
"Not allowed to set adjacent on invalid fragment tokens");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
@@ -1169,7 +1182,12 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
return;
}
mLaunchTaskFragments.removeAt(index);
- taskFragment.removeImmediately();
+ taskFragment.remove(true /* withTransition */, "deleteTaskFragment");
+ }
+
+ @Nullable
+ TaskFragment getTaskFragment(IBinder tfToken) {
+ return mLaunchTaskFragments.get(tfToken);
}
static class CallerInfo {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c9b15062c708..bee8bda16008 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -193,6 +193,7 @@ import static com.android.server.wm.WindowStateProto.WINDOW_FRAMES;
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityTaskManager;
import android.app.AppOpsManager;
import android.app.admin.DevicePolicyCache;
import android.app.compat.CompatChanges;
@@ -1441,6 +1442,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
+ @Override
+ public Rect getBounds() {
+ // The window bounds are used for layout in screen coordinates. If the token has bounds for
+ // size compatibility mode, its configuration bounds are app based coordinates which should
+ // not be used for layout.
+ return mToken.hasSizeCompatBounds() ? mToken.getBounds() : super.getBounds();
+ }
+
/** Retrieves the current frame of the window that the application sees. */
Rect getFrame() {
return mWindowFrames.mFrame;
@@ -4728,7 +4737,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
final int drawState = mWinAnimator.mDrawState;
if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW) && mActivityRecord != null) {
if (mAttrs.type != TYPE_APPLICATION_STARTING) {
- mActivityRecord.onFirstWindowDrawn(this, mWinAnimator);
+ mActivityRecord.onFirstWindowDrawn(this);
} else {
mActivityRecord.onStartingWindowDrawn();
}
@@ -4816,6 +4825,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
windowInfo.focused = isFocused();
Task task = getTask();
windowInfo.inPictureInPicture = (task != null) && task.inPinnedWindowingMode();
+ windowInfo.taskId = task == null ? ActivityTaskManager.INVALID_TASK_ID : task.mTaskId;
windowInfo.hasFlagWatchOutsideTouch =
(mAttrs.flags & WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH) != 0;
@@ -6043,8 +6053,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
boolean hasWallpaper() {
- return (mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0
- || (mActivityRecord != null && mActivityRecord.hasWallpaperBackgroudForLetterbox());
+ return (mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0 || hasWallpaperForLetterboxBackground();
+ }
+
+ boolean hasWallpaperForLetterboxBackground() {
+ return mActivityRecord != null && mActivityRecord.hasWallpaperBackgroudForLetterbox();
}
/**
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 193d92a3b2ff..70219d2503a3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -327,7 +327,6 @@ import com.android.server.PersistentDataBlockManagerInternal;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemService;
import com.android.server.devicepolicy.ActiveAdmin.TrustAgentInfo;
-import com.android.server.devicepolicy.Owners.OwnerDto;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.pm.RestrictionsSet;
@@ -1259,17 +1258,37 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
// Used by DevicePolicyManagerServiceShellCommand
- List<OwnerDto> listAllOwners() {
+ List<OwnerShellData> listAllOwners() {
Preconditions.checkCallAuthorization(
hasCallingOrSelfPermission(permission.MANAGE_DEVICE_ADMINS));
return mInjector.binderWithCleanCallingIdentity(() -> {
- List<OwnerDto> owners = mOwners.listAllOwners();
+ SparseArray<DevicePolicyData> userData;
+
+ // Gets the owners of "full users" first (device owner and profile owners)
+ List<OwnerShellData> owners = mOwners.listAllOwners();
synchronized (getLockObject()) {
for (int i = 0; i < owners.size(); i++) {
- OwnerDto owner = owners.get(i);
+ OwnerShellData owner = owners.get(i);
owner.isAffiliated = isUserAffiliatedWithDeviceLocked(owner.userId);
}
+ userData = mUserData;
+ }
+
+ // Then the owners of profile users (managed profiles)
+ for (int i = 0; i < userData.size(); i++) {
+ DevicePolicyData policyData = mUserData.valueAt(i);
+ int userId = userData.keyAt(i);
+ int parentUserId = mUserManagerInternal.getProfileParentId(userId);
+ boolean isProfile = parentUserId != userId;
+ if (!isProfile) continue;
+ for (int j = 0; j < policyData.mAdminList.size(); j++) {
+ ActiveAdmin admin = policyData.mAdminList.get(j);
+ OwnerShellData owner = OwnerShellData.forManagedProfileOwner(userId,
+ parentUserId, admin.info.getComponent());
+ owners.add(owner);
+ }
}
+
return owners;
});
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
index a2db6aaca3df..85fe65ca5563 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
@@ -22,8 +22,6 @@ import android.os.ShellCommand;
import android.os.SystemClock;
import android.os.UserHandle;
-import com.android.server.devicepolicy.Owners.OwnerDto;
-
import java.io.PrintWriter;
import java.util.Collection;
import java.util.List;
@@ -205,12 +203,12 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
}
private int runListOwners(PrintWriter pw) {
- List<OwnerDto> owners = mService.listAllOwners();
+ List<OwnerShellData> owners = mService.listAllOwners();
int size = printAndGetSize(pw, owners, "owner");
if (size == 0) return 0;
for (int i = 0; i < size; i++) {
- OwnerDto owner = owners.get(i);
+ OwnerShellData owner = owners.get(i);
pw.printf("User %2d: admin=%s", owner.userId, owner.admin.flattenToShortString());
if (owner.isDeviceOwner) {
pw.print(",DeviceOwner");
@@ -218,6 +216,9 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
if (owner.isProfileOwner) {
pw.print(",ProfileOwner");
}
+ if (owner.isManagedProfileOwner) {
+ pw.printf(",ManagedProfileOwner(parentUserId=%d)", owner.parentUserId);
+ }
if (owner.isAffiliated) {
pw.print(",Affiliated");
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OwnerShellData.java b/services/devicepolicy/java/com/android/server/devicepolicy/OwnerShellData.java
new file mode 100644
index 000000000000..b98c3dc2ac07
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OwnerShellData.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.devicepolicy;
+
+import static android.os.UserHandle.USER_NULL;
+
+import android.annotation.UserIdInt;
+import android.content.ComponentName;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+
+/**
+ * Data-transfer object used by {@link DevicePolicyManagerServiceShellCommand}.
+ */
+final class OwnerShellData {
+
+ public final @UserIdInt int userId;
+ public final @UserIdInt int parentUserId;
+ public final ComponentName admin;
+ public final boolean isDeviceOwner;
+ public final boolean isProfileOwner;
+ public final boolean isManagedProfileOwner;
+ public boolean isAffiliated;
+
+ // NOTE: class is too simple to require a Builder (not to mention isAffiliated is mutable)
+ private OwnerShellData(@UserIdInt int userId, @UserIdInt int parentUserId, ComponentName admin,
+ boolean isDeviceOwner, boolean isProfileOwner, boolean isManagedProfileOwner) {
+ Preconditions.checkArgument(userId != USER_NULL, "userId cannot be USER_NULL");
+ this.userId = userId;
+ this.parentUserId = parentUserId;
+ this.admin = Objects.requireNonNull(admin, "admin must not be null");
+ this.isDeviceOwner = isDeviceOwner;
+ this.isProfileOwner = isProfileOwner;
+ this.isManagedProfileOwner = isManagedProfileOwner;
+ if (isManagedProfileOwner) {
+ Preconditions.checkArgument(parentUserId != USER_NULL,
+ "parentUserId cannot be USER_NULL for managed profile owner");
+ Preconditions.checkArgument(parentUserId != userId,
+ "cannot be parent of itself (%d)", userId);
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(getClass().getSimpleName())
+ .append("[userId=").append(userId)
+ .append(",admin=").append(admin.flattenToShortString());
+ if (isDeviceOwner) {
+ sb.append(",deviceOwner");
+ }
+ if (isProfileOwner) {
+ sb.append(",isProfileOwner");
+ }
+ if (isManagedProfileOwner) {
+ sb.append(",isManagedProfileOwner");
+ }
+ if (parentUserId != USER_NULL) {
+ sb.append(",parentUserId=").append(parentUserId);
+ }
+ if (isAffiliated) {
+ sb.append(",isAffiliated");
+ }
+ return sb.append(']').toString();
+ }
+
+ static OwnerShellData forDeviceOwner(@UserIdInt int userId, ComponentName admin) {
+ return new OwnerShellData(userId, /* parentUserId= */ USER_NULL, admin,
+ /* isDeviceOwner= */ true, /* isProfileOwner= */ false,
+ /* isManagedProfileOwner= */ false);
+ }
+
+ static OwnerShellData forUserProfileOwner(@UserIdInt int userId, ComponentName admin) {
+ return new OwnerShellData(userId, /* parentUserId= */ USER_NULL, admin,
+ /* isDeviceOwner= */ false, /* isProfileOwner= */ true,
+ /* isManagedProfileOwner= */ false);
+ }
+
+ static OwnerShellData forManagedProfileOwner(@UserIdInt int userId, @UserIdInt int parentUserId,
+ ComponentName admin) {
+ return new OwnerShellData(userId, parentUserId, admin, /* isDeviceOwner= */ false,
+ /* isProfileOwner= */ false, /* isManagedProfileOwner= */ true);
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index fd09e3f9cfd0..3584728a2e62 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -19,7 +19,6 @@ package com.android.server.devicepolicy;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
import android.annotation.Nullable;
-import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManagerInternal;
import android.app.admin.DevicePolicyManager.DeviceOwnerType;
@@ -476,17 +475,16 @@ class Owners {
}
}
- List<OwnerDto> listAllOwners() {
- List<OwnerDto> owners = new ArrayList<>();
+ List<OwnerShellData> listAllOwners() {
+ List<OwnerShellData> owners = new ArrayList<>();
synchronized (mLock) {
if (mDeviceOwner != null) {
- owners.add(new OwnerDto(mDeviceOwnerUserId, mDeviceOwner.admin,
- /* isDeviceOwner= */ true));
+ owners.add(OwnerShellData.forDeviceOwner(mDeviceOwnerUserId, mDeviceOwner.admin));
}
for (int i = 0; i < mProfileOwners.size(); i++) {
int userId = mProfileOwners.keyAt(i);
OwnerInfo info = mProfileOwners.valueAt(i);
- owners.add(new OwnerDto(userId, info.admin, /* isDeviceOwner= */ false));
+ owners.add(OwnerShellData.forUserProfileOwner(userId, info.admin));
}
}
return owners;
@@ -1236,24 +1234,6 @@ class Owners {
}
}
- /**
- * Data-transfer object used by {@link DevicePolicyManagerServiceShellCommand}.
- */
- static final class OwnerDto {
- public final @UserIdInt int userId;
- public final ComponentName admin;
- public final boolean isDeviceOwner;
- public final boolean isProfileOwner;
- public boolean isAffiliated;
-
- private OwnerDto(@UserIdInt int userId, ComponentName admin, boolean isDeviceOwner) {
- this.userId = userId;
- this.admin = Objects.requireNonNull(admin, "admin must not be null");
- this.isDeviceOwner = isDeviceOwner;
- this.isProfileOwner = !isDeviceOwner;
- }
- }
-
public void dump(IndentingPrintWriter pw) {
boolean needBlank = false;
if (mDeviceOwner != null) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 81995a79d9d8..4897ca0efedb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1586,6 +1586,9 @@ public final class SystemServer implements Dumpable {
// all listeners have the chance to react with special handling.
Settings.Global.putInt(context.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON, 1);
+ } else if (context.getResources().getBoolean(R.bool.config_autoResetAirplaneMode)) {
+ Settings.Global.putInt(context.getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0);
}
StatusBarManagerService statusBar = null;
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
index 20a58426f1eb..a883293b13b9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
@@ -173,8 +173,6 @@ public final class CachedAppOptimizerTest {
CachedAppOptimizer.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB);
assertThat(mCachedAppOptimizerUnderTest.mFullDeltaRssThrottleKb).isEqualTo(
CachedAppOptimizer.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB);
- assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
- CachedAppOptimizer.DEFAULT_USE_FREEZER);
assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMinOomAdj).isEqualTo(
CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MIN_OOM_ADJ);
assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleMaxOomAdj).isEqualTo(
@@ -188,6 +186,10 @@ public final class CachedAppOptimizerTest {
}
assertThat(mCachedAppOptimizerUnderTest.mProcStateThrottle)
.containsExactlyElementsIn(expected);
+
+ Assume.assumeTrue(mCachedAppOptimizerUnderTest.isFreezerSupported());
+ assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
+ CachedAppOptimizer.DEFAULT_USE_FREEZER);
}
@Test
@@ -244,9 +246,8 @@ public final class CachedAppOptimizerTest {
CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_MAX_OOM_ADJ - 10), false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
CachedAppOptimizer.KEY_COMPACT_PROC_STATE_THROTTLE, "1,2,3", false);
- assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
- CachedAppOptimizer.DEFAULT_USE_FREEZER);
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isFalse();
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
CachedAppOptimizer.KEY_USE_FREEZER, CachedAppOptimizer.DEFAULT_USE_FREEZER
? "false" : "true", false);
@@ -291,7 +292,8 @@ public final class CachedAppOptimizerTest {
CachedAppOptimizer.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB + 1);
assertThat(mCachedAppOptimizerUnderTest.mProcStateThrottle).containsExactly(1, 2, 3);
- if (mCachedAppOptimizerUnderTest.isFreezerSupported()) {
+ Assume.assumeTrue(CachedAppOptimizer.isFreezerSupported());
+ if (CachedAppOptimizer.isFreezerSupported()) {
if (CachedAppOptimizer.DEFAULT_USE_FREEZER) {
assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isFalse();
} else {
@@ -325,15 +327,15 @@ public final class CachedAppOptimizerTest {
@Test
public void useFreeze_doesNotListenToDeviceConfigChanges() throws InterruptedException {
- Assume.assumeTrue(mCachedAppOptimizerUnderTest.isFreezerSupported());
+ Assume.assumeTrue(CachedAppOptimizer.isFreezerSupported());
- assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
- CachedAppOptimizer.DEFAULT_USE_FREEZER);
+ assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isFalse();
// The freezer DeviceConfig property is read at boot only
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
CachedAppOptimizer.KEY_USE_FREEZER, "true", false);
mCachedAppOptimizerUnderTest.init();
+ assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isTrue();
mCountDown = new CountDownLatch(1);
// No notifications should get to the cached app optimizer.
@@ -346,14 +348,13 @@ public final class CachedAppOptimizerTest {
// Set the flag the other way without rebooting. It shall not change.
mCountDown = new CountDownLatch(1);
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
CachedAppOptimizer.KEY_USE_FREEZER, "false", false);
assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isTrue();
-
// Now, set the flag to false and restart the cached app optimizer
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
CachedAppOptimizer.KEY_USE_FREEZER, "false", false);
mCachedAppOptimizerUnderTest.init();
@@ -380,18 +381,17 @@ public final class CachedAppOptimizerTest {
@Test
public void useFreeze_listensToDeviceConfigChangesBadValues() throws InterruptedException {
- assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
- CachedAppOptimizer.DEFAULT_USE_FREEZER);
+ Assume.assumeTrue(CachedAppOptimizer.isFreezerSupported());
+ assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isFalse();
// When we push an invalid flag value...
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
CachedAppOptimizer.KEY_USE_FREEZER, "foobar", false);
mCachedAppOptimizerUnderTest.init();
- // Then we set the default.
- assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
- CachedAppOptimizer.DEFAULT_USE_FREEZER);
+ // DeviceConfig treats invalid value as false
+ assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isFalse();
}
@Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java b/services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java
index 589a3497435e..457c8db9fdf3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java
@@ -48,7 +48,7 @@ import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
/**
- * Run it as {@code atest FrameworksMockingCoreTests:FactoryResetterTest}
+ * Run it as {@code atest FrameworksMockingServicesTests:FactoryResetterTest}
*/
@Presubmit
public final class FactoryResetterTest {
diff --git a/services/tests/mockingservicestests/src/com/android/server/devicepolicy/OwnerShellDataTest.java b/services/tests/mockingservicestests/src/com/android/server/devicepolicy/OwnerShellDataTest.java
new file mode 100644
index 000000000000..dd67d7208034
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/devicepolicy/OwnerShellDataTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.devicepolicy;
+
+import static android.os.UserHandle.USER_NULL;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.testng.Assert.expectThrows;
+
+import android.content.ComponentName;
+
+import org.junit.Test;
+
+/**
+ * Run it as {@code atest FrameworksMockingServicesTests:OwnerShellDataTest}
+ */
+public final class OwnerShellDataTest {
+
+ private static final int USER_ID = 007;
+ private static final int PARENT_USER_ID = 'M' + 'I' + 6;
+ private static final ComponentName ADMIN = new ComponentName("Bond", "James");
+
+ @Test
+ public void testForDeviceOwner_noAdmin() {
+ expectThrows(NullPointerException.class,
+ () -> OwnerShellData.forDeviceOwner(USER_ID, /* admin= */ null));
+ }
+
+ @Test
+ public void testForDeviceOwner_invalidUser() {
+ expectThrows(IllegalArgumentException.class,
+ () -> OwnerShellData.forDeviceOwner(USER_NULL, ADMIN));
+ }
+
+ @Test
+ public void testForDeviceOwner() {
+ OwnerShellData dto = OwnerShellData.forDeviceOwner(USER_ID, ADMIN);
+
+ assertWithMessage("dto(%s).userId", dto).that(dto.userId).isEqualTo(USER_ID);
+ assertWithMessage("dto(%s).parentUserId", dto).that(dto.parentUserId)
+ .isEqualTo(USER_NULL);
+ assertWithMessage("dto(%s).admin", dto).that(dto.admin).isSameInstanceAs(ADMIN);
+ assertWithMessage("dto(%s).isDeviceOwner", dto).that(dto.isDeviceOwner).isTrue();
+ assertWithMessage("dto(%s).isProfileOwner", dto).that(dto.isProfileOwner).isFalse();
+ assertWithMessage("dto(%s).isManagedProfileOwner", dto).that(dto.isManagedProfileOwner)
+ .isFalse();
+ assertWithMessage("dto(%s).isAffiliated", dto).that(dto.isAffiliated).isFalse();
+ }
+
+ @Test
+ public void testForUserProfileOwner_noAdmin() {
+ expectThrows(NullPointerException.class,
+ () -> OwnerShellData.forUserProfileOwner(USER_ID, /* admin= */ null));
+ }
+
+ @Test
+ public void testForUserProfileOwner_invalidUser() {
+ expectThrows(IllegalArgumentException.class,
+ () -> OwnerShellData.forUserProfileOwner(USER_NULL, ADMIN));
+ }
+
+ @Test
+ public void testForUserProfileOwner() {
+ OwnerShellData dto = OwnerShellData.forUserProfileOwner(USER_ID, ADMIN);
+
+ assertWithMessage("dto(%s).userId", dto).that(dto.userId).isEqualTo(USER_ID);
+ assertWithMessage("dto(%s).parentUserId", dto).that(dto.parentUserId)
+ .isEqualTo(USER_NULL);
+ assertWithMessage("dto(%s).admin", dto).that(dto.admin).isSameInstanceAs(ADMIN);
+ assertWithMessage("dto(%s).isDeviceOwner", dto).that(dto.isDeviceOwner).isFalse();
+ assertWithMessage("dto(%s).isProfileOwner", dto).that(dto.isProfileOwner).isTrue();
+ assertWithMessage("dto(%s).isManagedProfileOwner", dto).that(dto.isManagedProfileOwner)
+ .isFalse();
+ assertWithMessage("dto(%s).isAffiliated", dto).that(dto.isAffiliated).isFalse();
+ }
+
+ @Test
+ public void testForManagedProfileOwner_noAdmin() {
+ expectThrows(NullPointerException.class,
+ () -> OwnerShellData.forManagedProfileOwner(USER_ID, PARENT_USER_ID, null));
+ }
+
+ @Test
+ public void testForManagedProfileOwner_invalidUser() {
+ expectThrows(IllegalArgumentException.class,
+ () -> OwnerShellData.forManagedProfileOwner(USER_NULL, PARENT_USER_ID, ADMIN));
+ }
+
+ @Test
+ public void testForManagedProfileOwner_invalidParent() {
+ expectThrows(IllegalArgumentException.class,
+ () -> OwnerShellData.forManagedProfileOwner(USER_ID, USER_NULL, ADMIN));
+ }
+
+ @Test
+ public void testForManagedProfileOwner_parentOfItself() {
+ expectThrows(IllegalArgumentException.class,
+ () -> OwnerShellData.forManagedProfileOwner(USER_ID, USER_ID, ADMIN));
+ }
+
+ @Test
+ public void testForManagedProfileOwner() {
+ OwnerShellData dto = OwnerShellData.forManagedProfileOwner(USER_ID, PARENT_USER_ID, ADMIN);
+
+ assertWithMessage("dto(%s).userId", dto).that(dto.userId).isEqualTo(USER_ID);
+ assertWithMessage("dto(%s).parentUserId", dto).that(dto.parentUserId)
+ .isEqualTo(PARENT_USER_ID);
+ assertWithMessage("dto(%s).admin", dto).that(dto.admin).isSameInstanceAs(ADMIN);
+ assertWithMessage("dto(%s).isDeviceOwner", dto).that(dto.isDeviceOwner).isFalse();
+ assertWithMessage("dto(%s).isProfileOwner", dto).that(dto.isProfileOwner).isFalse();
+ assertWithMessage("dto(%s).isManagedProfileOwner", dto).that(dto.isManagedProfileOwner)
+ .isTrue();
+ assertWithMessage("dto(%s).isAffiliated", dto).that(dto.isAffiliated).isFalse();
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 0efcc57eeec2..34856e2580ed 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -134,6 +134,14 @@ public class LocalDisplayAdapterTest {
when(mMockedResources.getFloat(com.android.internal.R.dimen
.config_screenBrightnessSettingMaximumFloat))
.thenReturn(BACKLIGHT_RANGE_ZERO_TO_ONE[1]);
+ when(mMockedResources.getStringArray(R.array.config_displayUniqueIdArray))
+ .thenReturn(new String[]{});
+ TypedArray mockArray = mock(TypedArray.class);
+ when(mockArray.length()).thenReturn(0);
+ when(mMockedResources.obtainTypedArray(R.array.config_maskBuiltInDisplayCutoutArray))
+ .thenReturn(mockArray);
+ when(mMockedResources.obtainTypedArray(R.array.config_waterfallCutoutArray))
+ .thenReturn(mockArray);
}
@After
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java
index c12eb32a9143..e98a4dded99b 100644
--- a/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java
@@ -64,12 +64,16 @@ public class AppOpsStartedWatcherTest {
.times(1)).onOpStarted(eq(AppOpsManager.OP_FINE_LOCATION),
eq(Process.myUid()), eq(getContext().getPackageName()),
eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF),
- eq(AppOpsManager.MODE_ALLOWED));
+ eq(AppOpsManager.MODE_ALLOWED), eq(OnOpStartedListener.START_TYPE_STARTED),
+ eq(AppOpsManager.ATTRIBUTION_FLAGS_NONE),
+ eq(AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE));
inOrder.verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
.times(1)).onOpStarted(eq(AppOpsManager.OP_CAMERA),
eq(Process.myUid()), eq(getContext().getPackageName()),
eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF),
- eq(AppOpsManager.MODE_ALLOWED));
+ eq(AppOpsManager.MODE_ALLOWED), eq(OnOpStartedListener.START_TYPE_STARTED),
+ eq(AppOpsManager.ATTRIBUTION_FLAGS_NONE),
+ eq(AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE));
// Stop watching
appOpsManager.stopWatchingStarted(listener);
@@ -94,7 +98,9 @@ public class AppOpsStartedWatcherTest {
.times(2)).onOpStarted(eq(AppOpsManager.OP_CAMERA),
eq(Process.myUid()), eq(getContext().getPackageName()),
eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF),
- eq(AppOpsManager.MODE_ALLOWED));
+ eq(AppOpsManager.MODE_ALLOWED), eq(OnOpStartedListener.START_TYPE_STARTED),
+ eq(AppOpsManager.ATTRIBUTION_FLAGS_NONE),
+ eq(AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE));
verifyNoMoreInteractions(listener);
// Finish up
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index 8592166aae15..f4d14995f7c7 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -378,6 +378,11 @@ public class BiometricSchedulerTest {
protected void handleLifecycleAfterAuth(boolean authenticated) {
}
+
+ @Override
+ public boolean wasUserDetected() {
+ return false;
+ }
}
private static class TestAuthenticationClient extends AuthenticationClient<Object> {
@@ -407,6 +412,11 @@ public class BiometricSchedulerTest {
protected void handleLifecycleAfterAuth(boolean authenticated) {
}
+
+ @Override
+ public boolean wasUserDetected() {
+ return false;
+ }
}
private static class TestClientMonitor2 extends TestClientMonitor {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
index f1adcae257a7..bfb0be760f85 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
@@ -32,6 +32,7 @@ import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
import android.content.Context;
+import android.hardware.biometrics.BiometricConstants;
import android.os.Handler;
import android.os.Looper;
import android.platform.test.annotations.Presubmit;
@@ -61,6 +62,8 @@ public class CoexCoordinatorTest {
private Context mContext;
@Mock
private CoexCoordinator.Callback mCallback;
+ @Mock
+ private CoexCoordinator.ErrorCallback mErrorCallback;
@Before
public void setUp() {
@@ -70,6 +73,7 @@ public class CoexCoordinatorTest {
mCoexCoordinator = CoexCoordinator.getInstance();
mCoexCoordinator.setAdvancedLogicEnabled(true);
+ mCoexCoordinator.setFaceHapticDisabledWhenNonBypass(true);
}
@Test
@@ -151,12 +155,76 @@ public class CoexCoordinatorTest {
mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, faceClient,
mCallback);
- verify(mCallback).sendHapticFeedback();
+ // Haptics tested in #testKeyguard_bypass_haptics. Let's leave this commented out (instead
+ // of removed) to keep this context.
+ // verify(mCallback).sendHapticFeedback();
verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
verify(mCallback).handleLifecycleAfterAuth();
}
@Test
+ public void testKeyguard_faceAuthSuccess_nonBypass_udfpsRunning_noHaptics() {
+ testKeyguard_bypass_haptics(false /* bypassEnabled */,
+ true /* faceAccepted */,
+ false /* shouldReceiveHaptics */);
+ }
+
+ @Test
+ public void testKeyguard_faceAuthReject_nonBypass_udfpsRunning_noHaptics() {
+ testKeyguard_bypass_haptics(false /* bypassEnabled */,
+ false /* faceAccepted */,
+ false /* shouldReceiveHaptics */);
+ }
+
+ @Test
+ public void testKeyguard_faceAuthSuccess_bypass_udfpsRunning_haptics() {
+ testKeyguard_bypass_haptics(true /* bypassEnabled */,
+ true /* faceAccepted */,
+ true /* shouldReceiveHaptics */);
+ }
+
+ @Test
+ public void testKeyguard_faceAuthReject_bypass_udfpsRunning_haptics() {
+ testKeyguard_bypass_haptics(true /* bypassEnabled */,
+ false /* faceAccepted */,
+ true /* shouldReceiveHaptics */);
+ }
+
+ private void testKeyguard_bypass_haptics(boolean bypassEnabled, boolean faceAccepted,
+ boolean shouldReceiveHaptics) {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+ when(faceClient.isKeyguard()).thenReturn(true);
+ when(faceClient.isKeyguardBypassEnabled()).thenReturn(bypassEnabled);
+
+ AuthenticationClient<?> udfpsClient = mock(AuthenticationClient.class,
+ withSettings().extraInterfaces(Udfps.class));
+ when(udfpsClient.isKeyguard()).thenReturn(true);
+ when(((Udfps) udfpsClient).isPointerDown()).thenReturn(false);
+
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, udfpsClient);
+
+ if (faceAccepted) {
+ mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, faceClient,
+ mCallback);
+ } else {
+ mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, faceClient,
+ LockoutTracker.LOCKOUT_NONE, mCallback);
+ }
+
+ if (shouldReceiveHaptics) {
+ verify(mCallback).sendHapticFeedback();
+ } else {
+ verify(mCallback, never()).sendHapticFeedback();
+ }
+
+ verify(mCallback).sendAuthenticationResult(eq(faceAccepted) /* addAuthTokenIfStrong */);
+ verify(mCallback).handleLifecycleAfterAuth();
+ }
+
+ @Test
public void testKeyguard_faceAuth_udfpsTouching_faceSuccess_thenUdfpsRejectedWithinBounds() {
testKeyguard_faceAuth_udfpsTouching_faceSuccess(false /* thenUdfpsAccepted */,
0 /* udfpsRejectedAfterMs */);
@@ -190,13 +258,16 @@ public class CoexCoordinatorTest {
mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, udfpsClient);
+ // For easier reading
+ final CoexCoordinator.Callback faceCallback = mCallback;
+
mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, faceClient,
- mCallback);
- verify(mCallback, never()).sendHapticFeedback();
- verify(mCallback, never()).sendAuthenticationResult(anyBoolean());
+ faceCallback);
+ verify(faceCallback, never()).sendHapticFeedback();
+ verify(faceCallback, never()).sendAuthenticationResult(anyBoolean());
// CoexCoordinator requests the system to hold onto this AuthenticationClient until
// UDFPS result is known
- verify(mCallback, never()).handleLifecycleAfterAuth();
+ verify(faceCallback, never()).handleLifecycleAfterAuth();
// Reset the mock
CoexCoordinator.Callback udfpsCallback = mock(CoexCoordinator.Callback.class);
@@ -209,6 +280,8 @@ public class CoexCoordinatorTest {
verify(udfpsCallback).sendAuthenticationResult(true /* addAuthTokenIfStrong */);
verify(udfpsCallback).handleLifecycleAfterAuth();
+ verify(faceCallback).sendAuthenticationCanceled();
+
assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
} else {
mCoexCoordinator.onAuthenticationRejected(udfpsRejectedAfterMs, udfpsClient,
@@ -216,16 +289,16 @@ public class CoexCoordinatorTest {
if (udfpsRejectedAfterMs <= CoexCoordinator.SUCCESSFUL_AUTH_VALID_DURATION_MS) {
verify(udfpsCallback, never()).sendHapticFeedback();
- verify(mCallback).sendHapticFeedback();
- verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
- verify(mCallback).handleLifecycleAfterAuth();
+ verify(faceCallback).sendHapticFeedback();
+ verify(faceCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
+ verify(faceCallback).handleLifecycleAfterAuth();
assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
} else {
assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
- verify(mCallback, never()).sendHapticFeedback();
- verify(mCallback, never()).sendAuthenticationResult(anyBoolean());
+ verify(faceCallback, never()).sendHapticFeedback();
+ verify(faceCallback, never()).sendAuthenticationResult(anyBoolean());
verify(udfpsCallback).sendHapticFeedback();
verify(udfpsCallback)
@@ -294,12 +367,13 @@ public class CoexCoordinatorTest {
}
@Test
- public void testKeyguard_udfpsRejected_thenFaceRejected() {
+ public void testKeyguard_udfpsRejected_thenFaceRejected_noKeyguardBypass() {
mCoexCoordinator.reset();
AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
when(faceClient.isKeyguard()).thenReturn(true);
when(faceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
+ when(faceClient.isKeyguardBypassEnabled()).thenReturn(false); // TODO: also test "true" case
AuthenticationClient<?> udfpsClient = mock(AuthenticationClient.class,
withSettings().extraInterfaces(Udfps.class));
@@ -312,8 +386,9 @@ public class CoexCoordinatorTest {
mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, udfpsClient,
LockoutTracker.LOCKOUT_NONE, mCallback);
- // Client becomes paused, but finger does not necessarily lift, since we suppress the haptic
- when(udfpsClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED_PAUSED);
+ // Auth was attempted
+ when(udfpsClient.getState())
+ .thenReturn(AuthenticationClient.STATE_STARTED_PAUSED_ATTEMPTED);
verify(mCallback, never()).sendHapticFeedback();
verify(mCallback).handleLifecycleAfterAuth();
@@ -418,4 +493,82 @@ public class CoexCoordinatorTest {
verify(callback).handleLifecycleAfterAuth();
verify(successfulAuths).remove(eq(auth));
}
+
+ @Test
+ public void testBiometricPrompt_FaceError() {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> client = mock(AuthenticationClient.class);
+ when(client.isBiometricPrompt()).thenReturn(true);
+ when(client.wasAuthAttempted()).thenReturn(true);
+
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, client);
+
+ mCoexCoordinator.onAuthenticationError(client, BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
+ mErrorCallback);
+ verify(mErrorCallback).sendHapticFeedback();
+ }
+
+ @Test
+ public void testKeyguard_faceAuthOnly_errorWhenBypassEnabled() {
+ testKeyguard_faceAuthOnly(true /* bypassEnabled */);
+ }
+
+ @Test
+ public void testKeyguard_faceAuthOnly_errorWhenBypassDisabled() {
+ testKeyguard_faceAuthOnly(false /* bypassEnabled */);
+ }
+
+ private void testKeyguard_faceAuthOnly(boolean bypassEnabled) {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> client = mock(AuthenticationClient.class);
+ when(client.isKeyguard()).thenReturn(true);
+ when(client.isKeyguardBypassEnabled()).thenReturn(bypassEnabled);
+ when(client.wasAuthAttempted()).thenReturn(true);
+ when(client.wasUserDetected()).thenReturn(true);
+
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, client);
+
+ mCoexCoordinator.onAuthenticationError(client, BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
+ mErrorCallback);
+ verify(mErrorCallback).sendHapticFeedback();
+ }
+
+ @Test
+ public void testKeyguard_coex_faceErrorWhenBypassEnabled() {
+ testKeyguard_coex_faceError(true /* bypassEnabled */);
+ }
+
+ @Test
+ public void testKeyguard_coex_faceErrorWhenBypassDisabled() {
+ testKeyguard_coex_faceError(false /* bypassEnabled */);
+ }
+
+ private void testKeyguard_coex_faceError(boolean bypassEnabled) {
+ mCoexCoordinator.reset();
+
+ AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+ when(faceClient.isKeyguard()).thenReturn(true);
+ when(faceClient.isKeyguardBypassEnabled()).thenReturn(bypassEnabled);
+ when(faceClient.wasAuthAttempted()).thenReturn(true);
+ when(faceClient.wasUserDetected()).thenReturn(true);
+
+ AuthenticationClient<?> udfpsClient = mock(AuthenticationClient.class,
+ withSettings().extraInterfaces(Udfps.class));
+ when(udfpsClient.isKeyguard()).thenReturn(true);
+ when(((Udfps) udfpsClient).isPointerDown()).thenReturn(false);
+
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+ mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, udfpsClient);
+
+ mCoexCoordinator.onAuthenticationError(faceClient,
+ BiometricConstants.BIOMETRIC_ERROR_TIMEOUT, mErrorCallback);
+
+ if (bypassEnabled) {
+ verify(mErrorCallback).sendHapticFeedback();
+ } else {
+ verify(mErrorCallback, never()).sendHapticFeedback();
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index a205a1d167fe..1ac28abb4c2f 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -1340,11 +1340,19 @@ public class DisplayModeDirectorTest {
createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
director.start(createMockSensorManager());
- ArgumentCaptor<ProximityActiveListener> captor =
+ ArgumentCaptor<ProximityActiveListener> ProximityCaptor =
ArgumentCaptor.forClass(ProximityActiveListener.class);
verify(mSensorManagerInternalMock).addProximityActiveListener(any(Executor.class),
- captor.capture());
- ProximityActiveListener listener = captor.getValue();
+ ProximityCaptor.capture());
+ ProximityActiveListener proximityListener = ProximityCaptor.getValue();
+
+ ArgumentCaptor<DisplayListener> DisplayCaptor =
+ ArgumentCaptor.forClass(DisplayListener.class);
+ verify(mInjector).registerDisplayListener(DisplayCaptor.capture(), any(Handler.class),
+ eq(DisplayManager.EVENT_FLAG_DISPLAY_ADDED
+ | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
+ | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED));
+ DisplayListener displayListener = DisplayCaptor.getValue();
// Verify that there is no proximity vote initially
Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
@@ -1353,13 +1361,38 @@ public class DisplayModeDirectorTest {
when(mDisplayManagerInternalMock.getRefreshRateForDisplayAndSensor(eq(DISPLAY_ID), eq(null),
eq(Sensor.STRING_TYPE_PROXIMITY))).thenReturn(new RefreshRateRange(60, 60));
+ when(mInjector.isDozeState(any(Display.class))).thenReturn(false);
+
// Set the proximity to active and verify that we added a vote.
- listener.onProximityActive(true);
+ proximityListener.onProximityActive(true);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
+ assertVoteForRefreshRate(vote, 60.f);
+
+ // Set the display state to doze and verify that the vote is gone
+ when(mInjector.isDozeState(any(Display.class))).thenReturn(true);
+ displayListener.onDisplayAdded(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
+ assertNull(vote);
+
+ // Set the display state to on and verify that we added the vote back.
+ when(mInjector.isDozeState(any(Display.class))).thenReturn(false);
+ displayListener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
+ assertVoteForRefreshRate(vote, 60.f);
+
+ // Set the display state to doze and verify that the vote is gone
+ when(mInjector.isDozeState(any(Display.class))).thenReturn(true);
+ displayListener.onDisplayAdded(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
+ assertNull(vote);
+
+ // Remove the display to cause the doze state to be removed
+ displayListener.onDisplayRemoved(DISPLAY_ID);
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
assertVoteForRefreshRate(vote, 60.f);
// Turn prox off and verify vote is gone.
- listener.onProximityActive(false);
+ proximityListener.onProximityActive(false);
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
assertNull(vote);
}
@@ -1710,6 +1743,11 @@ public class DisplayModeDirectorTest {
return null;
}
+ @Override
+ public boolean isDozeState(Display d) {
+ return false;
+ }
+
void notifyPeakRefreshRateChanged() {
if (mPeakRefreshRateObserver != null) {
mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/,
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
index 61b5c2b09bb2..4cc4d55f228d 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -83,7 +83,7 @@ import java.util.stream.Collectors;
@Presubmit
public class VibrationThreadTest {
- private static final int TEST_TIMEOUT_MILLIS = 1_000;
+ private static final int TEST_TIMEOUT_MILLIS = 900;
private static final int UID = Process.ROOT_UID;
private static final int VIBRATOR_ID = 1;
private static final String PACKAGE_NAME = "package";
diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
index 4b3771b95c05..f21991defbec 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
@@ -475,7 +475,7 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
@Test
public void requestProjection_failsForBogusPackageName() throws Exception {
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0))
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
.thenReturn(TestInjector.CALLING_UID + 1);
assertThrows(SecurityException.class, () -> mService.requestProjection(mBinder,
@@ -485,7 +485,7 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
@Test
public void requestProjection_failsIfNameNotFound() throws Exception {
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0))
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
.thenThrow(new PackageManager.NameNotFoundException());
assertThrows(SecurityException.class, () -> mService.requestProjection(mBinder,
@@ -495,7 +495,8 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
@Test
public void requestProjection_failsIfNoProjectionTypes() throws Exception {
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
assertThrows(IllegalArgumentException.class,
() -> mService.requestProjection(mBinder, PROJECTION_TYPE_NONE, PACKAGE_NAME));
@@ -507,7 +508,8 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
@Test
public void requestProjection_failsIfMultipleProjectionTypes() throws Exception {
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
// Don't use PROJECTION_TYPE_ALL because that's actually == -1 and will fail the > 0 check.
int multipleProjectionTypes = PROJECTION_TYPE_AUTOMOTIVE | 0x0002 | 0x0004;
@@ -522,7 +524,8 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
@Test
public void requestProjection_enforcesToggleAutomotiveProjectionPermission() throws Exception {
- doThrow(new SecurityException()).when(mPackageManager).getPackageUid(PACKAGE_NAME, 0);
+ doThrow(new SecurityException())
+ .when(mPackageManager).getPackageUidAsUser(eq(PACKAGE_NAME), anyInt());
assertThrows(SecurityException.class, () -> mService.requestProjection(mBinder,
PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME));
@@ -531,12 +534,14 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
@Test
public void requestProjection_automotive_failsIfAlreadySetByOtherPackage() throws Exception {
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
String otherPackage = "Raconteurs";
- when(mPackageManager.getPackageUid(otherPackage, 0)).thenReturn(TestInjector.CALLING_UID);
+ when(mPackageManager.getPackageUidAsUser(eq(otherPackage), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
assertFalse(mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, otherPackage));
assertThat(mService.getProjectingPackages(PROJECTION_TYPE_AUTOMOTIVE),
contains(PACKAGE_NAME));
@@ -544,7 +549,8 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
@Test
public void requestProjection_failsIfCannotLinkToDeath() throws Exception {
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
doThrow(new RemoteException()).when(mBinder).linkToDeath(any(), anyInt());
assertFalse(mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME));
@@ -553,7 +559,8 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
@Test
public void requestProjection() throws Exception {
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
// Should work for all powers of two.
for (int i = 0; i < Integer.SIZE; ++i) {
int projectionType = 1 << i;
@@ -568,11 +575,12 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
@Test
public void releaseProjection_failsForBogusPackageName() throws Exception {
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0))
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
.thenReturn(TestInjector.CALLING_UID + 1);
assertThrows(SecurityException.class, () -> mService.releaseProjection(
@@ -582,10 +590,11 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
@Test
public void releaseProjection_failsIfNameNotFound() throws Exception {
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0))
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
.thenThrow(new PackageManager.NameNotFoundException());
assertThrows(SecurityException.class, () -> mService.releaseProjection(
@@ -595,7 +604,8 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
@Test
public void releaseProjection_enforcesToggleAutomotiveProjectionPermission() throws Exception {
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
doThrow(new SecurityException()).when(mContext).enforceCallingPermission(
@@ -613,7 +623,8 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
@Test
public void releaseProjection() throws Exception {
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
requestAllPossibleProjectionTypes();
assertEquals(PROJECTION_TYPE_ALL, mService.getActiveProjectionTypes());
@@ -632,7 +643,8 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
@Test
public void binderDeath_releasesProjection() throws Exception {
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
requestAllPossibleProjectionTypes();
assertEquals(PROJECTION_TYPE_ALL, mService.getActiveProjectionTypes());
ArgumentCaptor<IBinder.DeathRecipient> deathRecipientCaptor = ArgumentCaptor.forClass(
@@ -647,7 +659,8 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
@Test
public void getActiveProjectionTypes() throws Exception {
assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
mService.releaseProjection(PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
@@ -657,7 +670,8 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
@Test
public void getProjectingPackages() throws Exception {
assertTrue(mService.getProjectingPackages(PROJECTION_TYPE_ALL).isEmpty());
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
assertEquals(1, mService.getProjectingPackages(PROJECTION_TYPE_AUTOMOTIVE).size());
assertEquals(1, mService.getProjectingPackages(PROJECTION_TYPE_ALL).size());
@@ -681,7 +695,8 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
@Test
public void addOnProjectionStateChangedListener_callsListenerIfProjectionActive()
throws Exception {
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
@@ -710,7 +725,8 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
mService.removeOnProjectionStateChangedListener(listener);
// Now set automotive projection, should not call back.
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
verify(listener, never()).onProjectionStateChanged(anyInt(), any());
}
@@ -726,7 +742,8 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
verifyNoMoreInteractions(listener);
// Now set automotive projection, should call back.
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
verify(listener).onProjectionStateChanged(eq(PROJECTION_TYPE_AUTOMOTIVE),
eq(List.of(PACKAGE_NAME)));
@@ -752,8 +769,9 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
int fakeProjectionType = 0x0002;
int otherFakeProjectionType = 0x0004;
String otherPackageName = "Internet Arms";
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
- when(mPackageManager.getPackageUid(otherPackageName, 0))
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
+ when(mPackageManager.getPackageUidAsUser(eq(otherPackageName), anyInt()))
.thenReturn(TestInjector.CALLING_UID);
IOnProjectionStateChangedListener listener = mock(IOnProjectionStateChangedListener.class);
when(listener.asBinder()).thenReturn(mBinder); // Any binder will do.
@@ -806,7 +824,8 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
// Now kill the binder for the listener. This should remove it from the list of listeners.
listenerDeathRecipient.getValue().binderDied();
- when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
verify(listener, never()).onProjectionStateChanged(anyInt(), any());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index fa1f4aca8642..b282cd7ce1cb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -27,6 +27,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMor
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.argThat;
@@ -70,6 +71,7 @@ import java.util.function.ToIntFunction;
@Presubmit
@RunWith(WindowTestRunner.class)
public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
+ private static final long TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5);
private ActivityMetricsLogger mActivityMetricsLogger;
private ActivityMetricsLogger.LaunchingState mLaunchingState;
private ActivityMetricsLaunchObserver mLaunchObserver;
@@ -137,7 +139,7 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
// messages that are waiting for the lock.
waitHandlerIdle(mAtm.mH);
// AMLO callbacks happen on a separate thread than AML calls, so we need to use a timeout.
- return verify(mock, timeout(TimeUnit.SECONDS.toMillis(5)));
+ return verify(mock, timeout(TIMEOUT_MS));
}
private void verifyOnActivityLaunchFinished(ActivityRecord activity) {
@@ -258,15 +260,40 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
@Test
public void testOnActivityLaunchWhileSleeping() {
- notifyActivityLaunching(mTopActivity.intent);
- notifyActivityLaunched(START_SUCCESS, mTopActivity);
- doReturn(true).when(mTopActivity.mDisplayContent).isSleeping();
- mTopActivity.setState(ActivityRecord.State.RESUMED, "test");
- mTopActivity.setVisibility(false);
+ notifyActivityLaunching(mTrampolineActivity.intent);
+ notifyActivityLaunched(START_SUCCESS, mTrampolineActivity);
+ doReturn(true).when(mTrampolineActivity.mDisplayContent).isSleeping();
+ mTrampolineActivity.setState(ActivityRecord.State.RESUMED, "test");
+ mTrampolineActivity.setVisibility(false);
waitHandlerIdle(mAtm.mH);
// Not cancel immediately because in one of real cases, the keyguard may be going away or
// occluded later, then the activity can be drawn.
- verify(mLaunchObserver, never()).onActivityLaunchCancelled(eqProto(mTopActivity));
+ verify(mLaunchObserver, never()).onActivityLaunchCancelled(eqProto(mTrampolineActivity));
+
+ clearInvocations(mLaunchObserver);
+ mLaunchTopByTrampoline = true;
+ mTopActivity.mVisibleRequested = false;
+ notifyActivityLaunching(mTopActivity.intent);
+ // It should schedule a message with UNKNOWN_VISIBILITY_CHECK_DELAY_MS to check whether
+ // the launch event is still valid.
+ notifyActivityLaunched(START_SUCCESS, mTopActivity);
+
+ // The posted message will acquire wm lock, so the test needs to release the lock to verify.
+ final Throwable error = awaitInWmLock(() -> {
+ try {
+ // Though the aborting target should be eqProto(mTopActivity), use any() to avoid
+ // any changes in proto that may cause failure by different arguments.
+ verify(mLaunchObserver, timeout(TIMEOUT_MS)).onActivityLaunchCancelled(any());
+ } catch (Throwable e) {
+ // Catch any errors including assertion because this runs in another thread.
+ return e;
+ }
+ return null;
+ });
+ // The launch event must be cancelled because the activity keeps invisible.
+ if (error != null) {
+ throw new AssertionError(error);
+ }
}
@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 488875b61752..9ca09d20cd49 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -18,6 +18,7 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
@@ -145,6 +146,8 @@ import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import java.util.ArrayList;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
/**
@@ -1601,16 +1604,23 @@ public class ActivityRecordTests extends WindowTestsBase {
}
@Test
- public void testRemoveImmediately() throws RemoteException {
- final ActivityRecord activity = createActivityWithTask();
- final WindowProcessController wpc = activity.app;
- activity.getTask().removeImmediately("test");
-
- verify(mAtm.getLifecycleManager()).scheduleTransaction(any(), eq(activity.appToken),
- isA(DestroyActivityItem.class));
- assertNull(activity.app);
- assertEquals(DESTROYED, activity.getState());
- assertFalse(wpc.hasActivities());
+ public void testRemoveImmediately() {
+ final Consumer<Consumer<ActivityRecord>> test = setup -> {
+ final ActivityRecord activity = createActivityWithTask();
+ final WindowProcessController wpc = activity.app;
+ setup.accept(activity);
+ activity.getTask().removeImmediately("test");
+ try {
+ verify(mAtm.getLifecycleManager()).scheduleTransaction(any(), eq(activity.appToken),
+ isA(DestroyActivityItem.class));
+ } catch (RemoteException ignored) {
+ }
+ assertNull(activity.app);
+ assertEquals(DESTROYED, activity.getState());
+ assertFalse(wpc.hasActivities());
+ };
+ test.accept(activity -> activity.setState(RESUMED, "test"));
+ test.accept(activity -> activity.finishing = true);
}
@Test
@@ -2506,7 +2516,7 @@ public class ActivityRecordTests extends WindowTestsBase {
false, false);
waitUntilHandlersIdle();
activity2.addStartingWindow(mPackageName,
- android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1.appToken.asBinder(),
+ android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1,
true, true, false, true, false, false);
waitUntilHandlersIdle();
assertNoStartingWindow(activity1);
@@ -2523,7 +2533,7 @@ public class ActivityRecordTests extends WindowTestsBase {
// Surprise, ...! Transfer window in the middle of the creation flow.
activity2.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0,
- activity1.appToken.asBinder(), true, true, false,
+ activity1, true, true, false,
true, false, false);
});
activity1.addStartingWindow(mPackageName,
@@ -2544,7 +2554,7 @@ public class ActivityRecordTests extends WindowTestsBase {
false, false);
waitUntilHandlersIdle();
activity2.addStartingWindow(mPackageName,
- android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1.appToken.asBinder(),
+ android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1,
true, true, false, true, false, false);
waitUntilHandlersIdle();
assertNoStartingWindow(activity1);
@@ -2600,7 +2610,7 @@ public class ActivityRecordTests extends WindowTestsBase {
// Make mVisibleSetFromTransferredStartingWindow true.
final ActivityRecord middle = new ActivityBuilder(mAtm).setTask(task).build();
task.startActivityLocked(middle, null /* focusedTopActivity */,
- false /* newTask */, false /* keepCurTransition */, null /* options */,
+ false /* newTask */, false /* isTaskSwitch */, null /* options */,
null /* sourceRecord */);
middle.makeFinishingLocked();
@@ -2613,7 +2623,7 @@ public class ActivityRecordTests extends WindowTestsBase {
top.setVisible(false);
// The finishing middle should be able to transfer starting window to top.
task.startActivityLocked(top, null /* focusedTopActivity */,
- false /* newTask */, false /* keepCurTransition */, null /* options */,
+ false /* newTask */, false /* isTaskSwitch */, null /* options */,
null /* sourceRecord */);
assertNull(middle.mStartingWindow);
@@ -2650,7 +2660,7 @@ public class ActivityRecordTests extends WindowTestsBase {
// Make sure the fixed rotation transform linked to activity2 when adding starting window
// on activity2.
topActivity.addStartingWindow(mPackageName,
- android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity.appToken.asBinder(),
+ android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity,
false, false, false, true, false, false);
waitUntilHandlersIdle();
assertTrue(topActivity.hasFixedRotationTransform());
@@ -2682,6 +2692,52 @@ public class ActivityRecordTests extends WindowTestsBase {
}
@Test
+ public void testStartingWindowInTaskFragment() {
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ final WindowState startingWindow = createWindowState(
+ new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING), activity1);
+ activity1.addWindow(startingWindow);
+ activity1.attachStartingWindow(startingWindow);
+ activity1.mStartingData = mock(StartingData.class);
+ final Task task = activity1.getTask();
+ final Rect taskBounds = task.getBounds();
+ final int width = taskBounds.width();
+ final int height = taskBounds.height();
+ final BiConsumer<TaskFragment, Rect> fragmentSetup = (fragment, bounds) -> {
+ final Configuration config = fragment.getRequestedOverrideConfiguration();
+ config.windowConfiguration.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ config.windowConfiguration.setBounds(bounds);
+ fragment.onRequestedOverrideConfigurationChanged(config);
+ };
+
+ final TaskFragment taskFragment1 = new TaskFragment(
+ mAtm, null /* fragmentToken */, false /* createdByOrganizer */);
+ fragmentSetup.accept(taskFragment1, new Rect(0, 0, width / 2, height));
+ task.addChild(taskFragment1, POSITION_TOP);
+
+ final TaskFragment taskFragment2 = new TaskFragment(
+ mAtm, null /* fragmentToken */, false /* createdByOrganizer */);
+ fragmentSetup.accept(taskFragment2, new Rect(width / 2, 0, width, height));
+ task.addChild(taskFragment2, POSITION_TOP);
+ final ActivityRecord activity2 = new ActivityBuilder(mAtm).build();
+ activity2.mVisibleRequested = true;
+ taskFragment2.addChild(activity2);
+ activity1.reparent(taskFragment1, POSITION_TOP);
+
+ assertEquals(task, activity1.mStartingData.mAssociatedTask);
+ assertEquals(taskFragment1.getBounds(), activity1.getBounds());
+ // The activity was resized by task fragment, but starting window must still cover the task.
+ assertEquals(taskBounds, activity1.mStartingWindow.getBounds());
+
+ // The starting window is only removed when all embedded activities are drawn.
+ final WindowState activityWindow = mock(WindowState.class);
+ activity1.onFirstWindowDrawn(activityWindow);
+ assertNotNull(activity1.mStartingWindow);
+ activity2.onFirstWindowDrawn(activityWindow);
+ assertNull(activity1.mStartingWindow);
+ }
+
+ @Test
public void testTransitionAnimationBounds() {
removeGlobalMinSizeRestriction();
final Task task = new TaskBuilder(mSupervisor)
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 2df9a8df3a99..1b4d0a4ab5a4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -32,6 +32,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
@@ -755,12 +756,12 @@ public class ActivityStarterTests extends WindowTestsBase {
}
/**
- * This test ensures that {@link ActivityStarter#setTargetStackAndMoveToFrontIfNeeded} will
- * move the existing task to front if the current focused stack doesn't have running task.
+ * This test ensures that {@link ActivityStarter#setTargetRootTaskIfNeeded} will
+ * move the existing task to front if the current focused root task doesn't have running task.
*/
@Test
- public void testBringTaskToFrontWhenFocusedStackIsFinising() {
- // Put 2 tasks in the same stack (simulate the behavior of home stack).
+ public void testBringTaskToFrontWhenFocusedTaskIsFinishing() {
+ // Put 2 tasks in the same root task (simulate the behavior of home root task).
final Task rootTask = new TaskBuilder(mSupervisor).build();
final ActivityRecord activity = new ActivityBuilder(mAtm)
.setParentTask(rootTask)
@@ -777,13 +778,16 @@ public class ActivityStarterTests extends WindowTestsBase {
assertEquals(finishingTopActivity, mRootWindowContainer.topRunningActivity());
finishingTopActivity.finishing = true;
- // Launch the bottom task of the target stack.
+ // Launch the bottom task of the target root task.
prepareStarter(FLAG_ACTIVITY_NEW_TASK, false /* mockGetLaunchStack */)
- .setReason("testBringTaskToFrontWhenTopStackIsFinising")
- .setIntent(activity.intent)
+ .setReason("testBringTaskToFrontWhenFocusedTaskIsFinishing")
+ .setIntent(activity.intent.addFlags(
+ FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
.execute();
+ verify(activity.getRootTask()).startActivityLocked(any(), any(), anyBoolean(),
+ eq(true) /* isTaskSwitch */, any(), any());
// The hierarchies of the activity should move to front.
- assertEquals(activity, mRootWindowContainer.topRunningActivity());
+ assertEquals(activity.getTask(), mRootWindowContainer.topRunningActivity().getTask());
}
/**
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 ea203c3a82e3..d086474aa03b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -2213,6 +2213,9 @@ public class DisplayContentTests extends WindowTestsBase {
// request IME visible.
final WindowState nextImeAppTarget =
createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "nextImeAppTarget");
+ spyOn(nextImeAppTarget);
+ doReturn(true).when(nextImeAppTarget).isAnimating(PARENTS | TRANSITION,
+ ANIMATION_TYPE_APP_TRANSITION);
mDisplayContent.setImeLayeringTarget(nextImeAppTarget);
assertNotEquals(imeMenuDialog, mDisplayContent.findFocusedWindow());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 3c7c4fdb4071..4957ab96ace1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -115,7 +115,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
spyOn(mNavBarWindow);
// Disabling this call for most tests since it can override the systemUiFlags when called.
- doReturn(false).when(mDisplayPolicy).updateSystemUiVisibilityLw();
+ doNothing().when(mDisplayPolicy).updateSystemBarAttributes();
updateDisplayFrames();
}
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 e3c38b06ec88..1b078b7454b2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -788,6 +788,19 @@ public class RecentTasksTest extends WindowTestsBase {
}
@Test
+ public void testVisibleEmbeddedTask_expectNotVisible() {
+ Task task = createTaskBuilder(".Task")
+ .setFlags(FLAG_ACTIVITY_NEW_TASK)
+ .build();
+ doReturn(true).when(task).isEmbedded();
+ mRecentTasks.add(task);
+
+ assertThat(mCallbacksRecorder.mAdded).hasSize(1);
+ assertFalse("embedded task should not be visible recents",
+ 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/RootTaskTests.java b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
index 6cc60ea3d51a..56d01cd34e01 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
@@ -191,7 +191,6 @@ public class RootTaskTests extends WindowTestsBase {
final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
// Root task removal is deferred if one of its child is animating.
- doReturn(true).when(rootTask).hasWindowsAlive();
doReturn(rootTask).when(task).getAnimatingContainer(
eq(TRANSITION | CHILDREN), anyInt());
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 59894973521d..3bebf6b39de1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -320,6 +320,11 @@ public class SizeCompatTests extends WindowTestsBase {
assertScaled();
// Activity is sandboxed due to size compat mode.
assertActivityMaxBoundsSandboxed();
+
+ final WindowState appWindow = addWindowToActivity(mActivity);
+ assertTrue(mActivity.hasSizeCompatBounds());
+ assertEquals("App window must use size compat bounds for layout in screen space",
+ mActivity.getBounds(), appWindow.getBounds());
}
@Test
@@ -1981,6 +1986,61 @@ public class SizeCompatTests extends WindowTestsBase {
assertTrue(mActivity.areBoundsLetterboxed());
}
+ /**
+ * Tests that all three paths in which aspect ratio logic can be applied yield the same
+ * result, which is that aspect ratio is respected on app bounds. The three paths are
+ * fixed orientation, no fixed orientation but fixed aspect ratio, and size compat mode.
+ */
+ @Test
+ public void testAllAspectRatioLogicConsistent() {
+ // Create display that has all stable insets and does not rotate. Make sure that status bar
+ // height is greater than notch height so that stable bounds do not equal app bounds.
+ final int notchHeight = 75;
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1080, 600)
+ .setSystemDecorations(true).setNotch(notchHeight)
+ .setStatusBarHeight(notchHeight + 20).setCanRotate(false).build();
+
+ // Create task on test display.
+ final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build();
+
+ // Target min aspect ratio must be larger than parent aspect ratio to be applied.
+ final float targetMinAspectRatio = 3.0f;
+
+ // Create fixed portait activity with min aspect ratio greater than parent aspect ratio.
+ final ActivityRecord fixedOrientationActivity = new ActivityBuilder(mAtm)
+ .setTask(task).setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
+ .setMinAspectRatio(targetMinAspectRatio).build();
+ final Rect fixedOrientationAppBounds = new Rect(fixedOrientationActivity.getConfiguration()
+ .windowConfiguration.getAppBounds());
+
+ // Create activity with no fixed orientation and min aspect ratio greater than parent aspect
+ // ratio.
+ final ActivityRecord minAspectRatioActivity = new ActivityBuilder(mAtm).setTask(task)
+ .setMinAspectRatio(targetMinAspectRatio).build();
+ final Rect minAspectRatioAppBounds = new Rect(minAspectRatioActivity.getConfiguration()
+ .windowConfiguration.getAppBounds());
+
+ // Create unresizeable fixed portait activity with min aspect ratio greater than parent
+ // aspect ratio.
+ final ActivityRecord sizeCompatActivity = new ActivityBuilder(mAtm)
+ .setTask(task).setResizeMode(RESIZE_MODE_UNRESIZEABLE)
+ .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
+ .setMinAspectRatio(targetMinAspectRatio).build();
+ // Resize display running unresizeable activity to make it enter size compat mode.
+ resizeDisplay(display, 1800, 1000);
+ final Rect sizeCompatAppBounds = new Rect(sizeCompatActivity.getConfiguration()
+ .windowConfiguration.getAppBounds());
+
+ // Check that aspect ratio of app bounds is equal to the min aspect ratio.
+ final float delta = 0.01f;
+ assertEquals(targetMinAspectRatio, ActivityRecord
+ .computeAspectRatio(fixedOrientationAppBounds), delta);
+ assertEquals(targetMinAspectRatio, ActivityRecord
+ .computeAspectRatio(minAspectRatioAppBounds), delta);
+ assertEquals(targetMinAspectRatio, ActivityRecord
+ .computeAspectRatio(sizeCompatAppBounds), delta);
+ }
+
private void assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity(
float letterboxHorizontalPositionMultiplier) {
// Set up a display in landscape and ignoring orientation request.
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 629e45208234..807494429999 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -126,8 +126,15 @@ public class TaskTests extends WindowTestsBase {
final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
- task.removeIfPossible();
- // Assert that the container was removed.
+ task.remove(false /* withTransition */, "testRemoveContainer");
+ // There is still an activity to be destroyed, so the task is not removed immediately.
+ assertNotNull(task.getParent());
+ assertTrue(rootTask.hasChild());
+ assertTrue(task.hasChild());
+ assertTrue(activity.finishing);
+
+ activity.destroyed("testRemoveContainer");
+ // Assert that the container was removed after the activity is destroyed.
assertNull(task.getParent());
assertEquals(0, task.getChildCount());
assertNull(activity.getParent());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index ce2d74859931..0e504d326280 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -19,7 +19,9 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -77,6 +79,7 @@ class TestDisplayContent extends DisplayContent {
private int mPosition = POSITION_BOTTOM;
protected final ActivityTaskManagerService mService;
private boolean mSystemDecorations = false;
+ private int mStatusBarHeight = 0;
Builder(ActivityTaskManagerService service, int width, int height) {
mService = service;
@@ -125,6 +128,10 @@ class TestDisplayContent extends DisplayContent {
Insets.of(0, height, 0, 0), null, new Rect(20, 0, 80, height), null, null);
return this;
}
+ Builder setStatusBarHeight(int height) {
+ mStatusBarHeight = height;
+ return this;
+ }
Builder setCanRotate(boolean canRotate) {
mCanRotate = canRotate;
return this;
@@ -158,6 +165,14 @@ class TestDisplayContent extends DisplayContent {
doReturn(false).when(displayPolicy).hasStatusBar();
doReturn(false).when(newDisplay).supportsSystemDecorations();
}
+ if (mStatusBarHeight > 0) {
+ doReturn(true).when(displayPolicy).hasStatusBar();
+ doAnswer(invocation -> {
+ Rect inOutInsets = (Rect) invocation.getArgument(0);
+ inOutInsets.top = mStatusBarHeight;
+ return null;
+ }).when(displayPolicy).convertNonDecorInsetsToStableInsets(any(), anyInt());
+ }
Configuration c = new Configuration();
newDisplay.computeScreenConfiguration(c);
c.windowConfiguration.setWindowingMode(mWindowingMode);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 39fe952cc199..9160109e7e7f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -81,6 +81,7 @@ import android.window.ITaskOrganizer;
import android.window.IWindowContainerTransactionCallback;
import android.window.StartingWindowInfo;
import android.window.TaskAppearedInfo;
+import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import androidx.test.filters.SmallTest;
@@ -1275,6 +1276,24 @@ public class WindowOrganizerTests extends WindowTestsBase {
assertTrue(optionsCaptor.getValue().getOriginalOptions().getTransientLaunch());
}
+ @Test
+ public void testResumeTopsWhenLeavingPinned() {
+ final ActivityRecord record = makePipableActivity();
+ final Task rootTask = record.getRootTask();
+
+ clearInvocations(mWm.mAtmService.mRootWindowContainer);
+ final WindowContainerTransaction t = new WindowContainerTransaction();
+ WindowContainerToken wct = rootTask.mRemoteToken.toWindowContainerToken();
+ t.setWindowingMode(wct, WINDOWING_MODE_PINNED);
+ mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
+ verify(mWm.mAtmService.mRootWindowContainer).resumeFocusedTasksTopActivities();
+
+ clearInvocations(mWm.mAtmService.mRootWindowContainer);
+ t.setWindowingMode(wct, WINDOWING_MODE_FULLSCREEN);
+ mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
+ verify(mWm.mAtmService.mRootWindowContainer).resumeFocusedTasksTopActivities();
+ }
+
/**
* Verifies that task vanished is called for a specific task.
*/
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 965f126000fd..734172fc1549 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -36,6 +36,7 @@ import android.content.PermissionChecker;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.SoundTrigger;
import android.media.AudioFormat;
+import android.media.AudioManagerInternal;
import android.media.permission.Identity;
import android.media.permission.PermissionUtil;
import android.os.Binder;
@@ -44,6 +45,7 @@ import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SharedMemory;
@@ -275,6 +277,7 @@ final class HotwordDetectionConnection {
LocalServices.getService(PermissionManagerServiceInternal.class)
.setHotwordDetectionServiceProvider(null);
mIdentity = null;
+ updateServiceUidForAudioPolicy(Process.INVALID_UID);
}
mCancellationTaskFuture.cancel(/* may interrupt */ true);
if (mAudioFlinger != null) {
@@ -893,6 +896,8 @@ final class HotwordDetectionConnection {
connection.run(service -> service.ping(new IRemoteCallback.Stub() {
@Override
public void sendResult(Bundle bundle) throws RemoteException {
+ // TODO: Exit if the service has been unbound already (though there's a very low
+ // chance this happens).
if (DEBUG) {
Slog.d(TAG, "updating hotword UID " + Binder.getCallingUid());
}
@@ -902,10 +907,21 @@ final class HotwordDetectionConnection {
LocalServices.getService(PermissionManagerServiceInternal.class)
.setHotwordDetectionServiceProvider(() -> uid);
mIdentity = new HotwordDetectionServiceIdentity(uid, mVoiceInteractionServiceUid);
+ updateServiceUidForAudioPolicy(uid);
}
}));
}
+ private void updateServiceUidForAudioPolicy(int uid) {
+ mScheduledExecutorService.execute(() -> {
+ final AudioManagerInternal audioManager =
+ LocalServices.getService(AudioManagerInternal.class);
+ if (audioManager != null) {
+ audioManager.setHotwordDetectionServiceUid(uid);
+ }
+ });
+ }
+
private static void bestEffortClose(Closeable closeable) {
try {
closeable.close();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java
index b9e1fcd7ffd3..c0c3e6f530db 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerSessionPermissionsDecorator.java
@@ -29,7 +29,6 @@ import android.media.permission.Identity;
import android.media.permission.PermissionUtil;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.ServiceSpecificException;
import android.text.TextUtils;
import android.util.Slog;
@@ -61,7 +60,7 @@ final class SoundTriggerSessionPermissionsDecorator implements
@Override
public SoundTrigger.ModuleProperties getDspModuleProperties() throws RemoteException {
- // No permission needed.
+ // No permission needed here (the app must have the Assistant Role to retrieve the session).
return mDelegate.getDspModuleProperties();
}
@@ -72,7 +71,9 @@ final class SoundTriggerSessionPermissionsDecorator implements
if (DEBUG) {
Slog.d(TAG, "startRecognition");
}
- enforcePermissions();
+ if (!isHoldingPermissions()) {
+ return SoundTrigger.STATUS_PERMISSION_DENIED;
+ }
return mDelegate.startRecognition(i, s, iHotwordRecognitionStatusCallback,
recognitionConfig, b);
}
@@ -81,25 +82,28 @@ final class SoundTriggerSessionPermissionsDecorator implements
public int stopRecognition(int i,
IHotwordRecognitionStatusCallback iHotwordRecognitionStatusCallback)
throws RemoteException {
- enforcePermissions();
+ // Stopping a model does not require special permissions. Having a handle to the session is
+ // sufficient.
return mDelegate.stopRecognition(i, iHotwordRecognitionStatusCallback);
}
@Override
public int setParameter(int i, int i1, int i2) throws RemoteException {
- enforcePermissions();
+ if (!isHoldingPermissions()) {
+ return SoundTrigger.STATUS_PERMISSION_DENIED;
+ }
return mDelegate.setParameter(i, i1, i2);
}
@Override
public int getParameter(int i, int i1) throws RemoteException {
- enforcePermissions();
+ // No permission needed here (the app must have the Assistant Role to retrieve the session).
return mDelegate.getParameter(i, i1);
}
@Override
public SoundTrigger.ModelParamRange queryParameter(int i, int i1) throws RemoteException {
- enforcePermissions();
+ // No permission needed here (the app must have the Assistant Role to retrieve the session).
return mDelegate.queryParameter(i, i1);
}
@@ -110,15 +114,21 @@ final class SoundTriggerSessionPermissionsDecorator implements
}
// TODO: Share this code with SoundTriggerMiddlewarePermission.
- private void enforcePermissions() {
- enforcePermissionForPreflight(mContext, mOriginatorIdentity, RECORD_AUDIO);
- enforcePermissionForPreflight(mContext, mOriginatorIdentity, CAPTURE_AUDIO_HOTWORD);
+ private boolean isHoldingPermissions() {
+ try {
+ enforcePermissionForPreflight(mContext, mOriginatorIdentity, RECORD_AUDIO);
+ enforcePermissionForPreflight(mContext, mOriginatorIdentity, CAPTURE_AUDIO_HOTWORD);
+ return true;
+ } catch (SecurityException e) {
+ Slog.e(TAG, e.toString());
+ return false;
+ }
}
/**
* Throws a {@link SecurityException} if originator permanently doesn't have the given
- * permission, or a {@link ServiceSpecificException} with a {@link
- * #TEMPORARY_PERMISSION_DENIED} if caller originator doesn't have the given permission.
+ * permission.
+ * Soft (temporary) denials are considered OK for preflight purposes.
*
* @param context A {@link Context}, used for permission checks.
* @param identity The identity to check.
@@ -130,15 +140,12 @@ final class SoundTriggerSessionPermissionsDecorator implements
permission);
switch (status) {
case PermissionChecker.PERMISSION_GRANTED:
+ case PermissionChecker.PERMISSION_SOFT_DENIED:
return;
case PermissionChecker.PERMISSION_HARD_DENIED:
throw new SecurityException(
TextUtils.formatSimple("Failed to obtain permission %s for identity %s",
permission, toString(identity)));
- case PermissionChecker.PERMISSION_SOFT_DENIED:
- throw new ServiceSpecificException(TEMPORARY_PERMISSION_DENIED,
- TextUtils.formatSimple("Failed to obtain permission %s for identity %s",
- permission, toString(identity)));
default:
throw new RuntimeException("Unexpected permission check result.");
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 71541ad729d5..9ea2b7b12ad0 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1896,17 +1896,19 @@ public class VoiceInteractionManagerService extends SystemService {
String serviceComponentName = serviceInfo.getComponentName()
.flattenToShortString();
-
- String serviceRecognizerName = new ComponentName(pkg,
- voiceInteractionServiceInfo.getRecognitionService())
- .flattenToShortString();
+ if (voiceInteractionServiceInfo.getRecognitionService() == null) {
+ Slog.e(TAG, "The RecognitionService must be set to avoid boot "
+ + "loop on earlier platform version. Also make sure that this "
+ + "is a valid RecognitionService when running on Android 11 "
+ + "or earlier.");
+ serviceComponentName = "";
+ }
Settings.Secure.putStringForUser(getContext().getContentResolver(),
Settings.Secure.ASSISTANT, serviceComponentName, userId);
Settings.Secure.putStringForUser(getContext().getContentResolver(),
Settings.Secure.VOICE_INTERACTION_SERVICE, serviceComponentName,
userId);
-
return;
}
@@ -1947,6 +1949,29 @@ public class VoiceInteractionManagerService extends SystemService {
}
}
+ private void resetServicesIfNoRecognitionService(ComponentName serviceComponent,
+ int userHandle) {
+ for (ResolveInfo resolveInfo : queryInteractorServices(userHandle,
+ serviceComponent.getPackageName())) {
+ VoiceInteractionServiceInfo serviceInfo =
+ new VoiceInteractionServiceInfo(
+ mContext.getPackageManager(),
+ resolveInfo.serviceInfo);
+ if (!serviceInfo.getSupportsAssist()) {
+ continue;
+ }
+ if (serviceInfo.getRecognitionService() == null) {
+ Slog.e(TAG, "The RecognitionService must be set to "
+ + "avoid boot loop on earlier platform version. "
+ + "Also make sure that this is a valid "
+ + "RecognitionService when running on Android 11 "
+ + "or earlier.");
+ setCurInteractor(null, userHandle);
+ resetCurAssistant(userHandle);
+ }
+ }
+ }
+
PackageMonitor mPackageMonitor = new PackageMonitor() {
@Override
public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
@@ -2090,6 +2115,7 @@ public class VoiceInteractionManagerService extends SystemService {
change = isPackageAppearing(curInteractor.getPackageName());
if (change != PACKAGE_UNCHANGED) {
+ resetServicesIfNoRecognitionService(curInteractor, userHandle);
// If current interactor is now appearing, for any reason, then
// restart our connection with it.
if (mImpl != null && curInteractor.getPackageName().equals(
@@ -2112,6 +2138,13 @@ public class VoiceInteractionManagerService extends SystemService {
initForUser(userHandle);
return;
}
+ change = isPackageAppearing(curAssistant.getPackageName());
+ if (change != PACKAGE_UNCHANGED) {
+ // It is possible to update Assistant without a voice interactor to one
+ // with a voice-interactor. We should make sure the recognition service
+ // is set to avoid boot loop.
+ resetServicesIfNoRecognitionService(curAssistant, userHandle);
+ }
}
// There is no interactor, so just deal with a simple recognizer.
diff --git a/telephony/OWNERS b/telephony/OWNERS
index 628c48070314..4df8a4bc6413 100644
--- a/telephony/OWNERS
+++ b/telephony/OWNERS
@@ -4,13 +4,14 @@ amitmahajan@google.com
breadley@google.com
fionaxu@google.com
jackyu@google.com
-hallliu@google.com
rgreenwalt@google.com
tgunn@google.com
jminjie@google.com
shuoq@google.com
-refuhoo@google.com
nazaninb@google.com
sarahchin@google.com
-dbright@google.com
xiaotonj@google.com
+huiwang@google.com
+jayachandranc@google.com
+chinmayd@google.com
+amruthr@google.com
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
index c18ab33eb2c9..f0048248a5cc 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
@@ -193,6 +193,10 @@ public class SipDelegateAidlWrapper implements DelegateStateCallback, DelegateMe
return mDelegateBinder;
}
+ public ISipDelegateStateCallback getStateCallbackBinder() {
+ return mStateBinder;
+ }
+
private void notifyLocalMessageFailedToBeReceived(SipMessage m, int reason) {
String transactionId = m.getViaBranchParameter();
SipDelegate d = mDelegate;
diff --git a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
index 1f74c09af0f6..13ea99735ab4 100644
--- a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
@@ -21,6 +21,7 @@ import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.os.Binder;
import android.os.IBinder;
+import android.os.RemoteException;
import android.telephony.ims.DelegateMessageCallback;
import android.telephony.ims.DelegateRequest;
import android.telephony.ims.DelegateStateCallback;
@@ -33,6 +34,7 @@ import android.telephony.ims.aidl.SipDelegateAidlWrapper;
import android.util.Log;
import java.util.ArrayList;
+import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -49,10 +51,15 @@ import java.util.concurrent.Executor;
public class SipTransportImplBase {
private static final String LOG_TAG = "SipTransportIB";
- private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
+ private final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
- mBinderExecutor.execute(() -> binderDiedInternal());
+ // Clean up all binders in this case.
+ mBinderExecutor.execute(() -> binderDiedInternal(null));
+ }
+ @Override
+ public void binderDied(IBinder who) {
+ mBinderExecutor.execute(() -> binderDiedInternal(who));
}
};
@@ -142,6 +149,7 @@ public class SipTransportImplBase {
ISipDelegateStateCallback cb, ISipDelegateMessageCallback mc) {
SipDelegateAidlWrapper wrapper = new SipDelegateAidlWrapper(mBinderExecutor, cb, mc);
mDelegates.add(wrapper);
+ linkDeathRecipient(wrapper);
createSipDelegate(subId, r, wrapper, wrapper);
}
@@ -155,6 +163,7 @@ public class SipTransportImplBase {
}
if (result != null) {
+ unlinkDeathRecipient(result);
mDelegates.remove(result);
destroySipDelegate(result.getDelegate(), reason);
} else {
@@ -163,12 +172,37 @@ public class SipTransportImplBase {
}
}
- private void binderDiedInternal() {
+ private void linkDeathRecipient(SipDelegateAidlWrapper w) {
+ try {
+ w.getStateCallbackBinder().asBinder().linkToDeath(mDeathRecipient, 0);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "linkDeathRecipient, remote process already died, cleaning up.");
+ mDeathRecipient.binderDied(w.getStateCallbackBinder().asBinder());
+ }
+ }
+
+ private void unlinkDeathRecipient(SipDelegateAidlWrapper w) {
+ try {
+ w.getStateCallbackBinder().asBinder().unlinkToDeath(mDeathRecipient, 0);
+ } catch (NoSuchElementException e) {
+ // Ignore this case.
+ }
+ }
+
+ private void binderDiedInternal(IBinder who) {
for (SipDelegateAidlWrapper w : mDelegates) {
- destroySipDelegate(w.getDelegate(),
- SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
+ // If the binder itself was not given from the platform, just clean up all binders.
+ if (who == null || w.getStateCallbackBinder().asBinder().equals(who)) {
+ Log.w(LOG_TAG, "Binder death detected for " + w + ", calling destroy and "
+ + "removing.");
+ mDelegates.remove(w);
+ destroySipDelegate(w.getDelegate(),
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
+ return;
+ }
}
- mDelegates.clear();
+ Log.w(LOG_TAG, "Binder death detected for IBinder " + who + ", but couldn't find matching "
+ + "SipDelegate");
}
/**
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 217a72b90fd4..7731e098d9f5 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -25,11 +25,17 @@ package {
android_test {
name: "FlickerTests",
- srcs: ["src/**/*.java", "src/**/*.kt"],
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
manifest: "AndroidManifest.xml",
test_config: "AndroidTest.xml",
platform_apis: true,
certificate: "platform",
+ optimize: {
+ enabled: false,
+ },
test_suites: ["device-tests"],
libs: ["android.test.runner"],
static_libs: [
@@ -46,6 +52,9 @@ android_test {
java_library {
name: "wm-flicker-common-assertions",
platform_apis: true,
+ optimize: {
+ enabled: false,
+ },
srcs: [
"src/**/*Assertions.java",
"src/**/*Assertions.kt",
@@ -56,20 +65,23 @@ java_library {
static_libs: [
"flickerlib",
"truth-prebuilt",
- "app-helpers-core"
+ "app-helpers-core",
],
}
java_library {
name: "wm-flicker-common-app-helpers",
platform_apis: true,
+ optimize: {
+ enabled: false,
+ },
srcs: [
- "**/helpers/*"
+ "**/helpers/*",
],
static_libs: [
"flickerlib",
"flickertestapplib",
"truth-prebuilt",
- "app-helpers-core"
+ "app-helpers-core",
],
-} \ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index a540dffb3c9c..08c9e5dc7b64 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -14,77 +14,30 @@
* limitations under the License.
*/
+@file:JvmName("CommonAssertions")
package com.android.server.wm.flicker
-import android.platform.helpers.IAppHelper
+import android.content.ComponentName
import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.NAV_BAR_LAYER_NAME
-import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.NAV_BAR_WINDOW_NAME
-import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.STATUS_BAR_LAYER_NAME
-import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.STATUS_BAR_WINDOW_NAME
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
-val HOME_WINDOW_TITLE = arrayOf("Wallpaper", "Launcher")
+val LAUNCHER_COMPONENT = ComponentName("com.google.android.apps.nexuslauncher",
+ "com.google.android.apps.nexuslauncher.NexusLauncherActivity")
-fun FlickerTestParameter.statusBarWindowIsAlwaysVisible() {
+fun FlickerTestParameter.statusBarWindowIsVisible() {
assertWm {
- this.showsAboveAppWindow(STATUS_BAR_WINDOW_NAME)
+ this.isAboveAppWindowVisible(WindowManagerStateHelper.STATUS_BAR_COMPONENT)
}
}
-fun FlickerTestParameter.navBarWindowIsAlwaysVisible() {
+fun FlickerTestParameter.navBarWindowIsVisible() {
assertWm {
- this.showsAboveAppWindow(NAV_BAR_WINDOW_NAME)
- }
-}
-
-fun FlickerTestParameter.launcherReplacesAppWindowAsTopWindow(testApp: IAppHelper) {
- assertWm {
- this.showsAppWindowOnTop(testApp.getPackage())
- .then()
- .showsAppWindowOnTop(*HOME_WINDOW_TITLE)
- }
-}
-
-fun FlickerTestParameter.launcherWindowBecomesVisible() {
- assertWm {
- this.hidesBelowAppWindow(*HOME_WINDOW_TITLE)
- .then()
- .showsBelowAppWindow(*HOME_WINDOW_TITLE)
- }
-}
-
-fun FlickerTestParameter.launcherWindowBecomesInvisible() {
- assertWm {
- this.showsBelowAppWindow(*HOME_WINDOW_TITLE)
- .then()
- .hidesBelowAppWindow(*HOME_WINDOW_TITLE)
- }
-}
-
-fun FlickerTestParameter.appWindowAlwaysVisibleOnTop(packageName: String) {
- assertWm {
- this.showsAppWindowOnTop(packageName)
- }
-}
-
-fun FlickerTestParameter.appWindowBecomesVisible(appName: String) {
- assertWm {
- this.hidesAppWindow(appName)
- .then()
- .showsAppWindow(appName)
- }
-}
-
-fun FlickerTestParameter.appWindowBecomesInVisible(appName: String) {
- assertWm {
- this.showsAppWindow(appName)
- .then()
- .hidesAppWindow(appName)
+ this.isAboveAppWindowVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
}
}
@JvmOverloads
-fun FlickerTestParameter.noUncoveredRegions(
+fun FlickerTestParameter.entireScreenCovered(
beginRotation: Int,
endRotation: Int = beginRotation,
allStates: Boolean = true
@@ -111,37 +64,21 @@ fun FlickerTestParameter.noUncoveredRegions(
}
}
-@JvmOverloads
-fun FlickerTestParameter.navBarLayerIsAlwaysVisible(rotatesScreen: Boolean = false) {
- if (rotatesScreen) {
- assertLayers {
- this.isVisible(NAV_BAR_LAYER_NAME)
- .then()
- .isInvisible(NAV_BAR_LAYER_NAME)
- .then()
- .isVisible(NAV_BAR_LAYER_NAME)
- }
- } else {
- assertLayers {
- this.isVisible(NAV_BAR_LAYER_NAME)
- }
+fun FlickerTestParameter.navBarLayerIsVisible() {
+ assertLayersStart {
+ this.isVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
+ }
+ assertLayersEnd {
+ this.isVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
}
}
-@JvmOverloads
-fun FlickerTestParameter.statusBarLayerIsAlwaysVisible(rotatesScreen: Boolean = false) {
- if (rotatesScreen) {
- assertLayers {
- this.isVisible(STATUS_BAR_LAYER_NAME)
- .then()
- .isInvisible(STATUS_BAR_LAYER_NAME)
- .then()
- .isVisible(STATUS_BAR_LAYER_NAME)
- }
- } else {
- assertLayers {
- this.isVisible(STATUS_BAR_LAYER_NAME)
- }
+fun FlickerTestParameter.statusBarLayerIsVisible() {
+ assertLayersStart {
+ this.isVisible(WindowManagerStateHelper.STATUS_BAR_COMPONENT)
+ }
+ assertLayersEnd {
+ this.isVisible(WindowManagerStateHelper.STATUS_BAR_COMPONENT)
}
}
@@ -154,10 +91,10 @@ fun FlickerTestParameter.navBarLayerRotatesAndScales(
val endingPos = WindowUtils.getNavigationBarPosition(endRotation)
assertLayersStart {
- this.visibleRegion(NAV_BAR_LAYER_NAME).coversExactly(startingPos)
+ this.visibleRegion(WindowManagerStateHelper.NAV_BAR_COMPONENT).coversExactly(startingPos)
}
assertLayersEnd {
- this.visibleRegion(NAV_BAR_LAYER_NAME).coversExactly(endingPos)
+ this.visibleRegion(WindowManagerStateHelper.NAV_BAR_COMPONENT).coversExactly(endingPos)
}
}
@@ -170,54 +107,46 @@ fun FlickerTestParameter.statusBarLayerRotatesScales(
val endingPos = WindowUtils.getStatusBarPosition(endRotation)
assertLayersStart {
- this.visibleRegion(STATUS_BAR_LAYER_NAME).coversExactly(startingPos)
+ this.visibleRegion(WindowManagerStateHelper.STATUS_BAR_COMPONENT).coversExactly(startingPos)
}
assertLayersEnd {
- this.visibleRegion(STATUS_BAR_LAYER_NAME).coversExactly(endingPos)
- }
-}
-
-fun FlickerTestParameter.appLayerReplacesLauncher(appName: String) {
- assertLayers {
- this.isVisible(*HOME_WINDOW_TITLE)
- .then()
- .isVisible(appName)
+ this.visibleRegion(WindowManagerStateHelper.STATUS_BAR_COMPONENT).coversExactly(endingPos)
}
}
-fun FlickerTestParameter.launcherLayerReplacesApp(testApp: IAppHelper) {
+/**
+ * Asserts that:
+ * [originalLayer] is visible at the start of the trace
+ * [originalLayer] becomes invisible during the trace and (in the same entry) [newLayer]
+ * becomes visible
+ * [newLayer] remains visible until the end of the trace
+ *
+ * @param originalLayer Layer that should be visible at the start
+ * @param newLayer Layer that should be visible at the end
+ * @param ignoreSnapshot If the snapshot layer should be ignored during the transition
+ * (useful mostly for app launch)
+ */
+fun FlickerTestParameter.replacesLayer(
+ originalLayer: ComponentName,
+ newLayer: ComponentName,
+ ignoreSnapshot: Boolean = false
+) {
assertLayers {
- this.isVisible(testApp.getPackage())
- .then()
- .isInvisible(testApp.getPackage())
- .isVisible(*HOME_WINDOW_TITLE)
+ val assertion = this.isVisible(originalLayer)
+ if (ignoreSnapshot) {
+ assertion.then()
+ .isVisible(WindowManagerStateHelper.SNAPSHOT_COMPONENT, isOptional = true)
+ }
+ assertion.then().isVisible(newLayer)
}
-}
-fun FlickerTestParameter.layerBecomesVisible(packageName: String) {
- assertLayers {
- this.isInvisible(packageName)
- .then()
- .isVisible(packageName)
- }
-}
-
-fun FlickerTestParameter.layerBecomesInvisible(packageName: String) {
- assertLayers {
- this.isVisible(packageName)
- .then()
- .isInvisible(packageName)
+ assertLayersStart {
+ this.isVisible(originalLayer)
+ .isInvisible(newLayer)
}
-}
-fun FlickerTestParameter.focusChanges(vararg windows: String) {
- assertEventLog {
- this.focusChanges(windows)
+ assertLayersEnd {
+ this.isInvisible(originalLayer)
+ .isVisible(newLayer)
}
}
-
-fun FlickerTestParameter.focusDoesNotChange() {
- assertEventLog {
- this.focusDoesNotChange()
- }
-} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index 71184c2e0aa2..90c851d6e266 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -1,3 +1,4 @@
+
/*
* Copyright (C) 2020 The Android Open Source Project
*
@@ -16,6 +17,8 @@
package com.android.server.wm.flicker.close
+import android.platform.test.annotations.Postsubmit
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -23,6 +26,7 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -46,6 +50,13 @@ class CloseAppBackButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio
}
}
+ @FlakyTest
+ @Test
+ override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+ @Postsubmit
+ override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index 6786279ae107..e8391ed9cfa1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -16,6 +16,8 @@
package com.android.server.wm.flicker.close
+import android.platform.test.annotations.Postsubmit
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -23,6 +25,7 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -46,6 +49,13 @@ class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio
}
}
+ @FlakyTest
+ @Test
+ override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+ @Postsubmit
+ override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
+
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index f7f977d7bd0a..f9e6babee938 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -19,30 +19,35 @@ package com.android.server.wm.flicker.close
import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
import android.view.Surface
-import androidx.test.filters.FlakyTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.LAUNCHER_COMPONENT
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.helpers.StandardAppHelper
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.launcherReplacesAppWindowAsTopWindow
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.navBarWindowIsVisible
+import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.launcherLayerReplacesApp
-import com.android.server.wm.flicker.launcherWindowBecomesVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
+import com.android.server.wm.flicker.replacesLayer
import org.junit.Test
+/**
+ * Base test class for transitions that close an app back to the launcher screen
+ */
abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter) {
protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
protected open val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
+
+ /**
+ * Specification of the test transition to execute
+ */
protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
setup {
eachRun {
@@ -66,29 +71,29 @@ abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter)
@Presubmit
@Test
- open fun navBarWindowIsAlwaysVisible() {
- testSpec.navBarWindowIsAlwaysVisible()
+ open fun navBarWindowIsVisible() {
+ testSpec.navBarWindowIsVisible()
}
@Presubmit
@Test
- open fun statusBarWindowIsAlwaysVisible() {
- testSpec.statusBarWindowIsAlwaysVisible()
+ open fun statusBarWindowIsVisible() {
+ testSpec.statusBarWindowIsVisible()
}
- @FlakyTest
+ @Presubmit
@Test
- open fun navBarLayerIsAlwaysVisible() {
- testSpec.navBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
+ open fun navBarLayerIsVisible() {
+ testSpec.navBarLayerIsVisible()
}
@Presubmit
@Test
- open fun statusBarLayerIsAlwaysVisible() {
- testSpec.statusBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
+ open fun statusBarLayerIsVisible() {
+ testSpec.statusBarLayerIsVisible()
}
- @FlakyTest
+ @Presubmit
@Test
open fun navBarLayerRotatesAndScales() {
testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
@@ -118,25 +123,33 @@ abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter)
@Presubmit
@Test
- open fun noUncoveredRegions() {
- testSpec.noUncoveredRegions(testSpec.config.startRotation, Surface.ROTATION_0)
+ open fun entireScreenCovered() {
+ testSpec.entireScreenCovered(testSpec.config.startRotation, Surface.ROTATION_0)
}
@Presubmit
@Test
open fun launcherReplacesAppWindowAsTopWindow() {
- testSpec.launcherReplacesAppWindowAsTopWindow(testApp)
+ testSpec.assertWm {
+ this.isAppWindowOnTop(testApp.component)
+ .then()
+ .isAppWindowOnTop(LAUNCHER_COMPONENT)
+ }
}
@Presubmit
@Test
open fun launcherWindowBecomesVisible() {
- testSpec.launcherWindowBecomesVisible()
+ testSpec.assertWm {
+ this.isAppWindowInvisible(LAUNCHER_COMPONENT)
+ .then()
+ .isAppWindowOnTop(LAUNCHER_COMPONENT)
+ }
}
@Presubmit
@Test
open fun launcherLayerReplacesApp() {
- testSpec.launcherLayerReplacesApp(testApp)
+ testSpec.replacesLayer(testApp.component, LAUNCHER_COMPONENT)
}
} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
index 83fddae5b1a7..d224af97462e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
@@ -61,7 +61,8 @@ open class ImeAppHelper @JvmOverloads constructor(
if (wmHelper == null) {
device.waitForIdle()
} else {
- wmHelper.waitImeWindowShown()
+ wmHelper.waitImeShown()
+ wmHelper.waitForAppTransitionIdle()
}
}
@@ -78,7 +79,7 @@ open class ImeAppHelper @JvmOverloads constructor(
if (wmHelper == null) {
device.waitForIdle()
} else {
- wmHelper.waitImeWindowGone()
+ wmHelper.waitImeGone()
}
}
} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index b5757fd21ee0..384d8e8e998d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -18,8 +18,8 @@ package com.android.server.wm.flicker.ime
import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
+import android.view.Surface
import android.view.WindowManagerPolicyConstants
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -28,15 +28,15 @@ 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.entireScreenCovered
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -46,6 +46,14 @@ import org.junit.runners.Parameterized
/**
* Test IME window closing back to app window transitions.
+ *
+ * This test doesn't work on 90 degrees. According to the InputMethodService documentation:
+ *
+ * Don't show if this is not explicitly requested by the user and the input method
+ * is fullscreen. That would be too disruptive.
+ *
+ * More details on b/190352379
+ *
* To run this test: `atest FlickerTests:CloseImeAutoOpenWindowToAppTest`
*/
@RequiresDevice
@@ -79,37 +87,55 @@ class CloseImeAutoOpenWindowToAppTest(private val testSpec: FlickerTestParameter
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
@Presubmit
@Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
@Presubmit
@Test
fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
testSpec.assertWm {
- this.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE,
- WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME))
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry()
}
}
@Presubmit
@Test
- fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(testApp)
+ fun imeAppWindowIsAlwaysVisible() {
+ testSpec.assertWm {
+ this.isAppWindowOnTop(testApp.component)
+ }
+ }
@Presubmit
@Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+ fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
@Presubmit
@Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+ fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
- @FlakyTest
+ @Presubmit
@Test
- fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
+ fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation)
+
+ @Presubmit
+ @Test
+ fun imeLayerVisibleStart() {
+ testSpec.assertLayersStart {
+ this.isVisible(WindowManagerStateHelper.IME_COMPONENT)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun imeLayerInvisibleEnd() {
+ testSpec.assertLayersEnd {
+ this.isInvisible(WindowManagerStateHelper.IME_COMPONENT)
+ }
+ }
@Presubmit
@Test
@@ -117,15 +143,19 @@ class CloseImeAutoOpenWindowToAppTest(private val testSpec: FlickerTestParameter
@Presubmit
@Test
- fun imeAppLayerIsAlwaysVisible() = testSpec.imeAppLayerIsAlwaysVisible(testApp)
+ fun imeAppLayerIsAlwaysVisible() {
+ testSpec.assertLayers {
+ this.isVisible(testApp.component)
+ }
+ }
- @FlakyTest
+ @Presubmit
@Test
fun navBarLayerRotatesAndScales() {
testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
}
- @FlakyTest
+ @Presubmit
@Test
fun statusBarLayerRotatesScales() {
testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation)
@@ -145,8 +175,11 @@ class CloseImeAutoOpenWindowToAppTest(private val testSpec: FlickerTestParameter
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(repetitions = 5,
+ // b/190352379 (IME doesn't show on app launch in 90 degrees)
+ supportedRotations = listOf(Surface.ROTATION_0),
supportedNavigationModes = listOf(
- WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY)
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
+ WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)
)
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index 549e44c511b9..ade215b3022d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -30,14 +30,14 @@ 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.ImeAppAutoFocusHelper
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.navBarWindowIsVisible
+import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -47,6 +47,14 @@ import org.junit.runners.Parameterized
/**
* Test IME window closing back to app window transitions.
+ *
+ * This test doesn't work on 90 degrees. According to the InputMethodService documentation:
+ *
+ * Don't show if this is not explicitly requested by the user and the input method
+ * is fullscreen. That would be too disruptive.
+ *
+ * More details on b/190352379
+ *
* To run this test: `atest FlickerTests:CloseImeAutoOpenWindowToHomeTest`
*/
@RequiresDevice
@@ -75,51 +83,73 @@ class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParamete
transitions {
device.pressHome()
wmHelper.waitForHomeActivityVisible()
- wmHelper.waitImeWindowGone()
+ wmHelper.waitImeGone()
}
}
}
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
@Presubmit
@Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
@Presubmit
@Test
fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
testSpec.assertWm {
- this.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE,
- WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME))
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry()
}
}
- @FlakyTest
+ @FlakyTest(bugId = 190189685)
@Test
- fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible()
+ fun imeAppWindowBecomesInvisible() {
+ testSpec.assertWm {
+ this.isAppWindowOnTop(testApp.component)
+ .then()
+ .appWindowNotOnTop(testApp.component)
+ }
+ }
- @FlakyTest
+ @Presubmit
@Test
- fun imeAppWindowBecomesInvisible() = testSpec.imeAppWindowBecomesInvisible(testApp)
+ fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation,
+ Surface.ROTATION_0)
@Presubmit
@Test
- fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
- Surface.ROTATION_0)
+ fun imeLayerVisibleStart() {
+ testSpec.assertLayersStart {
+ this.isVisible(WindowManagerStateHelper.IME_COMPONENT)
+ }
+ }
- @FlakyTest
+ @Presubmit
+ @Test
+ fun imeLayerInvisibleEnd() {
+ testSpec.assertLayersEnd {
+ this.isInvisible(WindowManagerStateHelper.IME_COMPONENT)
+ }
+ }
+
+ @Presubmit
@Test
fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
@Presubmit
@Test
- fun imeAppLayerBecomesInvisible() = testSpec.imeAppLayerBecomesInvisible(testApp)
+ fun imeAppLayerBecomesInvisible() {
+ testSpec.assertLayers {
+ this.isVisible(testApp.component)
+ .then()
+ .isInvisible(testApp.component)
+ }
+ }
- @FlakyTest
+ @Presubmit
@Test
fun navBarLayerRotatesAndScales() {
testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation, Surface.ROTATION_0)
@@ -133,18 +163,19 @@ class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParamete
@Presubmit
@Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+ fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
- @FlakyTest
+ @Presubmit
@Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+ fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
@Presubmit
@Test
fun visibleLayersShownMoreThanOneConsecutiveEntry() {
testSpec.assertLayers {
- this.visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(IME_WINDOW_TITLE, WindowManagerStateHelper.SPLASH_SCREEN_NAME))
+ this.visibleLayersShownMoreThanOneConsecutiveEntry(listOf(
+ WindowManagerStateHelper.IME_COMPONENT,
+ WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT))
}
}
@@ -154,8 +185,11 @@ class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParamete
fun getParams(): Collection<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(repetitions = 1,
+ // b/190352379 (IME doesn't show on app launch in 90 degrees)
+ supportedRotations = listOf(Surface.ROTATION_0),
supportedNavigationModes = listOf(
- WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY)
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
+ WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)
)
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index 82ca074b5ef2..cdfcff3d4beb 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -28,13 +28,13 @@ 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.ImeAppHelper
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.navBarWindowIsVisible
+import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
import org.junit.Assume
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import org.junit.FixMethodOrder
@@ -61,7 +61,7 @@ class CloseImeWindowToAppTest(private val testSpec: FlickerTestParameter) {
return FlickerBuilder(instrumentation).apply {
setup {
test {
- testApp.launchViaIntent()
+ testApp.launchViaIntent(wmHelper)
}
eachRun {
testApp.openIME(device, wmHelper)
@@ -80,37 +80,42 @@ class CloseImeWindowToAppTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
@Presubmit
@Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
@Presubmit
@Test
fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
testSpec.assertWm {
- this.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE,
- WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME))
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(
+ WindowManagerStateHelper.IME_COMPONENT,
+ WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT,
+ WindowManagerStateHelper.SNAPSHOT_COMPONENT))
}
}
@Presubmit
@Test
- fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(testApp)
+ fun imeAppWindowIsAlwaysVisible() {
+ testSpec.assertWm {
+ this.isAppWindowOnTop(testApp.component)
+ }
+ }
@Presubmit
@Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+ fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
@Presubmit
@Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+ fun statusBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
@Presubmit
@Test
- fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
+ fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation)
@Presubmit
@Test
@@ -146,7 +151,11 @@ class CloseImeWindowToAppTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- fun imeAppLayerIsAlwaysVisible() = testSpec.imeAppLayerIsAlwaysVisible(testApp)
+ fun imeAppLayerIsAlwaysVisible() {
+ testSpec.assertLayers {
+ this.isVisible(testApp.component)
+ }
+ }
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index 703e4a125440..05fc2672168e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -30,13 +30,13 @@ 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.ImeAppHelper
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.navBarWindowIsVisible
+import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -68,7 +68,7 @@ class CloseImeWindowToHomeTest(private val testSpec: FlickerTestParameter) {
transitions {
device.pressHome()
wmHelper.waitForHomeActivityVisible()
- wmHelper.waitImeWindowGone()
+ wmHelper.waitImeGone()
}
teardown {
eachRun {
@@ -84,19 +84,20 @@ class CloseImeWindowToHomeTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
@Presubmit
@Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
@Presubmit
@Test
fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
testSpec.assertWm {
- this.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE,
- WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME))
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(
+ WindowManagerStateHelper.IME_COMPONENT,
+ WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT,
+ WindowManagerStateHelper.SNAPSHOT_COMPONENT))
}
}
@@ -106,19 +107,25 @@ class CloseImeWindowToHomeTest(private val testSpec: FlickerTestParameter) {
@FlakyTest
@Test
- fun imeAppWindowBecomesInvisible() = testSpec.imeAppWindowBecomesInvisible(testApp)
+ fun imeAppWindowBecomesInvisible() {
+ testSpec.assertWm {
+ this.isAppWindowVisible(testApp.component)
+ .then()
+ .isAppWindowInvisible(testApp.component)
+ }
+ }
@Presubmit
@Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+ fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
@Presubmit
@Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+ fun statusBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
@Presubmit
@Test
- fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation,
Surface.ROTATION_0)
@Presubmit
@@ -127,7 +134,13 @@ class CloseImeWindowToHomeTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- fun imeAppLayerBecomesInvisible() = testSpec.imeAppLayerBecomesInvisible(testApp)
+ fun imeAppLayerBecomesInvisible() {
+ testSpec.assertLayers {
+ this.isVisible(testApp.component)
+ .then()
+ .isInvisible(testApp.component)
+ }
+ }
@Presubmit
@Test
@@ -144,8 +157,9 @@ class CloseImeWindowToHomeTest(private val testSpec: FlickerTestParameter) {
@Test
fun visibleLayersShownMoreThanOneConsecutiveEntry() {
testSpec.assertLayers {
- this.visibleLayersShownMoreThanOneConsecutiveEntry(
- listOf(IME_WINDOW_TITLE, WindowManagerStateHelper.SPLASH_SCREEN_NAME))
+ this.visibleLayersShownMoreThanOneConsecutiveEntry(listOf(
+ WindowManagerStateHelper.IME_COMPONENT,
+ WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT))
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
index 7e34469b8188..7659d9471e2f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
@@ -14,128 +14,56 @@
* limitations under the License.
*/
+@file:JvmName("CommonAssertions")
package com.android.server.wm.flicker.ime
-import android.platform.helpers.IAppHelper
import com.android.server.wm.flicker.FlickerTestParameter
-
-const val IME_WINDOW_TITLE = "InputMethod"
-
-fun FlickerTestParameter.imeLayerIsAlwaysVisible(rotatesScreen: Boolean = false) {
- if (rotatesScreen) {
- assertLayers {
- this.isVisible(IME_WINDOW_TITLE)
- .then()
- .isInvisible(IME_WINDOW_TITLE)
- .then()
- .isVisible(IME_WINDOW_TITLE)
- }
- } else {
- assertLayers {
- this.isVisible(IME_WINDOW_TITLE)
- }
- }
-}
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
fun FlickerTestParameter.imeLayerBecomesVisible() {
assertLayers {
- this.isInvisible(IME_WINDOW_TITLE)
+ this.isInvisible(WindowManagerStateHelper.IME_COMPONENT)
.then()
- .isVisible(IME_WINDOW_TITLE)
+ .isVisible(WindowManagerStateHelper.IME_COMPONENT)
}
}
fun FlickerTestParameter.imeLayerBecomesInvisible() {
assertLayers {
- this.isVisible(IME_WINDOW_TITLE)
+ this.isVisible(WindowManagerStateHelper.IME_COMPONENT)
.then()
- .isInvisible(IME_WINDOW_TITLE)
- }
-}
-
-fun FlickerTestParameter.imeAppLayerIsAlwaysVisible(testApp: IAppHelper) {
- assertLayers {
- this.isVisible(testApp.getPackage())
- }
-}
-
-fun FlickerTestParameter.imeAppWindowIsAlwaysVisible(testApp: IAppHelper) {
- assertWm {
- this.showsAppWindowOnTop(testApp.getPackage())
+ .isInvisible(WindowManagerStateHelper.IME_COMPONENT)
}
}
fun FlickerTestParameter.imeWindowIsAlwaysVisible(rotatesScreen: Boolean = false) {
if (rotatesScreen) {
assertWm {
- this.showsNonAppWindow(IME_WINDOW_TITLE)
+ this.isNonAppWindowVisible(WindowManagerStateHelper.IME_COMPONENT)
.then()
- .hidesNonAppWindow(IME_WINDOW_TITLE)
+ .isNonAppWindowInvisible(WindowManagerStateHelper.IME_COMPONENT)
.then()
- .showsNonAppWindow(IME_WINDOW_TITLE)
+ .isNonAppWindowVisible(WindowManagerStateHelper.IME_COMPONENT)
}
} else {
assertWm {
- this.showsNonAppWindow(IME_WINDOW_TITLE)
+ this.isNonAppWindowVisible(WindowManagerStateHelper.IME_COMPONENT)
}
}
}
fun FlickerTestParameter.imeWindowBecomesVisible() {
assertWm {
- this.hidesNonAppWindow(IME_WINDOW_TITLE)
+ this.isNonAppWindowInvisible(WindowManagerStateHelper.IME_COMPONENT)
.then()
- .showsNonAppWindow(IME_WINDOW_TITLE)
+ .isNonAppWindowVisible(WindowManagerStateHelper.IME_COMPONENT)
}
}
fun FlickerTestParameter.imeWindowBecomesInvisible() {
assertWm {
- this.showsNonAppWindow(IME_WINDOW_TITLE)
+ this.isNonAppWindowVisible(WindowManagerStateHelper.IME_COMPONENT)
.then()
- .hidesNonAppWindow(IME_WINDOW_TITLE)
+ .isNonAppWindowInvisible(WindowManagerStateHelper.IME_COMPONENT)
}
}
-
-fun FlickerTestParameter.imeAppWindowIsAlwaysVisible(
- testApp: IAppHelper,
- rotatesScreen: Boolean = false
-) {
- if (rotatesScreen) {
- assertWm {
- this.showsAppWindow(testApp.getPackage())
- .then()
- .hidesAppWindow(testApp.getPackage())
- .then()
- .showsAppWindow(testApp.getPackage())
- }
- } else {
- assertWm {
- this.showsAppWindow(testApp.getPackage())
- }
- }
-}
-
-fun FlickerTestParameter.imeAppWindowBecomesVisible(windowName: String) {
- assertWm {
- this.hidesAppWindow(windowName)
- .then()
- .showsAppWindow(windowName)
- }
-}
-
-fun FlickerTestParameter.imeAppWindowBecomesInvisible(testApp: IAppHelper) {
- assertWm {
- this.showsAppWindowOnTop(testApp.getPackage())
- .then()
- .appWindowNotOnTop(testApp.getPackage())
- }
-}
-
-fun FlickerTestParameter.imeAppLayerBecomesInvisible(testApp: IAppHelper) {
- assertLayers {
- this.isVisible(testApp.getPackage())
- .then()
- .isInvisible(testApp.getPackage())
- }
-} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index cae1b16c1c8c..f35a180e1ad6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -28,16 +28,15 @@ 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.helpers.ImeAppHelper
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
-import com.android.server.wm.flicker.appWindowAlwaysVisibleOnTop
+import com.android.server.wm.flicker.navBarWindowIsVisible
+import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -81,11 +80,11 @@ class OpenImeWindowTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
@Presubmit
@Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
@Presubmit
@Test
@@ -93,19 +92,23 @@ class OpenImeWindowTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- fun appWindowAlwaysVisibleOnTop() = testSpec.appWindowAlwaysVisibleOnTop(testApp.`package`)
+ fun appWindowAlwaysVisibleOnTop() {
+ testSpec.assertWm {
+ this.isAppWindowOnTop(testApp.component)
+ }
+ }
@Presubmit
@Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+ fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
@Presubmit
@Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+ fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
@Presubmit
@Test
- fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation)
+ fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation)
@Presubmit
@Test
@@ -115,7 +118,7 @@ class OpenImeWindowTest(private val testSpec: FlickerTestParameter) {
@Test
fun layerAlwaysVisible() {
testSpec.assertLayers {
- this.isVisible(testApp.`package`)
+ this.isVisible(testApp.component)
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index b7673d5b0107..3bcf793e9071 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -17,6 +17,7 @@
package com.android.server.wm.flicker.ime
import android.app.Instrumentation
+import android.content.ComponentName
import android.platform.test.annotations.Presubmit
import android.view.Surface
import android.view.WindowManagerPolicyConstants
@@ -26,23 +27,22 @@ 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.LAUNCHER_COMPONENT
import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.launcherWindowBecomesInvisible
-import com.android.server.wm.flicker.appLayerReplacesLauncher
+import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.endRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.flicker.statusBarWindowIsVisible
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -61,7 +61,6 @@ import org.junit.runners.Parameterized
class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
- private val testAppComponentName = ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
@@ -73,14 +72,14 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
}
eachRun {
device.pressRecentApps()
- wmHelper.waitImeWindowGone()
+ wmHelper.waitImeGone()
wmHelper.waitForAppTransitionIdle()
this.setRotation(testSpec.config.startRotation)
}
}
transitions {
device.reopenAppFromOverview(wmHelper)
- wmHelper.waitImeWindowShown()
+ wmHelper.waitImeShown()
}
teardown {
test {
@@ -92,23 +91,34 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
@Presubmit
@Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
@Presubmit
@Test
fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ val component = ComponentName("", "RecentTaskScreenshotSurface")
testSpec.assertWm {
- this.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry(
+ ignoreWindows = listOf(WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT,
+ WindowManagerStateHelper.SNAPSHOT_COMPONENT,
+ component)
+ )
}
}
@Presubmit
@Test
- fun launcherWindowBecomesInvisible() = testSpec.launcherWindowBecomesInvisible()
+ fun launcherWindowBecomesInvisible() {
+ testSpec.assertWm {
+ this.isAppWindowVisible(LAUNCHER_COMPONENT)
+ .then()
+ .isAppWindowInvisible(LAUNCHER_COMPONENT)
+ }
+ }
@Presubmit
@Test
@@ -116,30 +126,57 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(testApp, true)
+ fun imeAppWindowVisibility() {
+ // the app starts visible in live tile, then becomes invisible during animation and
+ // is again launched. Since we log 1x per frame, sometimes the activity visibility and
+ // the app visibility are updated together, sometimes not, thus ignore activity check
+ // at the start
+ testSpec.assertWm {
+ this.isAppWindowVisible(testApp.component, ignoreActivity = true)
+ .then()
+ .isAppWindowInvisible(testApp.component, ignoreActivity = true)
+ .then()
+ .isAppWindowVisible(testApp.component)
+ }
+ }
@Presubmit
@Test
// During testing the launcher is always in portrait mode
- fun noUncoveredRegions() = testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation,
testSpec.config.endRotation)
@Presubmit
@Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+ fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
@Presubmit
@Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+ fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
@Presubmit
@Test
- fun imeLayerIsAlwaysVisible() = testSpec.imeLayerIsAlwaysVisible(true)
+ fun imeLayerIsBecomesVisible() {
+ testSpec.assertLayers {
+ this.isVisible(WindowManagerStateHelper.IME_COMPONENT)
+ .then()
+ .isInvisible(WindowManagerStateHelper.IME_COMPONENT)
+ .then()
+ .isVisible(WindowManagerStateHelper.IME_COMPONENT)
+ }
+ }
@Presubmit
@Test
- fun appLayerReplacesLauncher() =
- testSpec.appLayerReplacesLauncher(testAppComponentName.className)
+ fun appLayerReplacesLauncher() {
+ testSpec.assertLayers {
+ this.isVisible(LAUNCHER_COMPONENT)
+ .then()
+ .isVisible(WindowManagerStateHelper.SNAPSHOT_COMPONENT, isOptional = true)
+ .then()
+ .isVisible(testApp.component)
+ }
+ }
@Presubmit
@Test
@@ -156,8 +193,14 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
@Presubmit
@Test
fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ // depends on how much of the animation transactions are sent to SF at once
+ // sometimes this layer appears for 2-3 frames, sometimes for only 1
+ val recentTaskComponent = ComponentName("", "RecentTaskScreenshotSurface")
testSpec.assertLayers {
- this.visibleLayersShownMoreThanOneConsecutiveEntry()
+ this.visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT,
+ WindowManagerStateHelper.SNAPSHOT_COMPONENT, recentTaskComponent)
+ )
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
index 0cae37c8d5ab..f9dd88e8cb29 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
@@ -17,27 +17,26 @@
package com.android.server.wm.flicker.ime
import android.app.Instrumentation
+import android.content.ComponentName
import android.platform.test.annotations.Presubmit
+import android.view.Surface
import android.view.WindowManagerPolicyConstants
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
-
import com.android.server.wm.flicker.dsl.FlickerBuilder
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.helpers.ImeAppHelper
+import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -54,10 +53,11 @@ import org.junit.runners.Parameterized
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group2
+@Presubmit
class SwitchImeWindowsFromGestureNavTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = SimpleAppHelper(instrumentation)
- private val imeTestApp = ImeAppHelper(instrumentation)
+ private val imeTestApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
@@ -66,7 +66,13 @@ class SwitchImeWindowsFromGestureNavTest(private val testSpec: FlickerTestParame
eachRun {
this.setRotation(testSpec.config.startRotation)
testApp.launchViaIntent(wmHelper)
+ wmHelper.waitForFullScreenApp(testApp.component)
+ wmHelper.waitForAppTransitionIdle()
+
imeTestApp.launchViaIntent(wmHelper)
+ wmHelper.waitForFullScreenApp(testApp.component)
+ wmHelper.waitForAppTransitionIdle()
+
imeTestApp.openIME(device, wmHelper)
}
}
@@ -74,57 +80,86 @@ class SwitchImeWindowsFromGestureNavTest(private val testSpec: FlickerTestParame
eachRun {
device.pressHome()
wmHelper.waitForHomeActivityVisible()
- }
- test {
- imeTestApp.exit(wmHelper)
+ testApp.exit()
+ imeTestApp.exit()
}
}
transitions {
// [Step1]: Swipe right from imeTestApp to testApp task
+ createTag(TAG_IME_VISIBLE)
val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
- val displayCenterX = displayBounds.bounds.width() / 2
- device.swipe(displayCenterX, displayBounds.bounds.height(),
- displayBounds.bounds.width(), displayBounds.bounds.height(), 20)
+ device.swipe(0, displayBounds.bounds.height(),
+ displayBounds.bounds.width(), displayBounds.bounds.height(), 50)
+
wmHelper.waitForFullScreenApp(testApp.component)
+ wmHelper.waitForAppTransitionIdle()
+ createTag(TAG_IME_INVISIBLE)
}
transitions {
// [Step2]: Swipe left to back to imeTestApp task
val displayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
- val displayCenterX = displayBounds.bounds.width() / 2
device.swipe(displayBounds.bounds.width(), displayBounds.bounds.height(),
- displayCenterX, displayBounds.bounds.height(), 20)
+ 0, displayBounds.bounds.height(), 50)
wmHelper.waitForFullScreenApp(imeTestApp.component)
}
}
}
- @FlakyTest
@Test
- fun imeAppWindowIsAlwaysVisible() = testSpec.imeAppWindowIsAlwaysVisible(imeTestApp)
+ fun imeAppWindowVisibility() {
+ val component = ComponentName(imeTestApp.`package`, "")
+ testSpec.assertWm {
+ this.isAppWindowOnTop(component)
+ .then()
+ .isAppWindowVisible(component, ignoreActivity = true)
+ }
+ }
- @FlakyTest
@Test
- fun imeLayerBecomesVisible() = testSpec.imeLayerBecomesVisible()
+ fun navBarLayerIsVisibleAroundSwitching() {
+ testSpec.assertLayersStart {
+ isVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
+ }
+ testSpec.assertLayersEnd {
+ isVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
+ }
+ }
- @FlakyTest
@Test
- fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+ fun statusBarLayerIsVisibleAroundSwitching() {
+ testSpec.assertLayersStart {
+ isVisible(WindowManagerStateHelper.STATUS_BAR_COMPONENT)
+ }
+ testSpec.assertLayersEnd {
+ isVisible(WindowManagerStateHelper.STATUS_BAR_COMPONENT)
+ }
+ }
- @Presubmit
@Test
- fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
+ fun imeLayerIsVisibleWhenSwitchingToImeApp() {
+ testSpec.assertLayersStart {
+ isVisible(WindowManagerStateHelper.IME_COMPONENT)
+ }
+ testSpec.assertLayersTag(TAG_IME_VISIBLE) {
+ isVisible(WindowManagerStateHelper.IME_COMPONENT)
+ }
+ testSpec.assertLayersEnd {
+ isVisible(WindowManagerStateHelper.IME_COMPONENT)
+ }
+ }
- @FlakyTest
@Test
- fun navBarLayerIsAlwaysVisible() = testSpec.navBarLayerIsAlwaysVisible()
+ fun imeLayerIsInvisibleWhenSwitchingToTestApp() {
+ testSpec.assertLayersTag(TAG_IME_INVISIBLE) {
+ isInvisible(WindowManagerStateHelper.IME_COMPONENT)
+ }
+ }
- @Presubmit
@Test
- fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+ fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
- @FlakyTest
@Test
- fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
+ fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
companion object {
@Parameterized.Parameters(name = "{0}")
@@ -134,10 +169,13 @@ class SwitchImeWindowsFromGestureNavTest(private val testSpec: FlickerTestParame
.getConfigNonRotationTests(
repetitions = 3,
supportedNavigationModes = listOf(
- WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
- )
+ ),
+ supportedRotations = listOf(Surface.ROTATION_0)
)
}
+
+ private const val TAG_IME_VISIBLE = "imeVisible"
+ private const val TAG_IME_INVISIBLE = "imeInVisible"
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 9ff0bdfe66ba..e6dc8523acbf 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -64,35 +64,17 @@ class OpenAppColdTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSp
@FlakyTest
@Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
- }
-
- @FlakyTest
- @Test
- override fun navBarLayerIsAlwaysVisible() {
- super.navBarLayerIsAlwaysVisible()
- }
-
- @FlakyTest
- @Test
override fun navBarLayerRotatesAndScales() {
super.navBarLayerRotatesAndScales()
}
- @FlakyTest
- @Test
- override fun statusBarLayerIsAlwaysVisible() {
- super.statusBarLayerIsAlwaysVisible()
- }
-
- @FlakyTest
+ @FlakyTest(bugId = 192721431)
@Test
override fun appLayerReplacesLauncher() {
super.appLayerReplacesLauncher()
}
- @FlakyTest
+ @FlakyTest(bugId = 192721431)
@Test
override fun appWindowReplacesLauncherAsTopWindow() {
super.appWindowReplacesLauncherAsTopWindow()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index b073a7ca1495..7833e2f25eec 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -65,34 +65,10 @@ class OpenAppFromOverviewTest(testSpec: FlickerTestParameter) : OpenAppTransitio
@FlakyTest
@Test
- override fun navBarLayerIsAlwaysVisible() {
- super.navBarLayerIsAlwaysVisible()
- }
-
- @FlakyTest
- @Test
- override fun statusBarLayerIsAlwaysVisible() {
- super.statusBarLayerIsAlwaysVisible()
- }
-
- @FlakyTest
- @Test
override fun navBarLayerRotatesAndScales() {
super.navBarLayerRotatesAndScales()
}
- @FlakyTest
- @Test
- override fun statusBarLayerRotatesScales() {
- super.statusBarLayerRotatesScales()
- }
-
- @FlakyTest
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
- }
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
index b304d5f999df..860a5aed13fd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -22,24 +22,24 @@ import android.view.Surface
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.appLayerReplacesLauncher
+import com.android.server.wm.flicker.LAUNCHER_COMPONENT
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
-import com.android.server.wm.flicker.focusChanges
+import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.helpers.StandardAppHelper
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.replacesLayer
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.launcherWindowBecomesInvisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.SNAPSHOT_COMPONENT
import org.junit.Test
abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
@@ -71,14 +71,14 @@ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- open fun navBarWindowIsAlwaysVisible() {
- testSpec.navBarWindowIsAlwaysVisible()
+ open fun navBarWindowIsVisible() {
+ testSpec.navBarWindowIsVisible()
}
@Presubmit
@Test
- open fun navBarLayerIsAlwaysVisible() {
- testSpec.navBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
+ open fun navBarLayerIsVisible() {
+ testSpec.navBarLayerIsVisible()
}
@Presubmit
@@ -89,14 +89,14 @@ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
@Presubmit
@Test
- open fun statusBarWindowIsAlwaysVisible() {
- testSpec.statusBarWindowIsAlwaysVisible()
+ open fun statusBarWindowIsVisible() {
+ testSpec.statusBarWindowIsVisible()
}
@Presubmit
@Test
- open fun statusBarLayerIsAlwaysVisible() {
- testSpec.statusBarLayerIsAlwaysVisible(rotatesScreen = testSpec.isRotated)
+ open fun statusBarLayerIsVisible() {
+ testSpec.statusBarLayerIsVisible()
}
@Presubmit
@@ -124,31 +124,43 @@ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
@Presubmit
@Test
// During testing the launcher is always in portrait mode
- open fun noUncoveredRegions() {
- testSpec.noUncoveredRegions(Surface.ROTATION_0, testSpec.config.endRotation)
+ open fun entireScreenCovered() {
+ testSpec.entireScreenCovered(Surface.ROTATION_0, testSpec.config.endRotation)
}
@Presubmit
@Test
open fun focusChanges() {
- testSpec.focusChanges("NexusLauncherActivity", testApp.`package`)
+ testSpec.assertEventLog {
+ this.focusChanges("NexusLauncherActivity", testApp.`package`)
+ }
}
@Presubmit
@Test
open fun appLayerReplacesLauncher() {
- testSpec.appLayerReplacesLauncher(testApp.`package`)
+ testSpec.replacesLayer(LAUNCHER_COMPONENT, testApp.component)
}
@Presubmit
@Test
open fun appWindowReplacesLauncherAsTopWindow() {
- testSpec.appWindowReplacesLauncherAsTopWindow(testApp)
+ testSpec.assertWm {
+ this.isAppWindowOnTop(LAUNCHER_COMPONENT)
+ .then()
+ .isAppWindowOnTop(SNAPSHOT_COMPONENT, isOptional = true)
+ .then()
+ .isAppWindowOnTop(testApp.component)
+ }
}
@Presubmit
@Test
open fun launcherWindowBecomesInvisible() {
- testSpec.launcherWindowBecomesInvisible()
+ testSpec.assertWm {
+ this.isAppWindowVisible(LAUNCHER_COMPONENT)
+ .then()
+ .isAppWindowInvisible(LAUNCHER_COMPONENT)
+ }
}
} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index e2705c764917..b509c61d2aba 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -67,15 +67,7 @@ class OpenAppWarmTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSp
@FlakyTest
@Test
- override fun navBarLayerIsAlwaysVisible() {
- super.navBarLayerIsAlwaysVisible()
- }
-
- @FlakyTest
- @Test
- override fun navBarLayerRotatesAndScales() {
- super.navBarLayerRotatesAndScales()
- }
+ override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 69e8a8d08e58..73986b6def8f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -25,7 +25,13 @@ import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsVisible
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.ROTATION_COMPONENT
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -61,39 +67,62 @@ class ChangeAppRotationTest(
super.focusDoesNotChange()
}
- @Postsubmit
+ @Presubmit
@Test
fun screenshotLayerBecomesInvisible() {
testSpec.assertLayers {
- this.isVisible(testApp.getPackage())
+ this.isVisible(testApp.component)
.then()
- .isVisible(SCREENSHOT_LAYER)
+ .isVisible(ROTATION_COMPONENT)
.then()
- .isVisible(testApp.getPackage())
+ .isVisible(testApp.component)
}
}
+ @Presubmit
+ @Test
+ fun statusBarWindowIsVisible() {
+ testSpec.statusBarWindowIsVisible()
+ }
+
@Postsubmit
@Test
- override fun statusBarLayerRotatesScales() {
- super.statusBarLayerRotatesScales()
+ fun statusBarLayerIsVisible() {
+ testSpec.statusBarLayerIsVisible()
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerRotatesScales() {
+ testSpec.statusBarLayerRotatesScales(
+ testSpec.config.startRotation, testSpec.config.endRotation)
}
@Presubmit
@Test
- override fun navBarWindowIsAlwaysVisible() {
- super.navBarWindowIsAlwaysVisible()
+ override fun navBarWindowIsVisible() {
+ super.navBarWindowIsVisible()
+ }
+
+ @Postsubmit
+ @Test
+ override fun navBarLayerIsVisible() {
+ super.navBarLayerIsVisible()
}
@FlakyTest
@Test
- override fun statusBarLayerIsAlwaysVisible() {
- super.statusBarLayerIsAlwaysVisible()
+ override fun navBarLayerRotatesAndScales() {
+ super.navBarLayerRotatesAndScales()
}
- companion object {
- private const val SCREENSHOT_LAYER = "RotationLayer"
+ @Postsubmit
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+ companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
index 4b888cd5aad0..2b0b3c23a0b2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
@@ -17,25 +17,21 @@
package com.android.server.wm.flicker.rotation
import android.app.Instrumentation
+import android.content.ComponentName
import android.platform.test.annotations.Presubmit
-import androidx.test.filters.FlakyTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
-import com.android.server.wm.flicker.focusDoesNotChange
import com.android.server.wm.flicker.helpers.StandardAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
-import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
-import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.navBarWindowIsVisible
+import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.startRotation
-import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
-import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import org.junit.Test
@@ -69,19 +65,19 @@ abstract class RotationTransition(protected val testSpec: FlickerTestParameter)
}
}
- @FlakyTest
+ @Presubmit
@Test
- open fun navBarWindowIsAlwaysVisible() {
- testSpec.navBarWindowIsAlwaysVisible()
+ open fun navBarWindowIsVisible() {
+ testSpec.navBarWindowIsVisible()
}
- @FlakyTest
+ @Presubmit
@Test
- open fun navBarLayerIsAlwaysVisible() {
- testSpec.navBarLayerIsAlwaysVisible(rotatesScreen = true)
+ open fun navBarLayerIsVisible() {
+ testSpec.navBarLayerIsVisible()
}
- @FlakyTest
+ @Presubmit
@Test
open fun navBarLayerRotatesAndScales() {
testSpec.navBarLayerRotatesAndScales(
@@ -90,31 +86,12 @@ abstract class RotationTransition(protected val testSpec: FlickerTestParameter)
@Presubmit
@Test
- open fun statusBarWindowIsAlwaysVisible() {
- testSpec.statusBarWindowIsAlwaysVisible()
- }
-
- @FlakyTest
- @Test
- open fun statusBarLayerIsAlwaysVisible() {
- testSpec.statusBarLayerIsAlwaysVisible(rotatesScreen = true)
- }
-
- @FlakyTest
- @Test
- open fun statusBarLayerRotatesScales() {
- testSpec.statusBarLayerRotatesScales(
- testSpec.config.startRotation, testSpec.config.endRotation)
- }
-
- @FlakyTest
- @Test
open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
testSpec.assertLayers {
this.visibleLayersShownMoreThanOneConsecutiveEntry(
- ignoreLayers = listOf(WindowManagerStateHelper.SPLASH_SCREEN_NAME,
- WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME,
- "SecondaryHomeHandle"
+ ignoreLayers = listOf(WindowManagerStateHelper.SPLASH_SCREEN_COMPONENT,
+ WindowManagerStateHelper.SNAPSHOT_COMPONENT,
+ ComponentName("", "SecondaryHomeHandle")
)
)
}
@@ -130,22 +107,24 @@ abstract class RotationTransition(protected val testSpec: FlickerTestParameter)
@Presubmit
@Test
- open fun noUncoveredRegions() {
- testSpec.noUncoveredRegions(testSpec.config.startRotation,
+ open fun entireScreenCovered() {
+ testSpec.entireScreenCovered(testSpec.config.startRotation,
testSpec.config.endRotation, allStates = false)
}
@Presubmit
@Test
open fun focusDoesNotChange() {
- testSpec.focusDoesNotChange()
+ testSpec.assertEventLog {
+ this.focusDoesNotChange()
+ }
}
@Presubmit
@Test
open fun appLayerRotates_StartingPos() {
testSpec.assertLayersStart {
- this.visibleRegion(testApp.getPackage()).coversExactly(startingPos)
+ this.visibleRegion(testApp.component).coversExactly(startingPos)
}
}
@@ -153,7 +132,7 @@ abstract class RotationTransition(protected val testSpec: FlickerTestParameter)
@Test
open fun appLayerRotates_EndingPos() {
testSpec.assertLayersEnd {
- this.visibleRegion(testApp.getPackage()).coversExactly(endingPos)
+ this.visibleRegion(testApp.component).coversExactly(endingPos)
}
}
} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index b153bece1133..b97b97768362 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -18,6 +18,7 @@ package com.android.server.wm.flicker.rotation
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
+import android.view.WindowManager
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -27,6 +28,7 @@ import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -60,42 +62,91 @@ class SeamlessAppRotationTest(
}
}
- @FlakyTest(bugId = 140855415)
+ @Presubmit
@Test
- override fun statusBarWindowIsAlwaysVisible() {
- super.statusBarWindowIsAlwaysVisible()
+ fun appWindowFullScreen() {
+ testSpec.assertWm {
+ this.invoke("isFullScreen") {
+ val appWindow = it.windowState(testApp.`package`)
+ val flags = appWindow.windowState?.attributes?.flags ?: 0
+ appWindow.verify("isFullScreen")
+ .that(flags.and(WindowManager.LayoutParams.FLAG_FULLSCREEN))
+ .isGreaterThan(0)
+ }
+ }
}
- @FlakyTest(bugId = 140855415)
+ @Presubmit
@Test
- override fun statusBarLayerIsAlwaysVisible() {
- super.statusBarLayerIsAlwaysVisible()
+ fun appWindowSeamlessRotation() {
+ testSpec.assertWm {
+ this.invoke("isRotationSeamless") {
+ val appWindow = it.windowState(testApp.`package`)
+ val rotationAnimation = appWindow.windowState?.attributes?.rotationAnimation ?: 0
+ appWindow.verify("isRotationSeamless")
+ .that(rotationAnimation
+ .and(WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS))
+ .isGreaterThan(0)
+ }
+ }
}
@Presubmit
@Test
fun appLayerAlwaysVisible() {
testSpec.assertLayers {
- isVisible(testApp.`package`)
+ isVisible(testApp.component)
}
}
- @FlakyTest(bugId = 185400889)
+ @Postsubmit
@Test
fun appLayerRotates() {
testSpec.assertLayers {
- this.coversExactly(startingPos, testApp.`package`)
+ this.coversExactly(startingPos, testApp.component)
.then()
- .coversExactly(endingPos, testApp.`package`)
+ .coversExactly(endingPos, testApp.component)
}
}
- @Postsubmit
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysInvisible() {
+ testSpec.assertWm {
+ this.isAboveAppWindowInvisible(WindowManagerStateHelper.STATUS_BAR_COMPONENT)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysInvisible() {
+ testSpec.assertLayers {
+ this.isInvisible(WindowManagerStateHelper.STATUS_BAR_COMPONENT)
+ }
+ }
+
+ @Presubmit
@Test
override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
super.visibleLayersShownMoreThanOneConsecutiveEntry()
}
+ @Postsubmit
+ @Test
+ override fun navBarWindowIsVisible() {
+ super.navBarWindowIsVisible()
+ }
+
+ @Postsubmit
+ @Test
+ override fun navBarLayerIsVisible() {
+ super.navBarLayerIsVisible()
+ }
+
+ @FlakyTest
+ @Test
+ override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
companion object {
private val testFactory = FlickerTestParameterFactory.getInstance()
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml
index 4708cfd48381..c55e7c2720db 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml
@@ -23,5 +23,6 @@
<EditText android:id="@+id/plain_text_input"
android:layout_height="wrap_content"
android:layout_width="match_parent"
+ android:imeOptions="flagNoExtractUi"
android:inputType="text"/>
</LinearLayout>
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index 96f6512fe7f5..cbcbf05c860c 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -27,7 +27,7 @@ namespace aapt {
static ApiVersion sDevelopmentSdkLevel = 10000;
static const auto sDevelopmentSdkCodeNames = std::unordered_set<StringPiece>({
- "Q", "R", "S"
+ "Q", "R", "S", "Sv2"
});
static const std::vector<std::pair<uint16_t, ApiVersion>> sAttrIdMap = {