summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/autofill/AndroidManifest.xml10
-rw-r--r--apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java7
-rw-r--r--core/api/current.txt11
-rw-r--r--core/api/test-current.txt5
-rw-r--r--core/java/android/app/ActivityManager.java51
-rw-r--r--core/java/android/app/ActivityManagerInternal.java8
-rw-r--r--core/java/android/app/ContextImpl.java2
-rw-r--r--core/java/android/app/IActivityManager.aidl1
-rw-r--r--core/java/android/app/LoadedApk.java34
-rw-r--r--core/java/android/app/TaskInfo.java3
-rw-r--r--core/java/android/app/WallpaperManager.java21
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java71
-rw-r--r--core/java/android/app/admin/DevicePolicyManagerInternal.java8
-rw-r--r--core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS4
-rw-r--r--core/java/android/app/admin/EnterprisePlatform_OWNERS2
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl2
-rw-r--r--core/java/android/app/admin/OWNERS10
-rw-r--r--core/java/android/app/admin/WorkDeviceExperience_OWNERS5
-rw-r--r--core/java/android/appwidget/AppWidgetHostView.java27
-rw-r--r--core/java/android/companion/CompanionDeviceManager.java3
-rw-r--r--core/java/android/companion/ICompanionDeviceDiscoveryService.aidl2
-rw-r--r--core/java/android/content/pm/ActivityInfo.java77
-rw-r--r--core/java/android/content/pm/PackageManager.java10
-rw-r--r--core/java/android/hardware/biometrics/BiometricOverlayConstants.java5
-rw-r--r--core/java/android/hardware/biometrics/BiometricPrompt.java13
-rw-r--r--core/java/android/hardware/biometrics/PromptInfo.java11
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java11
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl3
-rw-r--r--core/java/android/net/NetworkTemplate.java33
-rwxr-xr-xcore/java/android/os/Build.java11
-rw-r--r--core/java/android/provider/Telephony.java9
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java3
-rw-r--r--core/java/android/util/FeatureFlagUtils.java2
-rw-r--r--core/java/android/view/IRecentsAnimationRunner.aidl16
-rw-r--r--core/java/android/view/IWindowManager.aidl14
-rw-r--r--core/java/android/view/ImeInsetsSourceConsumer.java2
-rw-r--r--core/java/android/view/InsetsAnimationControlImpl.java2
-rw-r--r--core/java/android/view/SurfaceView.java29
-rw-r--r--core/java/android/view/TaskTransitionSpec.aidl (renamed from packages/SystemUI/res/interpolator/wireless_charging_animation_interpolator_0.xml)13
-rw-r--r--core/java/android/view/TaskTransitionSpec.java92
-rw-r--r--core/java/android/view/View.java4
-rw-r--r--core/java/android/view/ViewRootImpl.java98
-rw-r--r--core/java/android/view/WindowManager.java19
-rw-r--r--core/java/android/view/translation/UiTranslationController.java10
-rw-r--r--core/java/android/widget/RemoteViews.java51
-rw-r--r--core/java/android/widget/RemoteViewsAdapter.java2
-rw-r--r--core/java/android/window/RemoteTransition.java46
-rw-r--r--core/java/android/window/SplashScreen.java3
-rw-r--r--core/java/android/window/SplashScreenView.java28
-rw-r--r--core/java/android/window/TaskFragmentInfo.java1
-rw-r--r--core/java/com/android/internal/jank/FrameTracker.java240
-rw-r--r--core/java/com/android/internal/jank/InteractionJankMonitor.java111
-rw-r--r--core/jni/android_graphics_BLASTBufferQueue.cpp6
-rw-r--r--core/proto/android/server/windowmanagerservice.proto3
-rw-r--r--core/res/OWNERS6
-rw-r--r--core/res/res/layout/alert_dialog.xml6
-rw-r--r--core/res/res/values-as/strings.xml46
-rw-r--r--core/res/res/values-ko/strings.xml2
-rw-r--r--core/res/res/values-my/strings.xml18
-rw-r--r--core/res/res/values-pa/strings.xml4
-rw-r--r--core/res/res/values-vi/strings.xml2
-rw-r--r--core/res/res/values-zh-rTW/strings.xml2
-rw-r--r--core/res/res/values/attrs.xml11
-rw-r--r--core/res/res/values/config.xml5
-rw-r--r--core/res/res/values/dimens_car.xml2
-rw-r--r--core/res/res/values/public.xml85
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java97
-rw-r--r--data/etc/car/com.android.car.shell.xml1
-rw-r--r--data/etc/car/com.google.android.car.kitchensink.xml1
-rw-r--r--data/etc/services.core.protolog.json12
-rw-r--r--graphics/java/android/graphics/BLASTBufferQueue.java5
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/common/CommonDisplayFeature.java35
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/common/DisplayFeature.java24
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java51
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java77
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java49
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java15
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java24
-rw-r--r--libs/WindowManager/Jetpack/window-extensions-release.aarbin18249 -> 19183 bytes
-rw-r--r--libs/WindowManager/Shell/Android.bp5
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_split.xml (renamed from packages/SystemUI/res/drawable/ic_exit_to_app.xml)14
-rw-r--r--libs/WindowManager/Shell/res/drawable/size_compat_hint_bubble.xml (renamed from packages/SystemUI/res/drawable/screenshot_rounded_corners.xml)9
-rw-r--r--libs/WindowManager/Shell/res/drawable/size_compat_hint_point.xml (renamed from packages/SystemUI/res/color/prv_color_surface.xml)13
-rw-r--r--libs/WindowManager/Shell/res/drawable/size_compat_restart_button.xml25
-rw-r--r--libs/WindowManager/Shell/res/layout/bubble_overflow_view.xml2
-rw-r--r--libs/WindowManager/Shell/res/layout/pip_menu.xml26
-rw-r--r--libs/WindowManager/Shell/res/layout/size_compat_mode_hint.xml35
-rw-r--r--libs/WindowManager/Shell/res/layout/size_compat_ui.xml23
-rw-r--r--libs/WindowManager/Shell/res/layout/split_decor.xml (renamed from packages/SystemUI/res/drawable/screenrecord_switch_track.xml)22
-rw-r--r--libs/WindowManager/Shell/res/layout/split_outline.xml29
-rw-r--r--libs/WindowManager/Shell/res/values-land/styles.xml2
-rw-r--r--libs/WindowManager/Shell/res/values/colors.xml1
-rw-r--r--libs/WindowManager/Shell/res/values/config.xml4
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml19
-rw-r--r--libs/WindowManager/Shell/res/values/strings.xml6
-rw-r--r--libs/WindowManager/Shell/res/values/styles.xml2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java21
-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.java29
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/SingleInstanceRemoteListener.java123
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/SurfaceUtils.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ExternalMainThread.java34
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java31
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java184
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java73
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java25
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/README.txt13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java (renamed from packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java)11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java (renamed from packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java)6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java (renamed from packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java)66
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java (renamed from packages/SystemUI/src/com/android/systemui/wmshell/WMShellConcurrencyModule.java)33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java (renamed from packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java)12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMSingleton.java (renamed from packages/SystemUI/src/com/android/systemui/dagger/WMSingleton.java)4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropEventLogger.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenUnfoldController.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.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/pip/PipTaskOrganizer.java71
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java23
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java105
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java45
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java24
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasks.aidl41
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl28
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasks.java32
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java315
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopup.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButton.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java74
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java50
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineManager.java181
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineView.java82
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java87
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java175
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java55
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java243
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java68
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java52
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.aidl (renamed from packages/SystemUI/res/values/arrays_tv.xml)17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java96
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/util/StagedSplitBounds.java114
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt8
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/fullscreen/FullscreenTaskListenerTest.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java9
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java232
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/StagedSplitBoundsTest.java94
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java51
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java34
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java11
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java14
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java22
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java10
-rw-r--r--libs/hwui/pipeline/skia/FunctorDrawable.h4
-rw-r--r--libs/hwui/pipeline/skia/TransformCanvas.cpp14
-rw-r--r--media/java/android/media/MediaFormat.java2
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java12
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java19
-rw-r--r--packages/PackageInstaller/res/values-as/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-as/strings.xml8
-rw-r--r--packages/SettingsLib/ActivityEmbedding/Android.bp21
-rw-r--r--packages/SettingsLib/ActivityEmbedding/AndroidManifest.xml (renamed from packages/SystemUI/res/drawable/settingslib_switch_bar_bg_disabled.xml)17
-rw-r--r--packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java51
-rw-r--r--packages/SettingsLib/Android.bp1
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ms/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/SignalIcon.java199
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java11
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java14
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java8
-rw-r--r--packages/SystemUI/Android.bp12
-rw-r--r--packages/SystemUI/AndroidManifest.xml19
-rw-r--r--packages/SystemUI/TEST_MAPPING13
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt460
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt30
-rw-r--r--packages/SystemUI/docs/plugins.md1
-rw-r--r--packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt3
-rw-r--r--packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java10
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/flags/Flag.kt52
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java5
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java6
-rw-r--r--packages/SystemUI/res-keyguard/drawable/bubble_manage_user_education_bg.xml21
-rw-r--r--packages/SystemUI/res-keyguard/drawable/circle_white.xml19
-rw-r--r--packages/SystemUI/res-keyguard/drawable/face_auth_wallpaper.pngbin709067 -> 0 bytes
-rw-r--r--packages/SystemUI/res-keyguard/drawable/ic_done_black_24dp.xml25
-rw-r--r--packages/SystemUI/res-keyguard/drawable/ripple_drawable_pin.xml20
-rw-r--r--packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-land/integers.xml23
-rw-r--r--packages/SystemUI/res-keyguard/values-port/bools.xml19
-rw-r--r--packages/SystemUI/res-keyguard/values-port/integers.xml23
-rw-r--r--packages/SystemUI/res-keyguard/values-sw600dp-land/dimens.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-sw600dp/bools.xml19
-rw-r--r--packages/SystemUI/res-keyguard/values/alias.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values/colors.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values/dimens.xml5
-rw-r--r--packages/SystemUI/res-keyguard/values/donottranslate.xml1
-rw-r--r--packages/SystemUI/res-keyguard/values/strings.xml84
-rw-r--r--packages/SystemUI/res-keyguard/values/styles.xml13
-rw-r--r--packages/SystemUI/res/anim/bottomsheet_in.xml26
-rw-r--r--packages/SystemUI/res/anim/bottomsheet_out.xml25
-rw-r--r--packages/SystemUI/res/anim/tv_pip_controls_focus_gain_animation.xml21
-rw-r--r--packages/SystemUI/res/anim/tv_pip_controls_focus_loss_animation.xml21
-rw-r--r--packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml21
-rw-r--r--packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml21
-rw-r--r--packages/SystemUI/res/color/docked_divider_background.xml18
-rw-r--r--packages/SystemUI/res/color/notification_guts_buttons.xml7
-rw-r--r--packages/SystemUI/res/color/pin_delete_color.xml19
-rw-r--r--packages/SystemUI/res/color/pin_divider_color.xml19
-rw-r--r--packages/SystemUI/res/color/qs_user_detail_name.xml23
-rw-r--r--packages/SystemUI/res/color/screenrecord_switch_thumb_color.xml26
-rw-r--r--packages/SystemUI/res/color/screenrecord_switch_track_color.xml27
-rw-r--r--packages/SystemUI/res/color/settingslib_state_off.xml5
-rw-r--r--packages/SystemUI/res/drawable-hdpi/pip_dismiss_scrim.9.pngbin525 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/screenshot_panel.9.pngbin582 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/search_bg_transparent.9.pngbin625 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mcc310-mnc004/ic_5g_plus_mobiledata.xml36
-rw-r--r--packages/SystemUI/res/drawable-mcc311-mnc480/ic_5g_plus_mobiledata.xml36
-rw-r--r--packages/SystemUI/res/drawable-mdpi/one_handed_tutorial.pngbin1054 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/pip_dismiss_scrim.9.pngbin436 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/screenshot_panel.9.pngbin404 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/search_bg_transparent.9.pngbin431 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-nodpi/android_11_dial.xml63
-rw-r--r--packages/SystemUI/res/drawable-nodpi/work_challenge_background.pngbin210081 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/one_handed_tutorial.pngbin2215 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/pip_dismiss_scrim.9.pngbin611 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/remote.pngbin6957 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/search_bg_transparent.9.pngbin866 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/one_handed_tutorial.pngbin3649 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/pip_dismiss_scrim.9.pngbin633 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/search_bg_transparent.9.pngbin1246 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxxhdpi/one_handed_tutorial.pngbin5029 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxxhdpi/pip_dismiss_scrim.9.pngbin647 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable/circle_blue_40dp.xml22
-rw-r--r--packages/SystemUI/res/drawable/circle_white_40dp.xml22
-rw-r--r--packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml19
-rw-r--r--packages/SystemUI/res/drawable/ic_add_to_home.xml26
-rw-r--r--packages/SystemUI/res/drawable/ic_arrow_downward.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_camera.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_cancel_24.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_chevron_up.xml24
-rw-r--r--packages/SystemUI/res/drawable/ic_clear.xml24
-rw-r--r--packages/SystemUI/res/drawable/ic_demote_conversation.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_drag_handle.xml24
-rw-r--r--packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml24
-rw-r--r--packages/SystemUI/res/drawable/ic_important.xml26
-rw-r--r--packages/SystemUI/res/drawable/ic_kg_fingerprint.xml (renamed from packages/SystemUI/res/drawable/ic_fingerprint.xml)0
-rw-r--r--packages/SystemUI/res/drawable/ic_notification_block.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_notification_gentle.xml40
-rw-r--r--packages/SystemUI/res/drawable/ic_notification_interruptive.xml41
-rw-r--r--packages/SystemUI/res/drawable/ic_pause_white.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_photo_camera.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_play_arrow_white.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_power_settings_new_gm2_24px.xml9
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml24
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_no_internet_airplane.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_screenrecord.xml9
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_wifi_0.xml32
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_wifi_1.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_wifi_2.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_wifi_3.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_wifi_4.xml28
-rw-r--r--packages/SystemUI/res/drawable/ic_settings_16dp.xml27
-rw-r--r--packages/SystemUI/res/drawable/ic_tune_black_16dp.xml26
-rw-r--r--packages/SystemUI/res/drawable/ic_unlock.xml42
-rw-r--r--packages/SystemUI/res/drawable/ic_volume_voice.xml27
-rw-r--r--packages/SystemUI/res/drawable/ic_width.xml28
-rw-r--r--packages/SystemUI/res/drawable/internet_dialog_background.xml23
-rw-r--r--packages/SystemUI/res/drawable/internet_dialog_rounded_top_corner_background.xml22
-rw-r--r--packages/SystemUI/res/drawable/pip_icon.xml25
-rw-r--r--packages/SystemUI/res/drawable/pip_resize_handle.xml29
-rw-r--r--packages/SystemUI/res/drawable/qs_bg_gradient.xml24
-rw-r--r--packages/SystemUI/res/drawable/qs_dual_tile_caret.xml25
-rw-r--r--packages/SystemUI/res/drawable/rounded_bg_bottom_background.xml11
-rw-r--r--packages/SystemUI/res/drawable/rounded_bg_top.xml22
-rw-r--r--packages/SystemUI/res/drawable/screenrecord_switch_thumb.xml29
-rw-r--r--packages/SystemUI/res/drawable/stat_notify_image.xml28
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_camera.xml22
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_location.xml19
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_managed_profile_status.xml2
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_mic_none.xml30
-rw-r--r--packages/SystemUI/res/drawable/tv_ic_mic_white.xml27
-rw-r--r--packages/SystemUI/res/drawable/udfps_enroll_checkmark.xml35
-rw-r--r--packages/SystemUI/res/interpolator/assist_disclosure_trace.xml22
-rw-r--r--packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_0.xml19
-rw-r--r--packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_1.xml19
-rw-r--r--packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_2.xml19
-rw-r--r--packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_3.xml19
-rw-r--r--packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_4.xml19
-rw-r--r--packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_5.xml19
-rw-r--r--packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_6.xml19
-rw-r--r--packages/SystemUI/res/interpolator/ic_caret_down_animation_interpolator_0.xml19
-rw-r--r--packages/SystemUI/res/interpolator/ic_caret_up_animation_interpolator_0.xml19
-rw-r--r--packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_0.xml19
-rw-r--r--packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_1.xml19
-rw-r--r--packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_2.xml19
-rw-r--r--packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_3.xml19
-rw-r--r--packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_4.xml19
-rw-r--r--packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_5.xml19
-rw-r--r--packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_6.xml19
-rw-r--r--packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_0.xml19
-rw-r--r--packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_1.xml19
-rw-r--r--packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_2.xml19
-rw-r--r--packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_3.xml19
-rw-r--r--packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_4.xml19
-rw-r--r--packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_5.xml19
-rw-r--r--packages/SystemUI/res/interpolator/ic_landscape_to_rotate_animation_interpolator_0.xml19
-rw-r--r--packages/SystemUI/res/interpolator/ic_rotate_to_landscape_animation_interpolator_0.xml19
-rw-r--r--packages/SystemUI/res/interpolator/ic_rotate_to_portrait_animation_interpolator_0.xml19
-rw-r--r--packages/SystemUI/res/interpolator/lockscreen_fingerprint_draw_off_animation_interpolator_0.xml19
-rw-r--r--packages/SystemUI/res/interpolator/lockscreen_fingerprint_draw_off_animation_interpolator_1.xml19
-rw-r--r--packages/SystemUI/res/interpolator/lockscreen_fingerprint_draw_on_animation_interpolator_0.xml19
-rw-r--r--packages/SystemUI/res/interpolator/lockscreen_fingerprint_draw_on_animation_interpolator_1.xml19
-rw-r--r--packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_0.xml19
-rw-r--r--packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_1.xml19
-rw-r--r--packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_2.xml19
-rw-r--r--packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_3.xml19
-rw-r--r--packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_4.xml19
-rw-r--r--packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_5.xml19
-rw-r--r--packages/SystemUI/res/interpolator/wireless_charging_animation_interpolator_1.xml21
-rw-r--r--packages/SystemUI/res/layout-land/global_actions_column_seascape.xml68
-rw-r--r--packages/SystemUI/res/layout-land/global_actions_grid_item.xml61
-rw-r--r--packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml79
-rw-r--r--packages/SystemUI/res/layout-sw600dp-land/global_actions_grid_v2.xml68
-rw-r--r--packages/SystemUI/res/layout-sw600dp/global_actions_grid_v2.xml76
-rw-r--r--packages/SystemUI/res/layout/app_ops_info.xml96
-rw-r--r--packages/SystemUI/res/layout/combined_qs_header.xml104
-rw-r--r--packages/SystemUI/res/layout/controls_icon.xml26
-rw-r--r--packages/SystemUI/res/layout/global_actions_grid_item.xml60
-rw-r--r--packages/SystemUI/res/layout/global_actions_grid_v2.xml35
-rw-r--r--packages/SystemUI/res/layout/global_actions_item.xml60
-rw-r--r--packages/SystemUI/res/layout/global_actions_lock_view.xml35
-rw-r--r--packages/SystemUI/res/layout/global_screenshot_static.xml2
-rw-r--r--packages/SystemUI/res/layout/horizontal_divider.xml25
-rw-r--r--packages/SystemUI/res/layout/internet_connectivity_dialog.xml6
-rw-r--r--packages/SystemUI/res/layout/mland.xml103
-rw-r--r--packages/SystemUI/res/layout/mland_scorefield.xml32
-rw-r--r--packages/SystemUI/res/layout/nav_control_widget.xml62
-rw-r--r--packages/SystemUI/res/layout/nav_width_view.xml26
-rw-r--r--packages/SystemUI/res/layout/navigation_bar_app_item.xml30
-rw-r--r--packages/SystemUI/res/layout/ongoing_call_chip.xml1
-rw-r--r--packages/SystemUI/res/layout/people_space_widget.xml27
-rw-r--r--packages/SystemUI/res/layout/people_space_widget_item.xml93
-rw-r--r--packages/SystemUI/res/layout/preference_widget_settings.xml44
-rw-r--r--packages/SystemUI/res/layout/punctuation_layout.xml100
-rw-r--r--packages/SystemUI/res/layout/qs_add_tiles_list.xml32
-rw-r--r--packages/SystemUI/res/layout/qs_page_indicator.xml27
-rw-r--r--packages/SystemUI/res/layout/qs_tile_layout.xml21
-rw-r--r--packages/SystemUI/res/layout/qs_user_dialog_content.xml128
-rw-r--r--packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml2
-rw-r--r--packages/SystemUI/res/layout/recents_onboarding.xml64
-rw-r--r--packages/SystemUI/res/layout/remember_permission_checkbox.xml34
-rw-r--r--packages/SystemUI/res/layout/rotate_suggestion.xml6
-rw-r--r--packages/SystemUI/res/layout/rounded_corners.xml75
-rw-r--r--packages/SystemUI/res/layout/screen_record_dialog.xml3
-rw-r--r--packages/SystemUI/res/layout/shelf_menu_anchor.xml24
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml6
-rw-r--r--packages/SystemUI/res/layout/super_status_bar.xml4
-rw-r--r--packages/SystemUI/res/layout/tuner_activity.xml4
-rw-r--r--packages/SystemUI/res/layout/udfps_surface_view.xml21
-rw-r--r--packages/SystemUI/res/mipmap-hdpi/ic_daydreams.pngbin8822 -> 0 bytes
-rw-r--r--packages/SystemUI/res/mipmap-mdpi/ic_daydreams.pngbin5268 -> 0 bytes
-rw-r--r--packages/SystemUI/res/mipmap-xhdpi/ic_daydreams.pngbin13030 -> 0 bytes
-rw-r--r--packages/SystemUI/res/transition/tv_privacy_chip_collapse.xml20
-rw-r--r--packages/SystemUI/res/transition/tv_privacy_chip_expand.xml20
-rw-r--r--packages/SystemUI/res/values-af/strings.xml2
-rw-r--r--packages/SystemUI/res/values-am/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml6
-rw-r--r--packages/SystemUI/res/values-as/strings.xml28
-rw-r--r--packages/SystemUI/res/values-az/strings.xml2
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml4
-rw-r--r--packages/SystemUI/res/values-be/strings.xml2
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml2
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml2
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml2
-rw-r--r--packages/SystemUI/res/values-da/strings.xml2
-rw-r--r--packages/SystemUI/res/values-de/strings.xml2
-rw-r--r--packages/SystemUI/res/values-el/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml2
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml6
-rw-r--r--packages/SystemUI/res/values-es/strings.xml2
-rw-r--r--packages/SystemUI/res/values-et/strings.xml4
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml4
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml4
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml4
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml2
-rw-r--r--packages/SystemUI/res/values-in/strings.xml2
-rw-r--r--packages/SystemUI/res/values-is/strings.xml2
-rw-r--r--packages/SystemUI/res/values-it/strings.xml8
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml2
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-km/strings.xml2
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml2
-rw-r--r--packages/SystemUI/res/values-land/styles.xml6
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml2
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml2
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml2
-rw-r--r--packages/SystemUI/res/values-my/strings.xml5
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml2
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-or/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml4
-rw-r--r--packages/SystemUI/res/values-si/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml4
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sw360dp/dimens.xml3
-rw-r--r--packages/SystemUI/res/values-sw392dp/dimens.xml8
-rw-r--r--packages/SystemUI/res/values-sw410dp/config.xml24
-rw-r--r--packages/SystemUI/res/values-sw410dp/dimens.xml8
-rw-r--r--packages/SystemUI/res/values-sw600dp-land/config.xml1
-rw-r--r--packages/SystemUI/res/values-sw600dp-land/dimens.xml28
-rw-r--r--packages/SystemUI/res/values-sw600dp/config.xml6
-rw-r--r--packages/SystemUI/res/values-sw600dp/dimens.xml40
-rw-r--r--packages/SystemUI/res/values-sw600dp/styles.xml3
-rw-r--r--packages/SystemUI/res/values-sw720dp/config.xml26
-rw-r--r--packages/SystemUI/res/values-sw720dp/dimens.xml9
-rw-r--r--packages/SystemUI/res/values-sw900dp/dimens.xml1
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml2
-rw-r--r--packages/SystemUI/res/values-te/strings.xml2
-rw-r--r--packages/SystemUI/res/values-th/strings.xml2
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml4
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml2
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml2
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml2
-rw-r--r--packages/SystemUI/res/values/colors.xml76
-rw-r--r--packages/SystemUI/res/values/config.xml82
-rw-r--r--packages/SystemUI/res/values/dimens.xml376
-rw-r--r--packages/SystemUI/res/values/ids.xml6
-rw-r--r--packages/SystemUI/res/values/integers.xml5
-rw-r--r--packages/SystemUI/res/values/internal.xml1
-rw-r--r--packages/SystemUI/res/values/mland_config.xml1
-rw-r--r--packages/SystemUI/res/values/mland_strings.xml20
-rw-r--r--packages/SystemUI/res/values/strings.xml702
-rw-r--r--packages/SystemUI/res/values/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values/styles.xml96
-rw-r--r--packages/SystemUI/res/xml/combined_qs_header_scene.xml50
-rw-r--r--packages/SystemUI/res/xml/media_collapsed.xml4
-rw-r--r--packages/SystemUI/res/xml/qqs_header.xml61
-rw-r--r--packages/SystemUI/res/xml/qs_header.xml62
-rw-r--r--packages/SystemUI/res/xml/split_header.xml57
-rw-r--r--packages/SystemUI/shared/Android.bp29
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt183
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt172
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/flags/FlagReader.kt43
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java (renamed from packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java)23
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl7
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java10
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java16
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java (renamed from packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButton.java)82
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonPositionCalculator.kt (renamed from packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculator.kt)4
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonView.java86
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButton.java59
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java (renamed from packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java)246
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java15
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java8
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java6
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java10
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java107
-rw-r--r--packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java144
-rw-r--r--packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt35
-rw-r--r--packages/SystemUI/src-release/com/android/systemui/flags/FeatureFlagManager.java74
-rw-r--r--packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt22
-rw-r--r--packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java50
-rw-r--r--packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java12
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt113
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java34
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java14
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt48
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt81
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java282
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarSegment.java280
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/Utils.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeLog.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/egg/MLand.java1440
-rw-r--r--packages/SystemUI/src/com/android/systemui/egg/MLandActivity.java90
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FeatureFlagManager.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java175
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java76
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.java (renamed from packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java)28
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt195
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java101
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/QSFragmentDisableLog.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipBuilder.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt48
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSSquishinessController.kt55
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSBrightnessController.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/TileLayout.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/HeightOverrideable.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt66
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java50
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java78
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java (renamed from packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java)20
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSlider.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/DisableFlagsLogger.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java597
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilder.java141
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointController.kt93
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImpl.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/CallbackHandler.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityState.kt104
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/EthernetSignalController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalController.java109
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileState.kt225
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkController.java198
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/SignalCallback.kt187
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/SignalController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiState.kt78
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java96
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt126
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideLocallyDismissedNotifsCoordinator.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinator.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java122
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt126
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinator.kt225
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt105
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinator.kt79
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt38
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt109
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt65
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationPresenterExtensions.java100
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Invalidator.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/InternalNotifUpdater.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtender.kt113
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewListener.kt30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewManager.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifShadeEventSource.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/SectionHeaderController.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java86
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java99
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentLogger.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java59
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java206
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java159
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java82
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt83
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java281
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt179
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt133
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java85
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java138
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt2
-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.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionListener.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelExpansionListener.java)21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt160
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelStateListener.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java67
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java)85
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowModule.kt47
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowView.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java)97
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvWMComponent.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt84
-rw-r--r--packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/unfold/UnfoldProgressProvider.kt (renamed from packages/SystemUI/src/com/android/systemui/unfold/ShellUnfoldProgressProvider.kt)2
-rw-r--r--packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt60
-rw-r--r--packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionWallpaperController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt75
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/ListenerSet.kt47
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt (renamed from packages/SystemUI/src/com/android/systemui/flags/FlagReader.java)30
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/kotlin/nullability.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java58
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt149
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt33
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt157
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java71
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java62
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java148
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsTest.java108
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/AnimatableClockControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt137
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java35
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt57
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSSquishinessControllerTest.kt57
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt64
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java44
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderTest.kt)6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt27
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/DisableFlagsLoggerTest.kt17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java178
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt70
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java174
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/CallbackHandlerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/MobileStateTest.java (renamed from packages/SettingsLib/tests/robotests/src/com/android/settingslib/MobileStateTest.java)14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerEthernetTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java90
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt117
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt145
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt209
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt106
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt230
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentLoggerTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java53
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java40
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt96
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SplitShadeHeaderControllerTest.kt88
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt82
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java145
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java49
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt92
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManagerTest.kt213
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java38
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/ListenerSetTest.kt135
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java21
-rw-r--r--packages/services/CameraExtensionsProxy/AndroidManifest.xml6
-rw-r--r--services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java2
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java11
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java54
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java61
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java102
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java15
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java36
-rw-r--r--services/core/java/com/android/server/am/UserController.java56
-rw-r--r--services/core/java/com/android/server/am/UserState.java7
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java9
-rw-r--r--services/core/java/com/android/server/audio/SpatializerHelper.java119
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java3
-rw-r--r--services/core/java/com/android/server/biometrics/PreAuthInfo.java16
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java6
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStartUserClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java9
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java6
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStartUserClient.java2
-rw-r--r--services/core/java/com/android/server/camera/CameraServiceProxy.java96
-rw-r--r--services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java2
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java36
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java7
-rw-r--r--services/core/java/com/android/server/location/provider/LocationProviderManager.java5
-rw-r--r--services/core/java/com/android/server/media/MediaSession2Record.java6
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java33
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecordImpl.java7
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java17
-rw-r--r--services/core/java/com/android/server/media/MediaSessionStack.java3
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java44
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java17
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerService.java18
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java53
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java6
-rw-r--r--services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java2
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java6
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java14
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java6
-rw-r--r--services/core/java/com/android/server/vibrator/Vibration.java2
-rw-r--r--services/core/java/com/android/server/vibrator/VibrationThread.java83
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java13
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java107
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java71
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java46
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java4
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java4
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java16
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java41
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java2
-rw-r--r--services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java8
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java71
-rw-r--r--services/core/java/com/android/server/wm/PackageConfigPersister.java6
-rw-r--r--services/core/java/com/android/server/wm/PinnedTaskController.java7
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimation.java3
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java125
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java7
-rw-r--r--services/core/java/com/android/server/wm/Session.java2
-rw-r--r--services/core/java/com/android/server/wm/SurfaceAnimator.java4
-rw-r--r--services/core/java/com/android/server/wm/SurfaceFreezer.java56
-rw-r--r--services/core/java/com/android/server/wm/Task.java43
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java45
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java40
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java3
-rw-r--r--services/core/java/com/android/server/wm/Transition.java5
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java43
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java141
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java38
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java249
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java9
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java58
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java183
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt85
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/usage/UserUsageStatsServiceTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java21
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java68
-rw-r--r--services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java58
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java58
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java19
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java97
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java55
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java26
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java30
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java47
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java101
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java24
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TransitionTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java65
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java30
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java32
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java49
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java26
-rw-r--r--services/usage/java/com/android/server/usage/UserUsageStatsService.java10
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java82
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java9
-rw-r--r--telephony/java/android/telephony/TelephonyScanManager.java35
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt16
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt131
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt33
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml6
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java5
-rw-r--r--tools/aapt/SdkConstants.h1
-rw-r--r--tools/aapt2/SdkConstants.cpp1
-rw-r--r--tools/aapt2/SdkConstants.h1
-rw-r--r--tools/aapt2/format/binary/BinaryResourceParser.cpp18
-rw-r--r--tools/aapt2/format/binary/BinaryResourceParser.h4
-rwxr-xr-xtools/finalize_res/finalize_res.py35
996 files changed, 19051 insertions, 15115 deletions
diff --git a/apct-tests/perftests/autofill/AndroidManifest.xml b/apct-tests/perftests/autofill/AndroidManifest.xml
index 57595a213d20..de2a3f2c4bfc 100644
--- a/apct-tests/perftests/autofill/AndroidManifest.xml
+++ b/apct-tests/perftests/autofill/AndroidManifest.xml
@@ -16,6 +16,16 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.perftests.autofill">
+ <uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
+ <uses-permission android:name="android.permission.DEVICE_POWER" />
+ <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <uses-permission android:name="android.permission.MANAGE_USERS" />
+ <uses-permission android:name="android.permission.REAL_GET_TASKS" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+
<application>
<uses-library android:name="android.test.runner" />
<activity android:name="android.perftests.utils.PerfTestActivity"
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
index 98b5938e4026..42fb24f570d2 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
@@ -25,7 +25,6 @@ import static org.hamcrest.core.Is.is;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
-import android.window.TaskSnapshot;
import android.app.IActivityTaskManager;
import android.content.ComponentName;
import android.content.Context;
@@ -41,6 +40,7 @@ import android.util.Pair;
import android.view.IRecentsAnimationController;
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationTarget;
+import android.window.TaskSnapshot;
import androidx.test.filters.LargeTest;
import androidx.test.runner.lifecycle.Stage;
@@ -210,13 +210,14 @@ public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase
}
@Override
- public void onAnimationCanceled(TaskSnapshot taskSnapshot) throws RemoteException {
+ public void onAnimationCanceled(int[] taskIds, TaskSnapshot[] taskSnapshots)
+ throws RemoteException {
Assume.assumeNoException(
new AssertionError("onAnimationCanceled should not be called"));
}
@Override
- public void onTaskAppeared(RemoteAnimationTarget app) throws RemoteException {
+ public void onTasksAppeared(RemoteAnimationTarget[] app) throws RemoteException {
/* no-op */
}
};
diff --git a/core/api/current.txt b/core/api/current.txt
index e015169cf69a..1dd401d04e2b 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1298,7 +1298,7 @@ package android {
field public static final int shortcutLongLabel = 16844074; // 0x101052a
field public static final int shortcutShortLabel = 16844073; // 0x1010529
field public static final int shouldDisableView = 16843246; // 0x10101ee
- field public static final int shouldUseDefaultUnfoldTransition;
+ field public static final int shouldUseDefaultUnfoldTransition = 16844364; // 0x101064c
field public static final int showAsAction = 16843481; // 0x10102d9
field public static final int showDefault = 16843258; // 0x10101fa
field public static final int showDividers = 16843561; // 0x1010329
@@ -2014,9 +2014,9 @@ package android {
public static final class R.id {
ctor public R.id();
field public static final int accessibilityActionContextClick = 16908348; // 0x102003c
- field public static final int accessibilityActionDragCancel;
- field public static final int accessibilityActionDragDrop;
- field public static final int accessibilityActionDragStart;
+ field public static final int accessibilityActionDragCancel = 16908375; // 0x1020057
+ field public static final int accessibilityActionDragDrop = 16908374; // 0x1020056
+ field public static final int accessibilityActionDragStart = 16908373; // 0x1020055
field public static final int accessibilityActionHideTooltip = 16908357; // 0x1020045
field public static final int accessibilityActionImeEnter = 16908372; // 0x1020054
field public static final int accessibilityActionMoveWindow = 16908354; // 0x1020042
@@ -22582,7 +22582,7 @@ package android.media {
field public static final String KEY_MAX_FPS_TO_ENCODER = "max-fps-to-encoder";
field public static final String KEY_MAX_HEIGHT = "max-height";
field public static final String KEY_MAX_INPUT_SIZE = "max-input-size";
- field public static final String KEY_MAX_OUTPUT_CHANNEL_COUNT = "max-output-channel_count";
+ field public static final String KEY_MAX_OUTPUT_CHANNEL_COUNT = "max-output-channel-count";
field public static final String KEY_MAX_PTS_GAP_TO_ENCODER = "max-pts-gap-to-encoder";
field public static final String KEY_MAX_WIDTH = "max-width";
field public static final String KEY_MIME = "mime";
@@ -30857,6 +30857,7 @@ package android.os {
field public static final int Q = 29; // 0x1d
field public static final int R = 30; // 0x1e
field public static final int S = 31; // 0x1f
+ field public static final int S_V2 = 32; // 0x20
}
public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 488f8b145e52..a4fb2c1f12ff 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -113,6 +113,7 @@ package android.app {
method @RequiresPermission(android.Manifest.permission.RESET_APP_ERRORS) public void resetAppErrors();
method public static void resumeAppSwitches() throws android.os.RemoteException;
method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void setStopUserOnSwitch(int);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean stopUser(int, boolean);
method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.DUMP) public void waitForBroadcastIdle();
@@ -127,6 +128,9 @@ package android.app {
field public static final int PROCESS_CAPABILITY_NONE = 0; // 0x0
field public static final int PROCESS_STATE_FOREGROUND_SERVICE = 4; // 0x4
field public static final int PROCESS_STATE_TOP = 2; // 0x2
+ field public static final int STOP_USER_ON_SWITCH_DEFAULT = -1; // 0xffffffff
+ field public static final int STOP_USER_ON_SWITCH_FALSE = 0; // 0x0
+ field public static final int STOP_USER_ON_SWITCH_TRUE = 1; // 0x1
}
public static class ActivityManager.RunningAppProcessInfo implements android.os.Parcelable {
@@ -781,6 +785,7 @@ package android.content.pm {
field public static final float OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE = 1.7777778f;
field public static final long OVERRIDE_MIN_ASPECT_RATIO_MEDIUM = 180326845L; // 0xabf91bdL
field public static final float OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE = 1.5f;
+ field public static final long OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY = 203647190L; // 0xc2368d6L
field public static final int RESIZE_MODE_RESIZEABLE = 2; // 0x2
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index f53c5b6c9748..992f02ca538b 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4076,6 +4076,57 @@ public class ActivityManager {
}
/**
+ * Uses the value defined by the platform.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final int STOP_USER_ON_SWITCH_DEFAULT = -1;
+
+ /**
+ * Overrides value defined by the platform and stop user on switch.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final int STOP_USER_ON_SWITCH_TRUE = 1;
+
+ /**
+ * Overrides value defined by the platform and don't stop user on switch.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final int STOP_USER_ON_SWITCH_FALSE = 0;
+
+ /** @hide */
+ @IntDef(prefix = { "STOP_USER_ON_SWITCH_" }, value = {
+ STOP_USER_ON_SWITCH_DEFAULT,
+ STOP_USER_ON_SWITCH_TRUE,
+ STOP_USER_ON_SWITCH_FALSE
+ })
+ public @interface StopUserOnSwitch {}
+
+ /**
+ * Sets whether the current foreground user (and its profiles) should be stopped after switched
+ * out.
+ *
+ * <p>Should only be used on tests. Doesn't apply to {@link UserHandle#SYSTEM system user}.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS})
+ public void setStopUserOnSwitch(@StopUserOnSwitch int value) {
+ try {
+ getService().setStopUserOnSwitch(value);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Starts a profile.
* To be used with non-managed profiles, managed profiles should use
* {@link UserManager#requestQuietModeEnabled}
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index f8c8aa32a26e..7be4c3e1465b 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -16,6 +16,8 @@
package android.app;
+import static android.app.ActivityManager.StopUserOnSwitch;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -661,6 +663,12 @@ public abstract class ActivityManagerInternal {
@Nullable VoiceInteractionManagerProvider provider);
/**
+ * Sets whether the current foreground user (and its profiles) should be stopped after switched
+ * out.
+ */
+ public abstract void setStopUserOnSwitch(@StopUserOnSwitch int value);
+
+ /**
* Provides the interface to communicate between voice interaction manager service and
* ActivityManagerService.
*/
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 7114d73ae168..b5ed1717496e 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2743,7 +2743,7 @@ class ContextImpl extends Context {
*/
private static Resources createWindowContextResources(@NonNull ContextImpl windowContextBase) {
final LoadedApk packageInfo = windowContextBase.mPackageInfo;
- final ClassLoader classLoader = windowContextBase.mClassLoader;
+ final ClassLoader classLoader = windowContextBase.getClassLoader();
final IBinder token = windowContextBase.getWindowContextToken();
final String resDir = packageInfo.getResDir();
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index b90b9a11611e..0210a94eafcc 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -341,6 +341,7 @@ interface IActivityManager {
@UnsupportedAppUsage
boolean switchUser(int userid);
@UnsupportedAppUsage
+ void setStopUserOnSwitch(int value);
boolean removeTask(int taskId);
@UnsupportedAppUsage
void registerProcessObserver(in IProcessObserver observer);
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index a2c9795204ad..74208c3a4aff 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -2134,4 +2134,38 @@ public final class LoadedApk {
final IBinder mService;
}
}
+
+ /**
+ * Check if the Apk paths in the cache are correct, and update them if they are not.
+ * @hide
+ */
+ public static void checkAndUpdateApkPaths(ApplicationInfo expectedAppInfo) {
+ // Get the LoadedApk from the cache
+ ActivityThread activityThread = ActivityThread.currentActivityThread();
+ if (activityThread == null) {
+ Log.e(TAG, "Cannot find activity thread");
+ return;
+ }
+ checkAndUpdateApkPaths(activityThread, expectedAppInfo, /* cacheWithCode */ true);
+ checkAndUpdateApkPaths(activityThread, expectedAppInfo, /* cacheWithCode */ false);
+ }
+
+ private static void checkAndUpdateApkPaths(ActivityThread activityThread,
+ ApplicationInfo expectedAppInfo, boolean cacheWithCode) {
+ String expectedCodePath = expectedAppInfo.getCodePath();
+ LoadedApk loadedApk = activityThread.peekPackageInfo(
+ expectedAppInfo.packageName, /* includeCode= */ cacheWithCode);
+ // If there is load apk cached, or if the cache is valid, don't do anything.
+ if (loadedApk == null || loadedApk.getApplicationInfo() == null
+ || loadedApk.getApplicationInfo().getCodePath().equals(expectedCodePath)) {
+ return;
+ }
+ // Duplicate framework logic
+ List<String> oldPaths = new ArrayList<>();
+ LoadedApk.makePaths(activityThread, expectedAppInfo, oldPaths);
+
+ // Force update the LoadedApk instance, which should update the reference in the cache
+ loadedApk.updateApplicationInfo(expectedAppInfo, oldPaths);
+ }
+
}
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index bd9b6e952118..ddde27220b96 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -368,7 +368,8 @@ public class TaskInfo {
&& Objects.equals(taskDescription, that.taskDescription)
&& isFocused == that.isFocused
&& isVisible == that.isVisible
- && isSleeping == that.isSleeping;
+ && isSleeping == that.isSleeping
+ && Objects.equals(mTopActivityLocusId, that.mTopActivityLocusId);
}
/**
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index b570ae60ee91..22b1c03fba50 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -240,6 +240,14 @@ public class WallpaperManager {
*/
public static final String EXTRA_NEW_WALLPAPER_ID = "android.service.wallpaper.extra.ID";
+ /**
+ * Extra passed on {@link Intent.ACTION_WALLPAPER_CHANGED} indicating if wallpaper was set from
+ * a foreground app.
+ * @hide
+ */
+ public static final String EXTRA_FROM_FOREGROUND_APP =
+ "android.service.wallpaper.extra.FROM_FOREGROUND_APP";
+
// flags for which kind of wallpaper to act on
/** @hide */
@@ -586,12 +594,12 @@ public class WallpaperManager {
Rect dimensions = null;
synchronized (this) {
+ ParcelFileDescriptor pfd = null;
try {
Bundle params = new Bundle();
+ pfd = mService.getWallpaperWithFeature(context.getOpPackageName(),
+ context.getAttributionTag(), this, FLAG_SYSTEM, params, userId);
// Let's peek user wallpaper first.
- ParcelFileDescriptor pfd = mService.getWallpaperWithFeature(
- context.getOpPackageName(), context.getAttributionTag(), this,
- FLAG_SYSTEM, params, userId);
if (pfd != null) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
@@ -600,6 +608,13 @@ public class WallpaperManager {
}
} catch (RemoteException ex) {
Log.w(TAG, "peek wallpaper dimensions failed", ex);
+ } finally {
+ if (pfd != null) {
+ try {
+ pfd.close();
+ } catch (IOException ignored) {
+ }
+ }
}
}
// If user wallpaper is unavailable, may be the default one instead.
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 5b01a7d2de66..556dfc7a96b3 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3437,6 +3437,9 @@ public class DevicePolicyManager {
* set on the primary {@link DevicePolicyManager} must be cleared first by calling
* {@link #setRequiredPasswordComplexity} with {@link #PASSWORD_COMPLEXITY_NONE) first.
*
+ * <p><string>Note:</strong> this method is ignored on
+ * {PackageManager#FEATURE_AUTOMOTIVE automotive builds}.
+ *
* @deprecated Prefer using {@link #setRequiredPasswordComplexity(int)}, to require a password
* that satisfies a complexity level defined by the platform, rather than specifying custom
* password requirement.
@@ -3527,12 +3530,14 @@ public class DevicePolicyManager {
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
* not, a security exception will be thrown.
* <p>
- *
* Apps targeting {@link android.os.Build.VERSION_CODES#R} and below can call this method on the
* {@link DevicePolicyManager} instance returned by
* {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
* profile.
*
+ * <p><string>Note:</strong> this method is ignored on
+ * {PackageManager#FEATURE_AUTOMOTIVE automotive builds}.
+ *
* @deprecated see {@link #setPasswordQuality(ComponentName, int)} for details.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -3610,12 +3615,14 @@ public class DevicePolicyManager {
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
* not, a security exception will be thrown.
* <p>
- *
* Apps targeting {@link android.os.Build.VERSION_CODES#R} and below can call this method on the
* {@link DevicePolicyManager} instance returned by
* {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
* profile.
*
+ * <p><string>Note:</strong> this method is ignored on
+ * {PackageManager#FEATURE_AUTOMOTIVE automotive builds}.
+ *
* @deprecated see {@link #setPasswordQuality(ComponentName, int)} for details.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -3700,12 +3707,14 @@ public class DevicePolicyManager {
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
* not, a security exception will be thrown.
* <p>
- *
* Apps targeting {@link android.os.Build.VERSION_CODES#R} and below can call this method on the
* {@link DevicePolicyManager} instance returned by
* {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
* profile.
*
+ * <p><string>Note:</strong> this method is ignored on
+ * {PackageManager#FEATURE_AUTOMOTIVE automotive builds}.
+ *
* @deprecated see {@link #setPasswordQuality(ComponentName, int)} for details.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -3790,12 +3799,14 @@ public class DevicePolicyManager {
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
* not, a security exception will be thrown.
* <p>
- *
* Apps targeting {@link android.os.Build.VERSION_CODES#R} and below can call this method on the
* {@link DevicePolicyManager} instance returned by
* {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
* profile.
*
+ * <p><string>Note:</strong> this method is ignored on
+ * {PackageManager#FEATURE_AUTOMOTIVE automotive builds}.
+ *
* @deprecated see {@link #setPasswordQuality(ComponentName, int)} for details.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -3879,12 +3890,14 @@ public class DevicePolicyManager {
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
* not, a security exception will be thrown.
* <p>
- *
* Apps targeting {@link android.os.Build.VERSION_CODES#R} and below can call this method on the
* {@link DevicePolicyManager} instance returned by
* {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
* profile.
*
+ * <p><string>Note:</strong> this method is ignored on
+ * {PackageManager#FEATURE_AUTOMOTIVE automotive builds}.
+ *
* @deprecated see {@link #setPasswordQuality(ComponentName, int)} for details.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -3968,12 +3981,14 @@ public class DevicePolicyManager {
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
* not, a security exception will be thrown.
* <p>
- *
* Apps targeting {@link android.os.Build.VERSION_CODES#R} and below can call this method on the
* {@link DevicePolicyManager} instance returned by
* {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
* profile.
*
+ * <p><string>Note:</strong> this method is ignored on
+ * {PackageManager#FEATURE_AUTOMOTIVE automotive builds}.
+ *
* @deprecated see {@link #setPasswordQuality(ComponentName, int)} for details.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -4056,12 +4071,14 @@ public class DevicePolicyManager {
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has
* not, a security exception will be thrown.
* <p>
- *
* Apps targeting {@link android.os.Build.VERSION_CODES#R} and below can call this method on the
* {@link DevicePolicyManager} instance returned by
* {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
* profile.
*
+ * <p><string>Note:</strong> this method is ignored on
+ * {PackageManager#FEATURE_AUTOMOTIVE automotive builds}.
+ *
* @deprecated see {@link #setPasswordQuality(ComponentName, int)} for details.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -9565,7 +9582,14 @@ public class DevicePolicyManager {
/**
* Called by a profile owner of secondary user that is affiliated with the device to stop the
- * calling user and switch back to primary.
+ * calling user and switch back to primary user.
+ *
+ * <p>Notice that on devices running with
+ * {@link UserManager#isHeadlessSystemUserMode() headless system user mode}, there is no primary
+ * user, so it switches back to the user that was in the foreground before the first call to
+ * {@link #switchUser(ComponentName, UserHandle)} (or fails with
+ * {@link UserManager#USER_OPERATION_ERROR_UNKNOWN} if that method was not called prior to this
+ * call).
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @return one of the following result codes:
@@ -9586,6 +9610,37 @@ public class DevicePolicyManager {
}
/**
+ * Gets the user a {@link #logoutUser(ComponentName)} call would switch to,
+ * or {@link UserHandle#USER_NULL} if the current user is not in a session.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ public @UserIdInt int getLogoutUserId() {
+ try {
+ return mService.getLogoutUserId();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Clears the user that {@link #logoutUser(ComponentName)} would switch to.
+ *
+ * <p>Typically used by system UI after it logout a session.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ public void clearLogoutUser() {
+ try {
+ mService.clearLogoutUser();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Called by a device owner to list all secondary users on the device. Managed profiles are not
* considered as secondary users.
* <p> Used for various user management APIs, including {@link #switchUser}, {@link #removeUser}
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index a0d2977cf09a..01875eda2eca 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -16,6 +16,7 @@
package android.app.admin;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.ComponentName;
@@ -77,6 +78,13 @@ public abstract class DevicePolicyManagerInternal {
OnCrossProfileWidgetProvidersChangeListener listener);
/**
+ * @param userHandle the handle of the user whose profile owner is being fetched.
+ * @return the configured supervision app if it exists and is the device owner or policy owner.
+ */
+ public abstract @Nullable ComponentName getProfileOwnerOrDeviceOwnerSupervisionComponent(
+ @NonNull UserHandle userHandle);
+
+ /**
* Checks if an app with given uid is an active device owner of its user.
*
* <p>This takes the DPMS lock. DO NOT call from PM/UM/AM with their lock held.
diff --git a/core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS b/core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS
new file mode 100644
index 000000000000..f5604347065e
--- /dev/null
+++ b/core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS
@@ -0,0 +1,4 @@
+rubinxu@google.com
+acjohnston@google.com
+pgrafov@google.com
+alexkershaw@google.com #{LAST_RESORT_SUGGESTION} \ No newline at end of file
diff --git a/core/java/android/app/admin/EnterprisePlatform_OWNERS b/core/java/android/app/admin/EnterprisePlatform_OWNERS
new file mode 100644
index 000000000000..fb00fe506ed1
--- /dev/null
+++ b/core/java/android/app/admin/EnterprisePlatform_OWNERS
@@ -0,0 +1,2 @@
+file:WorkDeviceExperience_OWNERS
+file:EnterprisePlatformSecurity_OWNERS \ No newline at end of file
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 1c9187d8d22c..7c7478bdb41f 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -261,6 +261,8 @@ interface IDevicePolicyManager {
int startUserInBackground(in ComponentName who, in UserHandle userHandle);
int stopUser(in ComponentName who, in UserHandle userHandle);
int logoutUser(in ComponentName who);
+ int getLogoutUserId();
+ void clearLogoutUser();
List<UserHandle> getSecondaryUsers(in ComponentName who);
void resetNewUserDisclaimer();
diff --git a/core/java/android/app/admin/OWNERS b/core/java/android/app/admin/OWNERS
index 6acbef29bec3..10a5f14dca9e 100644
--- a/core/java/android/app/admin/OWNERS
+++ b/core/java/android/app/admin/OWNERS
@@ -1,11 +1,5 @@
# Bug component: 142675
-# Android Enterprise team
-rubinxu@google.com
-sandness@google.com
-alexkershaw@google.com
-pgrafov@google.com
+file:EnterprisePlatform_OWNERS
-# Emeritus
-yamasani@google.com
-eranm@google.com
+yamasani@google.com #{LAST_RESORT_SUGGESTION} \ No newline at end of file
diff --git a/core/java/android/app/admin/WorkDeviceExperience_OWNERS b/core/java/android/app/admin/WorkDeviceExperience_OWNERS
new file mode 100644
index 000000000000..dcacaa25a236
--- /dev/null
+++ b/core/java/android/app/admin/WorkDeviceExperience_OWNERS
@@ -0,0 +1,5 @@
+work-device-experience+reviews@google.com
+scottjonathan@google.com
+arangelov@google.com
+kholoudm@google.com
+alexkershaw@google.com #{LAST_RESORT_SUGGESTION} \ No newline at end of file
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index dd147cc26e59..8be2b4873c67 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityOptions;
+import android.app.LoadedApk;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -96,7 +97,8 @@ public class AppWidgetHostView extends FrameLayout {
AppWidgetProviderInfo mInfo;
View mView;
int mViewMode = VIEW_MODE_NOINIT;
- int mLayoutId = -1;
+ // If true, we should not try to re-apply the RemoteViews on the next inflation.
+ boolean mColorMappingChanged = false;
private InteractionHandler mInteractionHandler;
private boolean mOnLightBackground;
private SizeF mCurrentSize = null;
@@ -539,7 +541,6 @@ public class AppWidgetHostView extends FrameLayout {
return;
}
content = getDefaultView();
- mLayoutId = -1;
mViewMode = VIEW_MODE_DEFAULT;
} else {
// Select the remote view we are actually going to apply.
@@ -554,10 +555,9 @@ public class AppWidgetHostView extends FrameLayout {
}
// Prepare a local reference to the remote Context so we're ready to
// inflate any requested LayoutParams.
- mRemoteContext = getRemoteContext();
+ mRemoteContext = getRemoteContextEnsuringCorrectCachedApkPath();
- int layoutId = rvToApply.getLayoutId();
- if (rvToApply.canRecycleView(mView)) {
+ if (!mColorMappingChanged && rvToApply.canRecycleView(mView)) {
try {
rvToApply.reapply(mContext, mView, mInteractionHandler, mCurrentSize,
mColorResources);
@@ -582,7 +582,6 @@ public class AppWidgetHostView extends FrameLayout {
}
}
- mLayoutId = layoutId;
mViewMode = VIEW_MODE_CONTENT;
}
@@ -590,6 +589,7 @@ public class AppWidgetHostView extends FrameLayout {
}
private void applyContent(View content, boolean recycled, Exception exception) {
+ mColorMappingChanged = false;
if (content == null) {
if (mViewMode == VIEW_MODE_ERROR) {
// We've already done this -- nothing to do.
@@ -616,7 +616,7 @@ public class AppWidgetHostView extends FrameLayout {
private void inflateAsync(@NonNull RemoteViews remoteViews) {
// Prepare a local reference to the remote Context so we're ready to
// inflate any requested LayoutParams.
- mRemoteContext = getRemoteContext();
+ mRemoteContext = getRemoteContextEnsuringCorrectCachedApkPath();
int layoutId = remoteViews.getLayoutId();
if (mLastExecutionSignal != null) {
@@ -625,7 +625,7 @@ public class AppWidgetHostView extends FrameLayout {
// If our stale view has been prepared to match active, and the new
// layout matches, try recycling it
- if (layoutId == mLayoutId && mView != null) {
+ if (!mColorMappingChanged && remoteViews.canRecycleView(mView)) {
try {
mLastExecutionSignal = remoteViews.reapplyAsync(mContext,
mView,
@@ -665,7 +665,6 @@ public class AppWidgetHostView extends FrameLayout {
@Override
public void onViewApplied(View v) {
- AppWidgetHostView.this.mLayoutId = mLayoutId;
mViewMode = VIEW_MODE_CONTENT;
applyContent(v, mIsReapply, null);
@@ -718,8 +717,10 @@ public class AppWidgetHostView extends FrameLayout {
* purposes of reading remote resources.
* @hide
*/
- protected Context getRemoteContext() {
+ protected Context getRemoteContextEnsuringCorrectCachedApkPath() {
try {
+ ApplicationInfo expectedAppInfo = mInfo.providerInfo.applicationInfo;
+ LoadedApk.checkAndUpdateApkPaths(expectedAppInfo);
// Return if cloned successfully, otherwise default
Context newContext = mContext.createApplicationContext(
mInfo.providerInfo.applicationInfo,
@@ -765,7 +766,7 @@ public class AppWidgetHostView extends FrameLayout {
try {
if (mInfo != null) {
- Context theirContext = getRemoteContext();
+ Context theirContext = getRemoteContextEnsuringCorrectCachedApkPath();
mRemoteContext = theirContext;
LayoutInflater inflater = (LayoutInflater)
theirContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -904,7 +905,7 @@ public class AppWidgetHostView extends FrameLayout {
}
mColorMapping = colorMapping.clone();
mColorResources = RemoteViews.ColorResources.create(mContext, mColorMapping);
- mLayoutId = -1;
+ mColorMappingChanged = true;
mViewMode = VIEW_MODE_NOINIT;
reapplyLastRemoteViews();
}
@@ -934,7 +935,7 @@ public class AppWidgetHostView extends FrameLayout {
if (mColorResources != null) {
mColorResources = null;
mColorMapping = null;
- mLayoutId = -1;
+ mColorMappingChanged = true;
mViewMode = VIEW_MODE_NOINIT;
reapplyLastRemoteViews();
}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index b99ad5125149..32c491753af4 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -108,7 +108,7 @@ public final class CompanionDeviceManager {
}
private final ICompanionDeviceManager mService;
- private final Context mContext;
+ private Context mContext;
/** @hide */
public CompanionDeviceManager(
@@ -541,6 +541,7 @@ public final class CompanionDeviceManager {
mCallback = null;
mHandler = null;
mRequest = null;
+ mContext = null;
}
}
diff --git a/core/java/android/companion/ICompanionDeviceDiscoveryService.aidl b/core/java/android/companion/ICompanionDeviceDiscoveryService.aidl
index a630873c7f67..e1c13f7fc9e1 100644
--- a/core/java/android/companion/ICompanionDeviceDiscoveryService.aidl
+++ b/core/java/android/companion/ICompanionDeviceDiscoveryService.aidl
@@ -29,4 +29,6 @@ oneway interface ICompanionDeviceDiscoveryService {
in String callingPackage,
in IFindDeviceCallback findCallback,
in AndroidFuture<Association> serviceCallback);
+
+ void onAssociationCreated();
}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index e28e4ad9ae9f..b5298fc9e1c7 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -22,6 +22,7 @@ import android.app.Activity;
import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.compat.annotation.Disabled;
+import android.compat.annotation.EnabledSince;
import android.compat.annotation.Overridable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
@@ -994,10 +995,9 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
* OVERRIDE_MIN_ASPECT_RATIO_MEDIUM
* OVERRIDE_MIN_ASPECT_RATIO_LARGE
*
- * If OVERRIDE_MIN_ASPECT_RATIO is applied, and the activity's orientation is fixed to
- * portrait, the min aspect ratio given in the app's manifest will be overridden to the
- * largest enabled aspect ratio treatment unless the app's manifest value is higher.
- * TODO(b/203647190): add OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY instead of portrait by default
+ * If OVERRIDE_MIN_ASPECT_RATIO is applied, the min aspect ratio given in the app's manifest
+ * will be overridden to the largest enabled aspect ratio treatment unless the app's manifest
+ * value is higher.
* @hide
*/
@ChangeId
@@ -1007,6 +1007,19 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
public static final long OVERRIDE_MIN_ASPECT_RATIO = 174042980L; // buganizer id
/**
+ * This change id restricts treatments that force a given min aspect ratio to activities
+ * whose orientation is fixed to portrait.
+ *
+ * This treatment only takes effect if OVERRIDE_MIN_ASPECT_RATIO is also enabled.
+ * @hide
+ */
+ @ChangeId
+ @Overridable
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S_V2)
+ @TestApi
+ public static final long OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY = 203647190L; // buganizer id
+
+ /**
* This change id sets the activity's min aspect ratio to a medium value as defined by
* OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE.
*
@@ -1041,6 +1054,14 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
public static final float OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE = 16 / 9f;
/**
+ * Compares activity window layout min width/height with require space for multi window to
+ * determine if it can be put into multi window mode.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+ private static final long CHECK_MIN_WIDTH_HEIGHT_FOR_MULTI_WINDOW = 197654537L;
+
+ /**
* Convert Java change bits to native.
*
* @hide
@@ -1327,9 +1348,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
*/
@SizeChangesSupportMode
public int supportsSizeChanges() {
- if (CompatChanges.isChangeEnabled(FORCE_NON_RESIZE_APP,
- applicationInfo.packageName,
- UserHandle.getUserHandleForUid(applicationInfo.uid))) {
+ if (isChangeEnabled(FORCE_NON_RESIZE_APP)) {
return SIZE_CHANGES_UNSUPPORTED_OVERRIDE;
}
@@ -1337,9 +1356,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
return SIZE_CHANGES_SUPPORTED_METADATA;
}
- if (CompatChanges.isChangeEnabled(FORCE_RESIZE_APP,
- applicationInfo.packageName,
- UserHandle.getUserHandleForUid(applicationInfo.uid))) {
+ if (isChangeEnabled(FORCE_RESIZE_APP)) {
return SIZE_CHANGES_SUPPORTED_OVERRIDE;
}
@@ -1351,9 +1368,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
* @hide
*/
public boolean neverSandboxDisplayApis() {
- return CompatChanges.isChangeEnabled(NEVER_SANDBOX_DISPLAY_APIS,
- applicationInfo.packageName,
- UserHandle.getUserHandleForUid(applicationInfo.uid))
+ return isChangeEnabled(NEVER_SANDBOX_DISPLAY_APIS)
|| ConstrainDisplayApisConfig.neverConstrainDisplayApis(applicationInfo);
}
@@ -1362,9 +1377,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
* @hide
*/
public boolean alwaysSandboxDisplayApis() {
- return CompatChanges.isChangeEnabled(ALWAYS_SANDBOX_DISPLAY_APIS,
- applicationInfo.packageName,
- UserHandle.getUserHandleForUid(applicationInfo.uid))
+ return isChangeEnabled(ALWAYS_SANDBOX_DISPLAY_APIS)
|| ConstrainDisplayApisConfig.alwaysConstrainDisplayApis(applicationInfo);
}
@@ -1394,31 +1407,28 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
* @hide
*/
public float getMinAspectRatio(@ScreenOrientation int orientation) {
- // TODO(b/203647190): check orientation only if OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY
- // In case the activity's orientation isn't fixed to portrait, OVERRIDE_MIN_ASPECT_RATIO
- // shouldn't be applied.
- if (applicationInfo == null || !CompatChanges.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO,
- applicationInfo.packageName,
- UserHandle.getUserHandleForUid(applicationInfo.uid))
- || !isFixedOrientationPortrait(orientation)) {
+ if (applicationInfo == null || !isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO) || (
+ isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
+ && !isFixedOrientationPortrait(orientation))) {
return mMinAspectRatio;
}
- if (CompatChanges.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_LARGE,
- applicationInfo.packageName,
- UserHandle.getUserHandleForUid(applicationInfo.uid))) {
+ if (isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_LARGE)) {
return Math.max(OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE, mMinAspectRatio);
}
- if (CompatChanges.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_MEDIUM,
- applicationInfo.packageName,
- UserHandle.getUserHandleForUid(applicationInfo.uid))) {
+ if (isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_MEDIUM)) {
return Math.max(OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE, mMinAspectRatio);
}
return mMinAspectRatio;
}
+ private boolean isChangeEnabled(long changeId) {
+ return CompatChanges.isChangeEnabled(changeId, applicationInfo.packageName,
+ UserHandle.getUserHandleForUid(applicationInfo.uid));
+ }
+
/** @hide */
public float getManifestMinAspectRatio() {
return mMinAspectRatio;
@@ -1480,6 +1490,15 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
}
}
+ /**
+ * Whether we should compare activity window layout min width/height with require space for
+ * multi window to determine if it can be put into multi window mode.
+ * @hide
+ */
+ public boolean shouldCheckMinWidthHeightForMultiWindow() {
+ return isChangeEnabled(CHECK_MIN_WIDTH_HEIGHT_FOR_MULTI_WINDOW);
+ }
+
public void dump(Printer pw, String prefix) {
dump(pw, prefix, DUMP_FLAG_ALL);
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d4fa2d54bd8c..a6bf6a41e756 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2474,6 +2474,16 @@ public abstract class PackageManager {
public static final String FEATURE_CTS = "android.software.cts";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
+ * is opted-in to render the application using Automotive App Host
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_CAR_TEMPLATES_HOST =
+ "android.software.car.templates_host";
+
+ /**
* Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature(String, int)}: If this feature is supported, the device supports
* {@link android.security.identity.IdentityCredentialStore} implemented in secure hardware
diff --git a/core/java/android/hardware/biometrics/BiometricOverlayConstants.java b/core/java/android/hardware/biometrics/BiometricOverlayConstants.java
index 603b06ddabaa..065ae64a92ad 100644
--- a/core/java/android/hardware/biometrics/BiometricOverlayConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricOverlayConstants.java
@@ -38,13 +38,16 @@ public interface BiometricOverlayConstants {
int REASON_AUTH_KEYGUARD = 4;
/** Non-specific usage (from FingerprintManager). */
int REASON_AUTH_OTHER = 5;
+ /** Usage from Settings. */
+ int REASON_AUTH_SETTINGS = 6;
@IntDef({REASON_UNKNOWN,
REASON_ENROLL_FIND_SENSOR,
REASON_ENROLL_ENROLLING,
REASON_AUTH_BP,
REASON_AUTH_KEYGUARD,
- REASON_AUTH_OTHER})
+ REASON_AUTH_OTHER,
+ REASON_AUTH_SETTINGS})
@Retention(RetentionPolicy.SOURCE)
@interface ShowReason {}
}
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index c8c122da4ab8..6b5bec99e674 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -408,6 +408,19 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
}
/**
+ * Flag to decide if authentication should ignore enrollment state.
+ * Defaults to false (not ignoring enrollment state)
+ * @param ignoreEnrollmentState
+ * @return This builder.
+ * @hide
+ */
+ @NonNull
+ public Builder setIgnoreEnrollmentState(boolean ignoreEnrollmentState) {
+ mPromptInfo.setIgnoreEnrollmentState(ignoreEnrollmentState);
+ return this;
+ }
+
+ /**
* Creates a {@link BiometricPrompt}.
*
* @return An instance of {@link BiometricPrompt}.
diff --git a/core/java/android/hardware/biometrics/PromptInfo.java b/core/java/android/hardware/biometrics/PromptInfo.java
index 339c654f4d2f..e6b762a64384 100644
--- a/core/java/android/hardware/biometrics/PromptInfo.java
+++ b/core/java/android/hardware/biometrics/PromptInfo.java
@@ -45,6 +45,7 @@ public class PromptInfo implements Parcelable {
private boolean mReceiveSystemEvents;
@NonNull private List<Integer> mAllowedSensorIds = new ArrayList<>();
private boolean mAllowBackgroundAuthentication;
+ private boolean mIgnoreEnrollmentState;
public PromptInfo() {
@@ -66,6 +67,7 @@ public class PromptInfo implements Parcelable {
mReceiveSystemEvents = in.readBoolean();
mAllowedSensorIds = in.readArrayList(Integer.class.getClassLoader());
mAllowBackgroundAuthentication = in.readBoolean();
+ mIgnoreEnrollmentState = in.readBoolean();
}
public static final Creator<PromptInfo> CREATOR = new Creator<PromptInfo>() {
@@ -102,6 +104,7 @@ public class PromptInfo implements Parcelable {
dest.writeBoolean(mReceiveSystemEvents);
dest.writeList(mAllowedSensorIds);
dest.writeBoolean(mAllowBackgroundAuthentication);
+ dest.writeBoolean(mIgnoreEnrollmentState);
}
public boolean containsTestConfigurations() {
@@ -192,6 +195,10 @@ public class PromptInfo implements Parcelable {
mAllowBackgroundAuthentication = allow;
}
+ public void setIgnoreEnrollmentState(boolean ignoreEnrollmentState) {
+ mIgnoreEnrollmentState = ignoreEnrollmentState;
+ }
+
// Getters
public CharSequence getTitle() {
@@ -261,4 +268,8 @@ public class PromptInfo implements Parcelable {
public boolean isAllowBackgroundAuthentication() {
return mAllowBackgroundAuthentication;
}
+
+ public boolean isIgnoreEnrollmentState() {
+ return mIgnoreEnrollmentState;
+ }
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index a3d595c23095..fe04e5d35784 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -531,7 +531,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
@RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
- authenticate(crypto, cancel, callback, handler, mContext.getUserId());
+ authenticate(crypto, cancel, callback, handler, SENSOR_ID_ANY, mContext.getUserId(), flags);
}
/**
@@ -541,7 +541,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
@RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
@NonNull AuthenticationCallback callback, Handler handler, int userId) {
- authenticate(crypto, cancel, callback, handler, SENSOR_ID_ANY, userId);
+ authenticate(crypto, cancel, callback, handler, SENSOR_ID_ANY, userId, 0 /* flags */);
}
/**
@@ -550,7 +550,8 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
*/
@RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
- @NonNull AuthenticationCallback callback, Handler handler, int sensorId, int userId) {
+ @NonNull AuthenticationCallback callback, Handler handler, int sensorId, int userId,
+ int flags) {
FrameworkStatsLog.write(FrameworkStatsLog.AUTH_DEPRECATED_API_USED,
AUTH_DEPRECATED_APIUSED__DEPRECATED_API__API_FINGERPRINT_MANAGER_AUTHENTICATE,
@@ -566,6 +567,8 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
return;
}
+ final boolean ignoreEnrollmentState = flags == 0 ? false : true;
+
if (mService != null) {
try {
useHandler(handler);
@@ -573,7 +576,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
mCryptoObject = crypto;
final long operationId = crypto != null ? crypto.getOpId() : 0;
final long authId = mService.authenticate(mToken, operationId, sensorId, userId,
- mServiceReceiver, mContext.getOpPackageName());
+ mServiceReceiver, mContext.getOpPackageName(), ignoreEnrollmentState);
if (cancel != null) {
cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index de94b2fbb5b5..ba1dc6da62a6 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -52,7 +52,8 @@ interface IFingerprintService {
// permission. This is effectively deprecated, since it only comes through FingerprintManager
// now. A requestId is returned that can be used to cancel this operation.
long authenticate(IBinder token, long operationId, int sensorId, int userId,
- IFingerprintServiceReceiver receiver, String opPackageName);
+ IFingerprintServiceReceiver receiver, String opPackageName,
+ boolean shouldIgnoreEnrollmentState);
// Uses the fingerprint hardware to detect for the presence of a finger, without giving details
// about accept/reject/lockout. A requestId is returned that can be used to cancel this
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index e6b5081e39a0..fee2e2b27457 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -160,19 +160,19 @@ public class NetworkTemplate implements Parcelable {
}
/**
- * Template to match cellular networks with the given IMSI and {@code ratType}.
- * Use {@link #NETWORK_TYPE_ALL} to include all network types when filtering.
- * See {@code TelephonyManager.NETWORK_TYPE_*}.
+ * Template to match cellular networks with the given IMSI, {@code ratType} and
+ * {@code metered}. Use {@link #NETWORK_TYPE_ALL} to include all network types when
+ * filtering. See {@code TelephonyManager.NETWORK_TYPE_*}.
*/
public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId,
- @NetworkType int ratType) {
+ @NetworkType int ratType, int metered) {
if (TextUtils.isEmpty(subscriberId)) {
return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
+ metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
+ metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL,
SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
@@ -305,6 +305,7 @@ public class NetworkTemplate implements Parcelable {
}
}
+ // TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S)
@UnsupportedAppUsage
public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
this(matchRule, subscriberId, new String[] { subscriberId }, networkId);
@@ -312,9 +313,14 @@ public class NetworkTemplate implements Parcelable {
public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
String networkId) {
- this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
- SUBSCRIBER_ID_MATCH_RULE_EXACT);
+ // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates
+ // to metered networks. It is now possible to match mobile with any meteredness, but
+ // in order to preserve backward compatibility of @UnsupportedAppUsage methods, this
+ //constructor passes METERED_YES for these types.
+ this(matchRule, subscriberId, matchSubscriberIds, networkId,
+ (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES
+ : METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
+ OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
// TODO: Remove it after updating all of the caller.
@@ -589,11 +595,7 @@ public class NetworkTemplate implements Parcelable {
// TODO: consider matching against WiMAX subscriber identity
return true;
} else {
- // Only metered mobile network would be matched regardless of metered filter.
- // This is used to exclude non-metered APNs, e.g. IMS. See ag/908650.
- // TODO: Respect metered filter and remove mMetered condition.
- return (ident.mType == TYPE_MOBILE && ident.mMetered)
- && !ArrayUtils.isEmpty(mMatchSubscriberIds)
+ return ident.mType == TYPE_MOBILE && !ArrayUtils.isEmpty(mMatchSubscriberIds)
&& ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId)
&& matchesCollapsedRatType(ident);
}
@@ -707,8 +709,7 @@ public class NetworkTemplate implements Parcelable {
if (ident.mType == TYPE_WIMAX) {
return true;
} else {
- return (ident.mType == TYPE_MOBILE && ident.mMetered)
- && matchesCollapsedRatType(ident);
+ return ident.mType == TYPE_MOBILE && matchesCollapsedRatType(ident);
}
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 6bf394dc347b..b7dd36e2c4f5 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1024,7 +1024,7 @@ public class Build {
* will also enable {@link StrictMode.ThreadPolicy.Builder#detectUnbufferedIo}.</li>
* <li>{@link android.provider.DocumentsContract}'s various methods will throw failure
* exceptions back to the caller instead of returning null.
- * <li>{@link View#hasFocusable View.hasFocusable} now includes auto-focusable views.</li>
+ * <li>{@link View#hasFocusable() View.hasFocusable} now includes auto-focusable views.</li>
* <li>{@link android.view.SurfaceView} will no longer always change the underlying
* Surface object when something about it changes; apps need to look at the current
* state of the object to determine which things they are interested in have changed.</li>
@@ -1130,6 +1130,15 @@ public class Build {
* S.
*/
public static final int S = 31;
+
+ /**
+ * S V2.
+ *
+ * Once more unto the breach, dear friends, once more.
+ *
+ */
+ public static final int S_V2 = 32;
+
}
/** The type of build, like "user" or "eng". */
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index f3a8b5d79ea0..9f3a847e12eb 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -5365,5 +5365,14 @@ public final class Telephony {
*/
public static final String COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS =
"d2d_sharing_contacts";
+
+ /**
+ * TelephonyProvider column name for NR Advanced calling
+ * Determines if the user has enabled VoNR settings for this subscription.
+ *
+ * @hide
+ */
+ public static final String COLUMN_NR_ADVANCED_CALLING_ENABLED =
+ "nr_advanced_calling_enabled";
}
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 2d263a54b874..c77399f692f0 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -1575,7 +1575,7 @@ public abstract class WallpaperService extends Service {
void updatePage(EngineWindowPage currentPage, int pageIndx, int numPages,
float xOffsetStep) {
// to save creating a runnable, check twice
- long current = SystemClock.elapsedRealtime();
+ long current = System.currentTimeMillis();
long lapsed = current - currentPage.getLastUpdateTime();
// Always update the page when the last update time is <= 0
// This is important especially when the device first boots
@@ -1768,6 +1768,7 @@ public abstract class WallpaperService extends Service {
return;
}
}
+ processLocalColors(mPendingXOffset, mPendingYOffset);
}
/**
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 3d39fbeea7d8..86cf28ffa0e0 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -75,7 +75,7 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put(SETTINGS_PROVIDER_MODEL, "true");
DEFAULT_FLAGS.put(SETTINGS_USE_NEW_BACKUP_ELIGIBILITY_RULES, "true");
DEFAULT_FLAGS.put(SETTINGS_ENABLE_SECURITY_HUB, "true");
- DEFAULT_FLAGS.put(SETTINGS_SUPPORT_LARGE_SCREEN, "false");
+ DEFAULT_FLAGS.put(SETTINGS_SUPPORT_LARGE_SCREEN, "true");
}
private static final Set<String> PERSISTENT_FLAGS;
diff --git a/core/java/android/view/IRecentsAnimationRunner.aidl b/core/java/android/view/IRecentsAnimationRunner.aidl
index 811175566a90..c7fd38092ec7 100644
--- a/core/java/android/view/IRecentsAnimationRunner.aidl
+++ b/core/java/android/view/IRecentsAnimationRunner.aidl
@@ -35,15 +35,17 @@ oneway interface IRecentsAnimationRunner {
* wallpaper not drawing in time, or the handler not finishing the animation within a predefined
* amount of time.
*
- * @param taskSnapshot If the snapshot is null, the animation will be cancelled and the leash
- * will be inactive immediately. Otherwise, the contents of the task will be
- * replaced with {@param taskSnapshot}, such that the runner's leash is
- * still active. As soon as the runner doesn't need the leash anymore, it
- * must call {@link IRecentsAnimationController#cleanupScreenshot).
+ * @param taskIds Indicates tasks with cancelling snapshot.
+ * @param taskSnapshots If the snapshots is null, the animation will be cancelled and the leash
+ * will be inactive immediately. Otherwise, the contents of the tasks will
+ * be replaced with {@param taskSnapshots}, such that the runner's leash is
+ * still active. As soon as the runner doesn't need the leash anymore, it
+ * must call {@link IRecentsAnimationController#cleanupScreenshot).
*
* @see {@link RecentsAnimationController#cleanupScreenshot}
*/
- void onAnimationCanceled(in @nullable TaskSnapshot taskSnapshot) = 1;
+ void onAnimationCanceled(in @nullable int[] taskIds,
+ in @nullable TaskSnapshot[] taskSnapshots) = 1;
/**
* Called when the system is ready for the handler to start animating all the visible tasks.
@@ -61,5 +63,5 @@ oneway interface IRecentsAnimationRunner {
* Called when the task of an activity that has been started while the recents animation
* was running becomes ready for control.
*/
- void onTaskAppeared(in RemoteAnimationTarget app) = 3;
+ void onTasksAppeared(in RemoteAnimationTarget[] app) = 3;
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 1791d3a731f7..9e41e4d2906c 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -61,6 +61,7 @@ import android.view.InputChannel;
import android.view.InputDevice;
import android.view.IInputFilter;
import android.view.AppTransitionAnimationSpec;
+import android.view.TaskTransitionSpec;
import android.view.WindowContentFrameStats;
import android.view.WindowManager;
import android.view.SurfaceControl;
@@ -896,4 +897,17 @@ interface IWindowManager
* @see android.window.WindowProviderService#getLaunchedDisplayId
*/
int getImeDisplayId();
+
+ /**
+ * Customized the task transition animation with a task transition spec.
+ *
+ * @param spec the spec that will be used to customize the task animations
+ */
+ void setTaskTransitionSpec(in TaskTransitionSpec spec);
+
+ /**
+ * Clears any task transition spec that has been previously set and
+ * reverts to using the default task transition with no spec changes.
+ */
+ void clearTaskTransitionSpec();
}
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index 06861046f2c7..02b2c5d5db84 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -124,7 +124,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
public void setControl(@Nullable InsetsSourceControl control, int[] showTypes,
int[] hideTypes) {
super.setControl(control, showTypes, hideTypes);
- if (control == null && !mIsRequestedVisibleAwaitingControl) {
+ if (control == null && !isRequestedVisibleAwaitingControl()) {
hide();
removeSurface();
}
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 7d8d653f5ab3..805727c871b2 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -284,8 +284,8 @@ public class InsetsAnimationControlImpl implements InternalInsetsAnimationContro
mShownOnFinish, mCurrentAlpha, mCurrentInsets));
mController.notifyFinished(this, mShownOnFinish);
releaseLeashes();
+ if (DEBUG) Log.d(TAG, "Animation finished abruptly.");
}
- if (DEBUG) Log.d(TAG, "Animation finished abruptly.");
return mFinished;
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 856dfe53dfac..e8725f00ffdf 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -162,8 +162,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
boolean mIsCreating = false;
- private volatile boolean mRtHandlingPositionUpdates = false;
- private volatile boolean mRtReleaseSurfaces = false;
private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener =
this::updateSurface;
@@ -909,13 +907,14 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
mBlastBufferQueue = null;
}
- if (mRtHandlingPositionUpdates) {
- mRtReleaseSurfaces = true;
- return;
+ ViewRootImpl viewRoot = getViewRootImpl();
+ Transaction transaction = new Transaction();
+ releaseSurfaces(transaction);
+ if (viewRoot != null) {
+ viewRoot.applyTransactionOnDraw(transaction);
+ } else {
+ transaction.apply();
}
-
- releaseSurfaces(mTmpTransaction);
- mTmpTransaction.apply();
}
}
@@ -1468,15 +1467,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
if (mSurfaceControl == null) {
return;
}
- // TODO: This is teensy bit racey in that a brand new SurfaceView moving on
- // its 2nd frame if RenderThread is running slowly could potentially see
- // this as false, enter the branch, get pre-empted, then this comes along
- // and reports a new position, then the UI thread resumes and reports
- // its position. This could therefore be de-sync'd in that interval, but
- // the synchronization would violate the rule that RT must never block
- // on the UI thread which would open up potential deadlocks. The risk of
- // a single-frame desync is therefore preferable for now.
- mRtHandlingPositionUpdates = true;
}
if (mRTLastReportedPosition.left == left
&& mRTLastReportedPosition.top == top
@@ -1552,12 +1542,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
return;
}
mRtTransaction.hide(mSurfaceControl);
- if (mRtReleaseSurfaces) {
- mRtReleaseSurfaces = false;
- releaseSurfaces(mRtTransaction);
- }
applyOrMergeTransaction(mRtTransaction, frameNumber);
- mRtHandlingPositionUpdates = false;
}
}
}
diff --git a/packages/SystemUI/res/interpolator/wireless_charging_animation_interpolator_0.xml b/core/java/android/view/TaskTransitionSpec.aidl
index 3fe59aeea8dc..08af15c3f933 100644
--- a/packages/SystemUI/res/interpolator/wireless_charging_animation_interpolator_0.xml
+++ b/core/java/android/view/TaskTransitionSpec.aidl
@@ -1,7 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
/*
-** Copyright 2018, The Android Open Source Project
+** 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.
@@ -15,7 +13,8 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.001,0.0 0.2,1.0 1.0,1.0" />
+
+package android.view;
+
+/** @hide */
+parcelable TaskTransitionSpec;
diff --git a/core/java/android/view/TaskTransitionSpec.java b/core/java/android/view/TaskTransitionSpec.java
new file mode 100644
index 000000000000..5f498a19f196
--- /dev/null
+++ b/core/java/android/view/TaskTransitionSpec.java
@@ -0,0 +1,92 @@
+/*
+ * 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 android.view;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArraySet;
+
+import java.util.Set;
+
+/**
+ * Holds information about how to execute task transition animations.
+ *
+ * This class is intended to be used with IWindowManager.setTaskTransitionSpec methods when
+ * we want more customization over the way default task transitions are executed.
+ *
+ * @hide
+ */
+public class TaskTransitionSpec implements Parcelable {
+ /**
+ * The background color to use during task animations (override the default background color)
+ */
+ public final int backgroundColor;
+
+ /**
+ * TEMPORARY FIELD (b/202383002)
+ * TODO: Remove once we use surfaceflinger rounded corners on tasks rather than taskbar overlays
+ * or when shell transitions are fully enabled
+ *
+ * A set of {@InsetsState.InternalInsetsType}s we want to use as the source to set the bounds
+ * of the task during the animation. Used to make sure that task animate above the taskbar.
+ * Will also be used to crop to the frame size of the inset source to the inset size to prevent
+ * the taskbar rounded corners overlay from being invisible during task transition animation.
+ */
+ public final Set<Integer> animationBoundInsets;
+
+ public TaskTransitionSpec(
+ int backgroundColor, Set<Integer> animationBoundInsets) {
+ this.backgroundColor = backgroundColor;
+ this.animationBoundInsets = animationBoundInsets;
+ }
+
+ public TaskTransitionSpec(Parcel in) {
+ this.backgroundColor = in.readInt();
+
+ int animationBoundInsetsSize = in.readInt();
+ this.animationBoundInsets = new ArraySet<>(animationBoundInsetsSize);
+ for (int i = 0; i < animationBoundInsetsSize; i++) {
+ this.animationBoundInsets.add(in.readInt());
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(backgroundColor);
+
+ dest.writeInt(animationBoundInsets.size());
+ for (int insetType : animationBoundInsets) {
+ dest.writeInt(insetType);
+ }
+ }
+
+ public static final @android.annotation.NonNull Parcelable.Creator<TaskTransitionSpec>
+ CREATOR = new Parcelable.Creator<TaskTransitionSpec>() {
+ public TaskTransitionSpec createFromParcel(Parcel in) {
+ return new TaskTransitionSpec(in);
+ }
+
+ public TaskTransitionSpec[] newArray(int size) {
+ return new TaskTransitionSpec[size];
+ }
+ };
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 572a7cdabdc9..f4386099a550 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -20270,7 +20270,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@CallSuper
protected void onAttachedToWindow() {
- if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
+ if (mParent != null && (mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
mParent.requestTransparentRegion(this);
}
@@ -25044,7 +25044,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
View parent = this;
- while (parent.mParent != null && parent.mParent instanceof View) {
+ while (parent.mParent instanceof View) {
parent = (View) parent.mParent;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5a3a9d5bb571..b0b5bb8870c6 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -208,6 +208,7 @@ import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.function.Consumer;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
@@ -757,6 +758,8 @@ public final class ViewRootImpl implements ViewParent,
*/
private boolean mNextDrawUseBlastSync = false;
+ private Consumer<SurfaceControl.Transaction> mBLASTDrawConsumer;
+
/**
* Wait for the blast sync transaction complete callback before drawing and queuing up more
* frames. This will prevent out of order buffers submissions when WM has requested to
@@ -820,11 +823,7 @@ public final class ViewRootImpl implements ViewParent,
context);
mCompatibleVisibilityInfo = new SystemUiVisibilityInfo();
mAccessibilityManager = AccessibilityManager.getInstance(context);
- mAccessibilityManager.addAccessibilityStateChangeListener(
- mAccessibilityInteractionConnectionManager, mHandler);
mHighContrastTextManager = new HighContrastTextManager();
- mAccessibilityManager.addHighTextContrastStateChangeListener(
- mHighContrastTextManager, mHandler);
mViewConfiguration = ViewConfiguration.get(context);
mDensity = context.getResources().getDisplayMetrics().densityDpi;
mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
@@ -883,6 +882,13 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ /** Remove a static config callback. */
+ public static void removeConfigCallback(ConfigChangedCallback callback) {
+ synchronized (sConfigCallbacks) {
+ sConfigCallbacks.remove(callback);
+ }
+ }
+
/** Add activity config callback to be notified about override config changes. */
public void setActivityConfigCallback(ActivityConfigCallback callback) {
mActivityConfigCallback = callback;
@@ -1024,8 +1030,6 @@ public final class ViewRootImpl implements ViewParent,
mView = view;
mAttachInfo.mDisplayState = mDisplay.getState();
- mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
-
mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
mFallbackEventHandler.setView(view);
mWindowAttributes.copyFrom(attrs);
@@ -1218,6 +1222,7 @@ public final class ViewRootImpl implements ViewParent,
"Unable to add window -- unknown error code " + res);
}
+ registerListeners();
if ((res & WindowManagerGlobal.ADD_FLAG_USE_BLAST) != 0) {
mUseBLASTAdapter = true;
}
@@ -1274,6 +1279,28 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ /**
+ * Register any kind of listeners if setView was success.
+ */
+ private void registerListeners() {
+ mAccessibilityManager.addAccessibilityStateChangeListener(
+ mAccessibilityInteractionConnectionManager, mHandler);
+ mAccessibilityManager.addHighTextContrastStateChangeListener(
+ mHighContrastTextManager, mHandler);
+ mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
+ }
+
+ /**
+ * Unregister all listeners while detachedFromWindow.
+ */
+ private void unregisterListeners() {
+ mAccessibilityManager.removeAccessibilityStateChangeListener(
+ mAccessibilityInteractionConnectionManager);
+ mAccessibilityManager.removeHighTextContrastStateChangeListener(
+ mHighContrastTextManager);
+ mDisplayManager.unregisterDisplayListener(mDisplayListener);
+ }
+
private void setTag() {
final String[] split = mWindowAttributes.getTitle().toString().split("\\.");
if (split.length > 0) {
@@ -3327,6 +3354,9 @@ public final class ViewRootImpl implements ViewParent,
}
boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
+ if (mBLASTDrawConsumer != null) {
+ mNextDrawUseBlastSync = true;
+ }
if (!cancelDraw) {
if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
@@ -4025,6 +4055,8 @@ public final class ViewRootImpl implements ViewParent,
*/
private HardwareRenderer.FrameCompleteCallback createFrameCompleteCallback(Handler handler,
boolean reportNextDraw, ArrayList<Runnable> commitCallbacks) {
+ final Consumer<SurfaceControl.Transaction> blastSyncConsumer = mBLASTDrawConsumer;
+ mBLASTDrawConsumer = null;
return frameNr -> {
if (DEBUG_BLAST) {
Log.d(mTag, "Received frameCompleteCallback frameNum=" + frameNr);
@@ -4037,6 +4069,9 @@ public final class ViewRootImpl implements ViewParent,
// is only true when the UI thread is paused. Therefore, no one should be
// modifying this object until the next vsync.
mSurfaceChangedTransaction.merge(mRtBLASTSyncTransaction);
+ if (blastSyncConsumer != null) {
+ blastSyncConsumer.accept(mSurfaceChangedTransaction);
+ }
}
if (reportNextDraw) {
@@ -4147,11 +4182,6 @@ public final class ViewRootImpl implements ViewParent,
}
});
});
- } else if (reportNextDraw) {
- // If we need to report next draw, wait for adapter to flush its shadow queue
- // by processing previously queued buffers so that we can submit the
- // transaction a timely manner.
- mBlastBufferQueue.flushShadowQueue();
}
};
registerRtFrameCallback(frameDrawingCallback);
@@ -5016,10 +5046,6 @@ public final class ViewRootImpl implements ViewParent,
}
mAccessibilityInteractionConnectionManager.ensureNoConnection();
- mAccessibilityManager.removeAccessibilityStateChangeListener(
- mAccessibilityInteractionConnectionManager);
- mAccessibilityManager.removeHighTextContrastStateChangeListener(
- mHighContrastTextManager);
removeSendWindowContentChangedCallback();
destroyHardwareRenderer();
@@ -5052,8 +5078,7 @@ public final class ViewRootImpl implements ViewParent,
mInputEventReceiver = null;
}
- mDisplayManager.unregisterDisplayListener(mDisplayListener);
-
+ unregisterListeners();
unscheduleTraversals();
}
@@ -10493,9 +10518,11 @@ public final class ViewRootImpl implements ViewParent,
@Override
public boolean applyTransactionOnDraw(@NonNull SurfaceControl.Transaction t) {
- registerRtFrameCallback(frame -> {
- mergeWithNextTransaction(t, frame);
- });
+ if (mRemoved) {
+ t.apply();
+ } else {
+ registerRtFrameCallback(frame -> mergeWithNextTransaction(t, frame));
+ }
return true;
}
@@ -10534,4 +10561,35 @@ public final class ViewRootImpl implements ViewParent,
listener.onBufferTransformHintChanged(hint);
}
}
+
+ /**
+ * Redirect the next draw of this ViewRoot (from the UI thread perspective)
+ * to the passed in consumer. This can be used to create P2P synchronization
+ * between ViewRoot's however it comes with many caveats.
+ *
+ * 1. You MUST consume the transaction, by either applying it immediately or
+ * merging it in to another transaction. The threading model doesn't
+ * allow you to hold in the passed transaction.
+ * 2. If you merge it in to another transaction, this ViewRootImpl will be
+ * paused until you finally apply that transaction and it receives
+ * the callback from SF. If you lose track of the transaction you will
+ * ANR the app.
+ * 3. Only one person can consume the transaction at a time, if you already
+ * have a pending consumer for this frame, the function will return false
+ * 4. Someone else may have requested to consume the next frame, in which case
+ * this function will return false and you will not receive a callback.
+ * 5. This function does not trigger drawing so even if it returns true you
+ * may not receive a callback unless there is some other UI thread work
+ * to trigger drawing. If it returns true, and a draw occurs, the callback
+ * will be called (Though again watch out for the null transaction case!)
+ * 6. This function must be called on the UI thread. The consumer will likewise
+ * be called on the UI thread.
+ */
+ public boolean consumeNextDraw(Consumer<SurfaceControl.Transaction> consume) {
+ if (mBLASTDrawConsumer != null) {
+ return false;
+ }
+ mBLASTDrawConsumer = consume;
+ return true;
+ }
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 51cd95e42742..8764ccc9d5f8 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -2441,6 +2441,20 @@ public interface WindowManager extends ViewManager {
public static final int PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY = 0x00100000;
/**
+ * Flag to indicate that this window will be excluded while computing the magnifiable region
+ * on the un-scaled screen coordinate, which could avoid the cutout on the magnification
+ * border. It should be used for unmagnifiable overlays.
+ *
+ * </p><p>
+ * Note unlike {@link #PRIVATE_FLAG_NOT_MAGNIFIABLE}, this flag doesn't affect the ability
+ * of magnification. If you want to the window to be unmagnifiable and doesn't lead to the
+ * cutout, you need to combine both of them.
+ * </p><p>
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION = 0x00200000;
+
+ /**
* Flag to prevent the window from being magnified by the accessibility magnifier.
*
* TODO(b/190623172): This is a temporary solution and need to find out another way instead.
@@ -2551,6 +2565,7 @@ public interface WindowManager extends ViewManager {
PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE,
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY,
+ PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION,
PRIVATE_FLAG_NOT_MAGNIFIABLE,
PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION,
PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC,
@@ -2632,6 +2647,10 @@ public interface WindowManager extends ViewManager {
equals = PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY,
name = "IS_ROUNDED_CORNERS_OVERLAY"),
@ViewDebug.FlagToString(
+ mask = PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION,
+ equals = PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION,
+ name = "EXCLUDE_FROM_SCREEN_MAGNIFICATION"),
+ @ViewDebug.FlagToString(
mask = PRIVATE_FLAG_NOT_MAGNIFIABLE,
equals = PRIVATE_FLAG_NOT_MAGNIFIABLE,
name = "NOT_MAGNIFIABLE"),
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index aa73ed7c8908..9d1bf171128e 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -369,6 +369,10 @@ public class UiTranslationController {
Log.v(TAG, "onVirtualViewTranslationCompleted: received response for "
+ "AutofillId " + autofillId);
}
+ view.onVirtualViewTranslationResponses(virtualChildResponse);
+ if (mCurrentState == STATE_UI_TRANSLATION_PAUSED) {
+ return;
+ }
mActivity.runOnUiThread(() -> {
if (view.getViewTranslationCallback() == null) {
if (DEBUG) {
@@ -377,7 +381,6 @@ public class UiTranslationController {
}
return;
}
- view.onVirtualViewTranslationResponses(virtualChildResponse);
if (view.getViewTranslationCallback() != null) {
view.getViewTranslationCallback().onShowTranslation(view);
}
@@ -425,6 +428,8 @@ public class UiTranslationController {
+ " may be gone.");
continue;
}
+ int currentState;
+ currentState = mCurrentState;
mActivity.runOnUiThread(() -> {
ViewTranslationCallback callback = view.getViewTranslationCallback();
if (view.getViewTranslationResponse() != null
@@ -458,6 +463,9 @@ public class UiTranslationController {
callback.enableContentPadding();
}
view.onViewTranslationResponse(response);
+ if (currentState == STATE_UI_TRANSLATION_PAUSED) {
+ return;
+ }
callback.onShowTranslation(view);
});
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index fe5eb085dc5c..f724285df9dc 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -34,6 +34,7 @@ import android.app.Activity;
import android.app.ActivityOptions;
import android.app.ActivityThread;
import android.app.Application;
+import android.app.LoadedApk;
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.appwidget.AppWidgetHostView;
@@ -5475,7 +5476,8 @@ public class RemoteViews implements Parcelable, Filter {
// user. So build a context that loads resources from that user but
// still returns the current users userId so settings like data / time formats
// are loaded without requiring cross user persmissions.
- final Context contextForResources = getContextForResources(context);
+ final Context contextForResources =
+ getContextForResourcesEnsuringCorrectCachedApkPaths(context);
if (colorResources != null) {
colorResources.apply(contextForResources);
}
@@ -5733,24 +5735,44 @@ public class RemoteViews implements Parcelable, Filter {
return previousLayoutId == getLayoutId() && mViewId == overrideId;
}
- // Note: topLevel should be true only for calls on the topLevel RemoteViews, internal calls
- // should set it to false.
- private void reapply(Context context, View v, InteractionHandler handler, SizeF size,
- ColorResources colorResources, boolean topLevel) {
-
+ /**
+ * Returns the RemoteViews that should be used in the reapply operation.
+ *
+ * If the current RemoteViews has multiple layout, this will select the correct one.
+ *
+ * @throws RuntimeException If the current RemoteViews should not be reapplied onto the provided
+ * View.
+ */
+ private RemoteViews getRemoteViewsToReapply(Context context, View v, @Nullable SizeF size) {
RemoteViews rvToApply = getRemoteViewsToApply(context, size);
// In the case that a view has this RemoteViews applied in one orientation or size, is
// persisted across change, and has the RemoteViews re-applied in a different situation
// (orientation or size), we throw an exception, since the layouts may be completely
// unrelated.
- if (hasMultipleLayouts()) {
+ // If the ViewID has been changed on the view, or is changed by the RemoteViews, we also
+ // may throw an exception, as the RemoteViews will probably not apply properly.
+ // However, we need to let potentially unrelated RemoteViews apply, as this lack of testing
+ // is already used in production code in some apps.
+ if (hasMultipleLayouts()
+ || rvToApply.mViewId != View.NO_ID
+ || v.getTag(R.id.remote_views_override_id) != null) {
if (!rvToApply.canRecycleView(v)) {
throw new RuntimeException("Attempting to re-apply RemoteViews to a view that" +
" that does not share the same root layout id.");
}
}
+ return rvToApply;
+ }
+
+ // Note: topLevel should be true only for calls on the topLevel RemoteViews, internal calls
+ // should set it to false.
+ private void reapply(Context context, View v, InteractionHandler handler, SizeF size,
+ ColorResources colorResources, boolean topLevel) {
+
+ RemoteViews rvToApply = getRemoteViewsToReapply(context, v, size);
+
rvToApply.performApply(v, (ViewGroup) v.getParent(), handler, colorResources);
// If the parent of the view is has is a root, resolve the recycling.
@@ -5787,17 +5809,7 @@ public class RemoteViews implements Parcelable, Filter {
public CancellationSignal reapplyAsync(Context context, View v, Executor executor,
OnViewAppliedListener listener, InteractionHandler handler, SizeF size,
ColorResources colorResources) {
- RemoteViews rvToApply = getRemoteViewsToApply(context, size);
-
- // In the case that a view has this RemoteViews applied in one orientation, is persisted
- // across orientation change, and has the RemoteViews re-applied in the new orientation,
- // we throw an exception, since the layouts may be completely unrelated.
- if (hasMultipleLayouts()) {
- if ((Integer) v.getTag(R.id.widget_frame) != rvToApply.getLayoutId()) {
- throw new RuntimeException("Attempting to re-apply RemoteViews to a view that" +
- " that does not share the same root layout id.");
- }
- }
+ RemoteViews rvToApply = getRemoteViewsToReapply(context, v, size);
return new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(),
context, listener, handler, colorResources, v, true /* topLevel */)
@@ -5853,13 +5865,14 @@ public class RemoteViews implements Parcelable, Filter {
}
}
- private Context getContextForResources(Context context) {
+ private Context getContextForResourcesEnsuringCorrectCachedApkPaths(Context context) {
if (mApplication != null) {
if (context.getUserId() == UserHandle.getUserId(mApplication.uid)
&& context.getPackageName().equals(mApplication.packageName)) {
return context;
}
try {
+ LoadedApk.checkAndUpdateApkPaths(mApplication);
return context.createApplicationContext(mApplication,
Context.CONTEXT_RESTRICTED);
} catch (NameNotFoundException e) {
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 6b33428d7fe4..8e293f4b356d 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -408,7 +408,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
}
@Override
- protected Context getRemoteContext() {
+ protected Context getRemoteContextEnsuringCorrectCachedApkPath() {
return null;
}
diff --git a/core/java/android/window/RemoteTransition.java b/core/java/android/window/RemoteTransition.java
index b243b656b8cd..4bd15f27a91a 100644
--- a/core/java/android/window/RemoteTransition.java
+++ b/core/java/android/window/RemoteTransition.java
@@ -18,6 +18,7 @@ package android.window;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.IApplicationThread;
import android.os.IBinder;
import android.os.Parcelable;
@@ -34,6 +35,14 @@ public class RemoteTransition implements Parcelable {
/** The actual remote-transition interface used to run the transition animation. */
private @NonNull IRemoteTransition mRemoteTransition;
+ /** The application thread that will be running the remote transition. */
+ private @Nullable IApplicationThread mAppThread;
+
+ /** Constructs with no app thread (animation runs in shell). */
+ public RemoteTransition(@NonNull IRemoteTransition remoteTransition) {
+ this(remoteTransition, null /* appThread */);
+ }
+
/** Get the IBinder associated with the underlying IRemoteTransition. */
public @Nullable IBinder asBinder() {
return mRemoteTransition.asBinder();
@@ -59,13 +68,17 @@ public class RemoteTransition implements Parcelable {
*
* @param remoteTransition
* The actual remote-transition interface used to run the transition animation.
+ * @param appThread
+ * The application thread that will be running the remote transition.
*/
@DataClass.Generated.Member
public RemoteTransition(
- @NonNull IRemoteTransition remoteTransition) {
+ @NonNull IRemoteTransition remoteTransition,
+ @Nullable IApplicationThread appThread) {
this.mRemoteTransition = remoteTransition;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mRemoteTransition);
+ this.mAppThread = appThread;
// onConstructed(); // You can define this method to get a callback
}
@@ -79,6 +92,14 @@ public class RemoteTransition implements Parcelable {
}
/**
+ * The application thread that will be running the remote transition.
+ */
+ @DataClass.Generated.Member
+ public @Nullable IApplicationThread getAppThread() {
+ return mAppThread;
+ }
+
+ /**
* The actual remote-transition interface used to run the transition animation.
*/
@DataClass.Generated.Member
@@ -89,6 +110,15 @@ public class RemoteTransition implements Parcelable {
return this;
}
+ /**
+ * The application thread that will be running the remote transition.
+ */
+ @DataClass.Generated.Member
+ public @NonNull RemoteTransition setAppThread(@NonNull IApplicationThread value) {
+ mAppThread = value;
+ return this;
+ }
+
@Override
@DataClass.Generated.Member
public String toString() {
@@ -96,7 +126,8 @@ public class RemoteTransition implements Parcelable {
// String fieldNameToString() { ... }
return "RemoteTransition { " +
- "remoteTransition = " + mRemoteTransition +
+ "remoteTransition = " + mRemoteTransition + ", " +
+ "appThread = " + mAppThread +
" }";
}
@@ -106,7 +137,11 @@ public class RemoteTransition implements Parcelable {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
+ byte flg = 0;
+ if (mAppThread != null) flg |= 0x2;
+ dest.writeByte(flg);
dest.writeStrongInterface(mRemoteTransition);
+ if (mAppThread != null) dest.writeStrongInterface(mAppThread);
}
@Override
@@ -120,11 +155,14 @@ public class RemoteTransition implements Parcelable {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
+ byte flg = in.readByte();
IRemoteTransition remoteTransition = IRemoteTransition.Stub.asInterface(in.readStrongBinder());
+ IApplicationThread appThread = (flg & 0x2) == 0 ? null : IApplicationThread.Stub.asInterface(in.readStrongBinder());
this.mRemoteTransition = remoteTransition;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mRemoteTransition);
+ this.mAppThread = appThread;
// onConstructed(); // You can define this method to get a callback
}
@@ -144,10 +182,10 @@ public class RemoteTransition implements Parcelable {
};
@DataClass.Generated(
- time = 1630613039043L,
+ time = 1630690027011L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/window/RemoteTransition.java",
- inputSignatures = "private @android.annotation.NonNull android.window.IRemoteTransition mRemoteTransition\npublic @android.annotation.Nullable android.os.IBinder asBinder()\nclass RemoteTransition extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genSetters=true, genAidl=true)")
+ inputSignatures = "private @android.annotation.NonNull android.window.IRemoteTransition mRemoteTransition\nprivate @android.annotation.Nullable android.app.IApplicationThread mAppThread\npublic @android.annotation.Nullable android.os.IBinder asBinder()\nclass RemoteTransition extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genSetters=true, genAidl=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/window/SplashScreen.java b/core/java/android/window/SplashScreen.java
index 3354a6ca7738..b9bf009fb2bb 100644
--- a/core/java/android/window/SplashScreen.java
+++ b/core/java/android/window/SplashScreen.java
@@ -92,6 +92,9 @@ public interface SplashScreen {
* overrides and persists the theme used for the {@link SplashScreen} of this application.
* <p>
* To reset to the default theme, set this the themeId to {@link Resources#ID_NULL}.
+ * <p>
+ * <b>Note:</b> The theme name must be stable across versions, otherwise it won't be found
+ * after your application is updated.
*/
void setSplashScreenTheme(@StyleRes int themeId);
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index f748d4bc121d..f04155d112d4 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -20,6 +20,10 @@ import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACK
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_SPLASHSCREEN_AVD;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -54,6 +58,7 @@ import android.widget.FrameLayout;
import android.widget.ImageView;
import com.android.internal.R;
+import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.policy.DecorView;
import com.android.internal.util.ContrastColorUtil;
@@ -487,6 +492,23 @@ public final class SplashScreenView extends FrameLayout {
}
IconAnimateListener aniDrawable = (IconAnimateListener) iconDrawable;
aniDrawable.prepareAnimate(duration, this::animationStartCallback);
+ aniDrawable.setAnimationJankMonitoring(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ InteractionJankMonitor.getInstance().cancel(CUJ_SPLASHSCREEN_AVD);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ InteractionJankMonitor.getInstance().end(CUJ_SPLASHSCREEN_AVD);
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ InteractionJankMonitor.getInstance().begin(
+ SplashScreenView.this, CUJ_SPLASHSCREEN_AVD);
+ }
+ });
}
private void animationStartCallback() {
@@ -669,6 +691,12 @@ public final class SplashScreenView extends FrameLayout {
* Stop animation.
*/
void stopAnimation();
+
+ /**
+ * Provides a chance to start interaction jank monitoring in avd animation.
+ * @param listener a listener to start jank monitoring
+ */
+ default void setAnimationJankMonitoring(AnimatorListenerAdapter listener) {}
}
/**
diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java
index 165dcdf3a836..a118f9a8188f 100644
--- a/core/java/android/window/TaskFragmentInfo.java
+++ b/core/java/android/window/TaskFragmentInfo.java
@@ -213,6 +213,7 @@ public final class TaskFragmentInfo implements Parcelable {
+ " isEmpty=" + mIsEmpty
+ " runningActivityCount=" + mRunningActivityCount
+ " isVisible=" + mIsVisible
+ + " activities=" + mActivities
+ " positionInParent=" + mPositionInParent
+ " isTaskClearedForReuse=" + mIsTaskClearedForReuse
+ "}";
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index c863292d4ea0..d14054d4f9f7 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -99,6 +99,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
private final ViewRootImpl.SurfaceChangedCallback mSurfaceChangedCallback;
private final Handler mHandler;
private final ChoreographerWrapper mChoreographer;
+ private final Object mLock = InteractionJankMonitor.getInstance().getLock();
@VisibleForTesting
public final boolean mSurfaceOnly;
@@ -181,7 +182,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
mSurfaceChangedCallback = new ViewRootImpl.SurfaceChangedCallback() {
@Override
public void surfaceCreated(SurfaceControl.Transaction t) {
- synchronized (FrameTracker.this) {
+ synchronized (mLock) {
if (mSurfaceControl == null) {
mSurfaceControl = mViewRoot.getSurfaceControl();
if (mBeginVsyncId != INVALID_ID) {
@@ -203,12 +204,12 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
// 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) {
+ synchronized (mLock) {
if (DEBUG) {
Log.d(TAG, "surfaceDestroyed: " + mSession.getName()
+ ", finalized=" + mMetricsFinalized
+ ", info=" + mJankInfos.size()
- + ", vsync=" + mBeginVsyncId + "-" + mEndVsyncId);
+ + ", vsync=" + mBeginVsyncId);
}
if (!mMetricsFinalized) {
end(REASON_END_SURFACE_DESTROYED);
@@ -227,20 +228,20 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
/**
* Begin a trace session of the CUJ.
*/
- public synchronized void begin() {
- mBeginVsyncId = mChoreographer.getVsyncId() + 1;
- 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);
+ public void begin() {
+ synchronized (mLock) {
+ mBeginVsyncId = mChoreographer.getVsyncId() + 1;
+ if (DEBUG) {
+ Log.d(TAG, "begin: " + mSession.getName() + ", begin=" + mBeginVsyncId);
+ }
+ if (mSurfaceControl != null) {
+ postTraceStartMarker();
+ mSurfaceControlWrapper.addJankStatsListener(this, mSurfaceControl);
+ }
+ if (!mSurfaceOnly) {
+ mRendererWrapper.addObserver(mObserver);
+ }
+ notifyCujEvent(ACTION_SESSION_BEGIN);
}
}
@@ -250,7 +251,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
@VisibleForTesting
public void postTraceStartMarker() {
mChoreographer.mChoreographer.postCallback(Choreographer.CALLBACK_INPUT, () -> {
- synchronized (FrameTracker.this) {
+ synchronized (mLock) {
if (mCancelled || mEndVsyncId != INVALID_ID) {
return;
}
@@ -263,88 +264,98 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
/**
* End the trace session of the CUJ.
*/
- public synchronized void end(@Reasons int reason) {
- if (mEndVsyncId != INVALID_ID) return;
- mEndVsyncId = mChoreographer.getVsyncId();
-
- // Cancel the session if:
- // 1. The session begins and ends at the same vsync id.
- // 2. The session never begun.
- if (mBeginVsyncId == INVALID_ID) {
- cancel(REASON_CANCEL_NOT_BEGUN);
- } else if (mEndVsyncId <= mBeginVsyncId) {
- cancel(REASON_CANCEL_SAME_VSYNC);
- } else {
- if (DEBUG) {
- Log.d(TAG, "end: " + mSession.getName()
- + ", end=" + mEndVsyncId + ", reason=" + reason);
- }
- Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
- mSession.setReason(reason);
- if (mListener != null) {
- mListener.onCujEvents(mSession, ACTION_SESSION_END);
+ public boolean end(@Reasons int reason) {
+ synchronized (mLock) {
+ if (mCancelled || mEndVsyncId != INVALID_ID) return false;
+ mEndVsyncId = mChoreographer.getVsyncId();
+ // Cancel the session if:
+ // 1. The session begins and ends at the same vsync id.
+ // 2. The session never begun.
+ if (mBeginVsyncId == INVALID_ID) {
+ return cancel(REASON_CANCEL_NOT_BEGUN);
+ } else if (mEndVsyncId <= mBeginVsyncId) {
+ return cancel(REASON_CANCEL_SAME_VSYNC);
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, "end: " + mSession.getName()
+ + ", end=" + mEndVsyncId + ", reason=" + reason);
+ }
+ Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
+ mSession.setReason(reason);
+
+ // We don't remove observer here,
+ // will remove it when all the frame metrics in this duration are called back.
+ // See onFrameMetricsAvailable for the logic of removing the observer.
+ // Waiting at most 10 seconds for all callbacks to finish.
+ mWaitForFinishTimedOut = () -> {
+ Log.e(TAG, "force finish cuj because of time out:" + mSession.getName());
+ finish(mJankInfos.size() - 1);
+ };
+ mHandler.postDelayed(mWaitForFinishTimedOut, TimeUnit.SECONDS.toMillis(10));
+ notifyCujEvent(ACTION_SESSION_END);
+ return true;
}
-
- // We don't remove observer here,
- // will remove it when all the frame metrics in this duration are called back.
- // See onFrameMetricsAvailable for the logic of removing the observer.
- // Waiting at most 10 seconds for all callbacks to finish.
- mWaitForFinishTimedOut = () -> {
- Log.e(TAG, "force finish cuj because of time out:" + mSession.getName());
- finish(mJankInfos.size() - 1);
- };
- mHandler.postDelayed(mWaitForFinishTimedOut, TimeUnit.SECONDS.toMillis(10));
}
}
/**
* Cancel the trace session of the CUJ.
*/
- public synchronized void cancel(@Reasons int reason) {
- mCancelled = true;
+ public boolean cancel(@Reasons int reason) {
+ synchronized (mLock) {
+ final boolean cancelFromEnd =
+ reason == REASON_CANCEL_NOT_BEGUN || reason == REASON_CANCEL_SAME_VSYNC;
+ if (mCancelled || (mEndVsyncId != INVALID_ID && !cancelFromEnd)) return false;
+ mCancelled = true;
+ // We don't need to end the trace section if it never begun.
+ if (mTracingStarted) {
+ Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
+ }
- // We don't need to end the trace section if it never begun.
- if (mTracingStarted) {
- Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
- }
+ // Always remove the observers in cancel call to avoid leakage.
+ removeObservers();
- // Always remove the observers in cancel call to avoid leakage.
- removeObservers();
+ if (DEBUG) {
+ Log.d(TAG, "cancel: " + mSession.getName() + ", begin=" + mBeginVsyncId
+ + ", end=" + mEndVsyncId + ", reason=" + reason);
+ }
- if (DEBUG) {
- Log.d(TAG, "cancel: " + mSession.getName()
- + ", begin=" + mBeginVsyncId + ", end=" + mEndVsyncId + ", reason=" + reason);
+ mSession.setReason(reason);
+ // Notify the listener the session has been cancelled.
+ // We don't notify the listeners if the session never begun.
+ notifyCujEvent(ACTION_SESSION_CANCEL);
+ return true;
}
+ }
- mSession.setReason(reason);
- // Notify the listener the session has been cancelled.
- // We don't notify the listeners if the session never begun.
- if (mListener != null) {
- mListener.onCujEvents(mSession, ACTION_SESSION_CANCEL);
- }
+ private void notifyCujEvent(String action) {
+ if (mListener == null) return;
+ mListener.onCujEvents(mSession, action);
}
@Override
- public synchronized void onJankDataAvailable(SurfaceControl.JankData[] jankData) {
- if (mCancelled) {
- return;
- }
-
- for (SurfaceControl.JankData jankStat : jankData) {
- if (!isInRange(jankStat.frameVsyncId)) {
- continue;
+ public void onJankDataAvailable(SurfaceControl.JankData[] jankData) {
+ synchronized (mLock) {
+ if (mCancelled) {
+ return;
}
- JankInfo info = findJankInfo(jankStat.frameVsyncId);
- if (info != null) {
- info.surfaceControlCallbackFired = true;
- info.jankType = jankStat.jankType;
- } else {
- mJankInfos.put((int) jankStat.frameVsyncId,
- JankInfo.createFromSurfaceControlCallback(
- jankStat.frameVsyncId, jankStat.jankType));
+
+ for (SurfaceControl.JankData jankStat : jankData) {
+ if (!isInRange(jankStat.frameVsyncId)) {
+ continue;
+ }
+ JankInfo info = findJankInfo(jankStat.frameVsyncId);
+ if (info != null) {
+ info.surfaceControlCallbackFired = true;
+ info.jankType = jankStat.jankType;
+ } else {
+ mJankInfos.put((int) jankStat.frameVsyncId,
+ JankInfo.createFromSurfaceControlCallback(
+ jankStat.frameVsyncId, jankStat.jankType));
+ }
}
+ processJankInfos();
}
- processJankInfos();
}
private @Nullable JankInfo findJankInfo(long frameVsyncId) {
@@ -359,31 +370,34 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
}
@Override
- public synchronized void onFrameMetricsAvailable(int dropCountSinceLastInvocation) {
- if (mCancelled) {
- return;
- }
+ public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) {
+ synchronized (mLock) {
+ if (mCancelled) {
+ return;
+ }
- // Since this callback might come a little bit late after the end() call.
- // We should keep tracking the begin / end timestamp.
- // Then compare with vsync timestamp to check if the frame is in the duration of the CUJ.
- long totalDurationNanos = mMetricsWrapper.getMetric(FrameMetrics.TOTAL_DURATION);
- boolean isFirstFrame = mMetricsWrapper.getMetric(FrameMetrics.FIRST_DRAW_FRAME) == 1;
- long frameVsyncId = mMetricsWrapper.getTiming()[FrameMetrics.Index.FRAME_TIMELINE_VSYNC_ID];
+ // Since this callback might come a little bit late after the end() call.
+ // We should keep tracking the begin / end timestamp that we can compare with
+ // vsync timestamp to check if the frame is in the duration of the CUJ.
+ long totalDurationNanos = mMetricsWrapper.getMetric(FrameMetrics.TOTAL_DURATION);
+ boolean isFirstFrame = mMetricsWrapper.getMetric(FrameMetrics.FIRST_DRAW_FRAME) == 1;
+ long frameVsyncId =
+ mMetricsWrapper.getTiming()[FrameMetrics.Index.FRAME_TIMELINE_VSYNC_ID];
- if (!isInRange(frameVsyncId)) {
- return;
- }
- JankInfo info = findJankInfo(frameVsyncId);
- if (info != null) {
- info.hwuiCallbackFired = true;
- info.totalDurationNanos = totalDurationNanos;
- info.isFirstFrame = isFirstFrame;
- } else {
- mJankInfos.put((int) frameVsyncId, JankInfo.createFromHwuiCallback(
- frameVsyncId, totalDurationNanos, isFirstFrame));
+ if (!isInRange(frameVsyncId)) {
+ return;
+ }
+ JankInfo info = findJankInfo(frameVsyncId);
+ if (info != null) {
+ info.hwuiCallbackFired = true;
+ info.totalDurationNanos = totalDurationNanos;
+ info.isFirstFrame = isFirstFrame;
+ } else {
+ mJankInfos.put((int) frameVsyncId, JankInfo.createFromHwuiCallback(
+ frameVsyncId, totalDurationNanos, isFirstFrame));
+ }
+ processJankInfos();
}
- processJankInfos();
}
/**
@@ -497,11 +511,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
(int) (maxFrameTimeNanos / NANOS_IN_MILLISECOND));
// Trigger perfetto if necessary.
- boolean overMissedFramesThreshold = mTraceThresholdMissedFrames != -1
- && missedFramesCount >= mTraceThresholdMissedFrames;
- boolean overFrameTimeThreshold = !mSurfaceOnly && mTraceThresholdFrameTimeMillis != -1
- && maxFrameTimeNanos >= mTraceThresholdFrameTimeMillis * NANOS_IN_MILLISECOND;
- if (overMissedFramesThreshold || overFrameTimeThreshold) {
+ if (shouldTriggerPerfetto(missedFramesCount, (int) maxFrameTimeNanos)) {
triggerPerfetto();
}
if (mSession.logToStatsd()) {
@@ -513,9 +523,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
maxFrameTimeNanos, /* will be 0 if mSurfaceOnly == true */
missedSfFramesCount,
missedAppFramesCount);
- if (mListener != null) {
- mListener.onCujEvents(mSession, ACTION_METRICS_LOGGED);
- }
+ notifyCujEvent(ACTION_METRICS_LOGGED);
}
if (DEBUG) {
Log.i(TAG, "finish: CUJ=" + mSession.getName()
@@ -528,6 +536,14 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
}
}
+ private boolean shouldTriggerPerfetto(int missedFramesCount, int maxFrameTimeNanos) {
+ boolean overMissedFramesThreshold = mTraceThresholdMissedFrames != -1
+ && missedFramesCount >= mTraceThresholdMissedFrames;
+ boolean overFrameTimeThreshold = !mSurfaceOnly && mTraceThresholdFrameTimeMillis != -1
+ && maxFrameTimeNanos >= mTraceThresholdFrameTimeMillis * NANOS_IN_MILLISECOND;
+ return overMissedFramesThreshold || overFrameTimeThreshold;
+ }
+
/**
* Remove all the registered listeners, observers and callbacks.
*/
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index f8eb95cbd48c..ea38db304e6d 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -58,6 +58,8 @@ 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_EXPAND;
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__SPLASHSCREEN_AVD;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_EXIT_ANIM;
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__USER_SWITCH;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION;
@@ -173,6 +175,8 @@ public class InteractionJankMonitor {
public static final int CUJ_PIP_TRANSITION = 35;
public static final int CUJ_WALLPAPER_TRANSITION = 36;
public static final int CUJ_USER_SWITCH = 37;
+ public static final int CUJ_SPLASHSCREEN_AVD = 38;
+ public static final int CUJ_SPLASHSCREEN_EXIT_ANIM = 39;
private static final int NO_STATSD_LOGGING = -1;
@@ -219,6 +223,8 @@ public class InteractionJankMonitor {
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PIP_TRANSITION,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_SWITCH,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_AVD,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_EXIT_ANIM,
};
private static volatile InteractionJankMonitor sInstance;
@@ -230,6 +236,7 @@ public class InteractionJankMonitor {
private final SparseArray<FrameTracker> mRunningTrackers;
private final SparseArray<Runnable> mTimeoutActions;
private final HandlerThread mWorker;
+ private final Object mLock = new Object();
private boolean mEnabled = DEFAULT_ENABLED;
private int mSamplingInterval = DEFAULT_SAMPLING_INTERVAL;
@@ -276,6 +283,8 @@ public class InteractionJankMonitor {
CUJ_PIP_TRANSITION,
CUJ_WALLPAPER_TRANSITION,
CUJ_USER_SWITCH,
+ CUJ_SPLASHSCREEN_AVD,
+ CUJ_SPLASHSCREEN_EXIT_ANIM,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
@@ -325,6 +334,10 @@ public class InteractionJankMonitor {
mPropertiesChangedListener);
}
+ Object getLock() {
+ return mLock;
+ }
+
/**
* Creates a {@link FrameTracker} instance.
*
@@ -344,7 +357,7 @@ public class InteractionJankMonitor {
final ChoreographerWrapper choreographer =
new ChoreographerWrapper(Choreographer.getInstance());
- synchronized (this) {
+ synchronized (mLock) {
FrameTrackerListener eventsListener =
(s, act) -> handleCujEvents(config.getContext(), act, s);
return new FrameTracker(session, mWorker.getThreadHandler(),
@@ -364,7 +377,13 @@ public class InteractionJankMonitor {
// Notify the receivers if necessary.
if (session.shouldNotify()) {
- notifyEvents(context, action, session);
+ if (context != null) {
+ notifyEvents(context, action, session);
+ } else {
+ throw new IllegalArgumentException(
+ "Can't notify cuj events due to lack of context: cuj="
+ + session.getName() + ", action=" + action);
+ }
}
}
@@ -372,11 +391,16 @@ public class InteractionJankMonitor {
final boolean badEnd = action.equals(ACTION_SESSION_END)
&& session.getReason() != REASON_END_NORMAL;
final boolean badCancel = action.equals(ACTION_SESSION_CANCEL)
- && session.getReason() != REASON_CANCEL_NORMAL;
+ && !(session.getReason() == REASON_CANCEL_NORMAL
+ || session.getReason() == REASON_CANCEL_TIMEOUT);
return badEnd || badCancel;
}
- private void notifyEvents(Context context, String action, Session session) {
+ /**
+ * Notifies who may interest in some CUJ events.
+ */
+ @VisibleForTesting
+ public void notifyEvents(Context context, String action, Session session) {
if (action.equals(ACTION_SESSION_CANCEL)
&& session.getReason() == REASON_CANCEL_NOT_BEGUN) {
return;
@@ -389,7 +413,7 @@ public class InteractionJankMonitor {
}
private void removeTimeout(@CujType int cujType) {
- synchronized (this) {
+ synchronized (mLock) {
Runnable timeout = mTimeoutActions.get(cujType);
if (timeout != null) {
mWorker.getThreadHandler().removeCallbacks(timeout);
@@ -432,17 +456,9 @@ public class InteractionJankMonitor {
}
private boolean beginInternal(@NonNull Configuration conf) {
- synchronized (this) {
+ synchronized (mLock) {
int cujType = conf.mCujType;
- boolean shouldSample = ThreadLocalRandom.current().nextInt() % mSamplingInterval == 0;
- if (!mEnabled || !shouldSample) {
- if (DEBUG) {
- Log.d(TAG, "Skip monitoring cuj: " + getNameOfCuj(cujType)
- + ", enable=" + mEnabled + ", debuggable=" + DEFAULT_ENABLED
- + ", sample=" + shouldSample + ", interval=" + mSamplingInterval);
- }
- return false;
- }
+ if (!shouldMonitor(cujType)) return false;
FrameTracker tracker = getTracker(cujType);
// Skip subsequent calls if we already have an ongoing tracing.
if (tracker != null) return false;
@@ -460,6 +476,24 @@ public class InteractionJankMonitor {
}
/**
+ * Check if the monitoring is enabled and if it should be sampled.
+ */
+ @SuppressWarnings("RandomModInteger")
+ @VisibleForTesting
+ public boolean shouldMonitor(@CujType int cujType) {
+ boolean shouldSample = ThreadLocalRandom.current().nextInt() % mSamplingInterval == 0;
+ if (!mEnabled || !shouldSample) {
+ if (DEBUG) {
+ Log.d(TAG, "Skip monitoring cuj: " + getNameOfCuj(cujType)
+ + ", enable=" + mEnabled + ", debuggable=" + DEFAULT_ENABLED
+ + ", sample=" + shouldSample + ", interval=" + mSamplingInterval);
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
* Schedules a timeout action.
* @param cuj cuj type
* @param timeout duration to timeout
@@ -478,14 +512,16 @@ public class InteractionJankMonitor {
* @return boolean true if the tracker is ended successfully, false otherwise.
*/
public boolean end(@CujType int cujType) {
- synchronized (this) {
+ synchronized (mLock) {
// 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(REASON_END_NORMAL);
- removeTracker(cujType);
+ // if the end call doesn't return true, another thread is handling end of the cuj.
+ if (tracker.end(REASON_END_NORMAL)) {
+ removeTracker(cujType);
+ }
return true;
}
}
@@ -499,33 +535,37 @@ public class InteractionJankMonitor {
return cancel(cujType, REASON_CANCEL_NORMAL);
}
- boolean cancel(@CujType int cujType, @Reasons int reason) {
- synchronized (this) {
+ /**
+ * Cancels the trace session.
+ *
+ * @return boolean true if the tracker is cancelled successfully, false otherwise.
+ */
+ @VisibleForTesting
+ public boolean cancel(@CujType int cujType, @Reasons int reason) {
+ synchronized (mLock) {
// 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(reason);
- removeTracker(cujType);
+ // if the cancel call doesn't return true, another thread is handling cancel of the cuj.
+ if (tracker.cancel(reason)) {
+ removeTracker(cujType);
+ }
return true;
}
}
private FrameTracker getTracker(@CujType int cuj) {
- synchronized (this) {
- return mRunningTrackers.get(cuj);
- }
+ return mRunningTrackers.get(cuj);
}
private void removeTracker(@CujType int cuj) {
- synchronized (this) {
- mRunningTrackers.remove(cuj);
- }
+ mRunningTrackers.remove(cuj);
}
private void updateProperties(DeviceConfig.Properties properties) {
- synchronized (this) {
+ synchronized (mLock) {
mSamplingInterval = properties.getInt(SETTINGS_SAMPLING_INTERVAL_KEY,
DEFAULT_SAMPLING_INTERVAL);
mEnabled = properties.getBoolean(SETTINGS_ENABLED_KEY, DEFAULT_ENABLED);
@@ -547,10 +587,8 @@ public class InteractionJankMonitor {
*/
@VisibleForTesting
public void trigger(Session session) {
- synchronized (this) {
- mWorker.getThreadHandler().post(
- () -> PerfettoTrigger.trigger(session.getPerfettoTrigger()));
- }
+ mWorker.getThreadHandler().post(
+ () -> PerfettoTrigger.trigger(session.getPerfettoTrigger()));
}
/**
@@ -648,6 +686,10 @@ public class InteractionJankMonitor {
return "WALLPAPER_TRANSITION";
case CUJ_USER_SWITCH:
return "USER_SWITCH";
+ case CUJ_SPLASHSCREEN_AVD:
+ return "SPLASHSCREEN_AVD";
+ case CUJ_SPLASHSCREEN_EXIT_ANIM:
+ return "SPLASHSCREEN_EXIT_ANIM";
}
return "UNKNOWN";
}
@@ -703,7 +745,8 @@ public class InteractionJankMonitor {
* @return builder
*/
public static Builder withView(@CujType int cuj, @NonNull View view) {
- return new Builder(cuj).setView(view);
+ return new Builder(cuj).setView(view)
+ .setContext(view.getContext());
}
private Builder(@CujType int cuj) {
diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp
index d4ae6d769cf7..c1587eb2c4f4 100644
--- a/core/jni/android_graphics_BLASTBufferQueue.cpp
+++ b/core/jni/android_graphics_BLASTBufferQueue.cpp
@@ -112,11 +112,6 @@ static void nativeUpdate(JNIEnv* env, jclass clazz, jlong ptr, jlong surfaceCont
transaction);
}
-static void nativeFlushShadowQueue(JNIEnv* env, jclass clazz, jlong ptr) {
- sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
- queue->flushShadowQueue();
-}
-
static void nativeMergeWithNextTransaction(JNIEnv*, jclass clazz, jlong ptr, jlong transactionPtr,
jlong framenumber) {
sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
@@ -147,7 +142,6 @@ static const JNINativeMethod gMethods[] = {
{"nativeDestroy", "(J)V", (void*)nativeDestroy},
{"nativeSetNextTransaction", "(JJ)V", (void*)nativeSetNextTransaction},
{"nativeUpdate", "(JJJJIJ)V", (void*)nativeUpdate},
- {"nativeFlushShadowQueue", "(J)V", (void*)nativeFlushShadowQueue},
{"nativeMergeWithNextTransaction", "(JJJ)V", (void*)nativeMergeWithNextTransaction},
{"nativeSetTransactionCompleteCallback",
"(JJLandroid/graphics/BLASTBufferQueue$TransactionCompleteCallback;)V",
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 061ecc8f7488..c750eadf845a 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -202,7 +202,6 @@ message DisplayContentProto {
optional .com.android.server.wm.IdentifierProto resumed_activity = 24;
repeated TaskProto tasks = 25 [deprecated=true];
optional bool display_ready = 26;
-
optional WindowStateProto input_method_target = 27;
optional WindowStateProto input_method_input_target = 28;
optional WindowStateProto input_method_control_target = 29;
@@ -212,6 +211,8 @@ message DisplayContentProto {
optional DisplayRotationProto display_rotation = 33;
optional int32 ime_policy = 34;
+ optional bool is_sleeping = 36;
+ repeated string sleep_tokens = 37;
}
/* represents DisplayArea object */
diff --git a/core/res/OWNERS b/core/res/OWNERS
index 7a8da36d8a7d..bd192088e80d 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -25,3 +25,9 @@ svetoslavganov@google.com
toddke@google.com
tsuji@google.com
yamasani@google.com
+
+# Multiuser
+per-file res/xml/config_user_types.xml = file:/MULTIUSER_OWNERS
+
+# Car
+per-file res/values/dimens_car.xml = file:/platform/packages/services/Car:/OWNERS
diff --git a/core/res/res/layout/alert_dialog.xml b/core/res/res/layout/alert_dialog.xml
index 59e56af01b8d..6869c5fb7935 100644
--- a/core/res/res/layout/alert_dialog.xml
+++ b/core/res/res/layout/alert_dialog.xml
@@ -124,21 +124,21 @@
android:layout_width="0dip"
android:layout_gravity="start"
android:layout_weight="1"
- style="?android:attr/buttonBarButtonStyle"
+ style="?android:attr/buttonBarPositiveButtonStyle"
android:maxLines="2"
android:layout_height="wrap_content" />
<Button android:id="@+id/button3"
android:layout_width="0dip"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
- style="?android:attr/buttonBarButtonStyle"
+ style="?android:attr/buttonBarNeutralButtonStyle"
android:maxLines="2"
android:layout_height="wrap_content" />
<Button android:id="@+id/button2"
android:layout_width="0dip"
android:layout_gravity="end"
android:layout_weight="1"
- style="?android:attr/buttonBarButtonStyle"
+ style="?android:attr/buttonBarNegativeButtonStyle"
android:maxLines="2"
android:layout_height="wrap_content" />
<LinearLayout android:id="@+id/rightSpacer"
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index f9786ed3d3e0..25a0ec834316 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -236,7 +236,7 @@
<string name="shutdown_confirm" product="default" msgid="136816458966692315">"আপোনাৰ ফ\'নটো বন্ধ হ\'ব।"</string>
<string name="shutdown_confirm_question" msgid="796151167261608447">"আপুনি ফ\'নটোৰ পাৱাৰ অফ কৰিব বিচাৰেনে?"</string>
<string name="reboot_safemode_title" msgid="5853949122655346734">"সুৰক্ষিত ম\'ডলৈ ৰিবুট কৰক"</string>
- <string name="reboot_safemode_confirm" msgid="1658357874737219624">"আপুনি সুৰক্ষিত ম\'ডলৈ ৰিবুট কৰিব বিচাৰেনে? এই কার্যই আপুনি ইনষ্টল কৰা তৃতীয় পক্ষৰ সকলো এপ্লিকেশ্বন অক্ষম কৰিব। আপুনি পুনৰ ৰিবুট কৰিলে সেইবোৰ পুনঃস্থাপন কৰা হ\'ব।"</string>
+ <string name="reboot_safemode_confirm" msgid="1658357874737219624">"আপুনি সুৰক্ষিত ম\'ডলৈ ৰিবুট কৰিব বিচাৰেনে? এই কার্যই আপুনি ইনষ্টল কৰা তৃতীয় পক্ষৰ আটাইবোৰ এপ্লিকেশ্বন অক্ষম কৰিব। আপুনি পুনৰ ৰিবুট কৰিলে সেইবোৰ পুনঃস্থাপন কৰা হ\'ব।"</string>
<string name="recent_tasks_title" msgid="8183172372995396653">"শেহতীয়া"</string>
<string name="no_recent_tasks" msgid="9063946524312275906">"কোনো শেহতীয়া এপ্ নাই।"</string>
<string name="global_actions" product="tablet" msgid="4412132498517933867">"টে\'বলেটৰ বিকল্পসমূহ"</string>
@@ -255,7 +255,7 @@
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"ইণ্টাৰেক্টিভ অভিযোগ"</string>
<string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"বেছিভাগ পৰিস্থিতিত এয়া ব্যৱহাৰ কৰক। ই আপোনাক অভিযোগৰ অগ্ৰগতি ট্ৰেক কৰিবলৈ, সমস্যাটোৰ সম্পর্কে অধিক বিৱৰণ দিবলৈ আৰু স্ক্ৰীণশ্বট ল\'বলৈ অনুমতি দিয়ে। ই কম ব্যৱহাৰ হোৱা সেই শাখাসমূহক অন্তৰ্ভুক্ত নকৰিব পাৰে যিবোৰক অভিযোগ কৰিবলৈ দীৰ্ঘ সময়ৰ প্ৰয়োজন হয়।"</string>
<string name="bugreport_option_full_title" msgid="7681035745950045690">"সম্পূৰ্ণ অভিযোগ"</string>
- <string name="bugreport_option_full_summary" msgid="1975130009258435885">"যেতিয়া আপোনাৰ ডিভাইচটোৱে সঁহাৰি নিদিয়া হয় বা ই অতি লেহেমীয়া হৈ পৰে বা যেতিয়া আপোনাক সকলো অভিযোগৰ শাখাৰ প্ৰয়োজন হয় তেতিয়া ছিষ্টেমত কম হস্তক্ষেপৰ বাবে এই বিকল্প ব্যৱহাৰ কৰক। আপোনাক অধিক বিৱৰণ দিবলৈ বা অতিৰিক্ত স্ক্ৰীণশ্বট ল’বলৈ নিদিয়ে।"</string>
+ <string name="bugreport_option_full_summary" msgid="1975130009258435885">"যেতিয়া আপোনাৰ ডিভাইচটোৱে সঁহাৰি নিদিয়া হয় বা ই অতি লেহেমীয়া হৈ পৰে বা যেতিয়া আপোনাক আটাইবোৰ অভিযোগৰ শাখাৰ প্ৰয়োজন হয় তেতিয়া ছিষ্টেমত কম হস্তক্ষেপৰ বাবে এই বিকল্প ব্যৱহাৰ কৰক। আপোনাক অধিক বিৱৰণ দিবলৈ বা অতিৰিক্ত স্ক্ৰীণশ্বট ল’বলৈ নিদিয়ে।"</string>
<plurals name="bugreport_countdown" formatted="false" msgid="3906120379260059206">
<item quantity="one">ত্ৰুটি সম্পর্কীয় অভিযোগৰ বাবে <xliff:g id="NUMBER_1">%d</xliff:g>ছেকেণ্ডৰ ভিতৰত স্ক্ৰীণশ্বট লোৱা হ\'ব।</item>
<item quantity="other">ত্ৰুটি সম্পর্কীয় অভিযোগৰ বাবে <xliff:g id="NUMBER_1">%d</xliff:g>ছেকেণ্ডৰ ভিতৰত স্ক্ৰীণশ্বট লোৱা হ\'ব।</item>
@@ -371,9 +371,9 @@
<string name="permlab_sendSms" msgid="7757368721742014252">"এছএমএছ ৰ বার্তাবোৰ প্ৰেৰণ কৰিব আৰু চাব পাৰে"</string>
<string name="permdesc_sendSms" msgid="6757089798435130769">"এপটোক এছএমএছ বাৰ্তা পঠিয়াবলৈ অনুমতি দিয়ে৷ ইয়াৰ ফলত অপ্ৰত্যাশিত মাচুল ভৰিবলগা হ\'ব পাৰে৷ ক্ষতিকাৰক এপসমূহে আপোনাৰ অনুমতি নোলোৱাকৈয়ে বাৰ্তা পঠিয়াই আপোনাৰ পৰা মাচুল কাটিব পাৰে৷"</string>
<string name="permlab_readSms" msgid="5164176626258800297">"আপোনাৰ পাঠ বার্তাবোৰ পঢ়ক (এছএমএছ বা এমএমএছ)"</string>
- <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"এই এপটোৱে আপোনাৰ টেবলেটটোত সংৰক্ষিত সকলো এছএমএছ (পাঠ) বাৰ্তা পঢ়িব পাৰে।"</string>
- <string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"এই এপ্‌টোৱে আপোনাৰ Android TV ডিভাইচত ষ্ট’ৰ কৰি ৰখা সকলো এছএমএছ (পাঠ) বাৰ্তা পঢ়িব পাৰে।"</string>
- <string name="permdesc_readSms" product="default" msgid="774753371111699782">"এই এপটোৱে আপোনাৰ ফ\'নত সংৰক্ষিত সকলো এছএমএছ (পাঠ) বাৰ্তা পঢ়িব পাৰে।"</string>
+ <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"এই এপ্‌টোৱে আপোনাৰ টেবলেটটোত সংৰক্ষিত আটাইবোৰ এছএমএছ (পাঠ) বাৰ্তা পঢ়িব পাৰে।"</string>
+ <string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"এই এপ্‌টোৱে আপোনাৰ Android TV ডিভাইচত ষ্ট’ৰ কৰি ৰখা আটাইবোৰ এছএমএছ (পাঠ) বাৰ্তা পঢ়িব পাৰে।"</string>
+ <string name="permdesc_readSms" product="default" msgid="774753371111699782">"এই এপ্‌টোৱে আপোনাৰ ফ\'নত সংৰক্ষিত আটাইবোৰ এছএমএছ (পাঠ) বাৰ্তা পঢ়িব পাৰে।"</string>
<string name="permlab_receiveWapPush" msgid="4223747702856929056">"পাঠ বার্তা (WAP) বোৰ লাভ কৰক"</string>
<string name="permdesc_receiveWapPush" msgid="1638677888301778457">"এপটোক WAP বাৰ্তাবোৰ পাবলৈ আৰু প্ৰক্ৰিয়া সম্পন্ন কৰিবলৈ অনুমতি দিয়ে৷ এই অনুমতিত আপোনালৈ পঠিওৱা বাৰ্তাবোৰ আপোনাক নেদেখুৱাকৈয়ে নিৰীক্ষণ বা মচাৰ সক্ষমতা অন্তৰ্ভুক্ত থাকে৷"</string>
<string name="permlab_getTasks" msgid="7460048811831750262">"চলি থকা এপসমূহ বিচাৰি উলিয়াওক"</string>
@@ -427,9 +427,9 @@
<string name="permlab_bodySensors" msgid="3411035315357380862">"শৰীৰৰ ছেন্সৰসমূহ (যেনে হৃদপিণ্ডৰ গতিৰ হাৰ নিৰীক্ষক) ব্যৱহাৰ কৰিব পাৰে"</string>
<string name="permdesc_bodySensors" product="default" msgid="2365357960407973997">"আপোনাৰ হৃদস্পন্দনৰ দৰে শাৰীৰিক অৱস্থাক নিৰীক্ষণ কৰা ছেন্সৰৰ পৰা ডেটা লাভ কৰিবলৈ এপক অনুমতি দিয়ে।"</string>
<string name="permlab_readCalendar" msgid="6408654259475396200">"কেলেণ্ডাৰৰ কাৰ্যক্ৰম আৰু সবিশেষ পঢ়িব পাৰে"</string>
- <string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"এই এপটোৱে আপোনাৰ টেবলেটটোত সংৰক্ষিত সকলো কেলেণ্ডাৰ কাৰ্যক্ৰম পঢ়িব পাৰে আৰু আপোনাৰ কেলেণ্ডাৰৰ ডেটা শ্বেয়াৰ বা ছেভ কৰিব পাৰে।"</string>
- <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"এই এপ্‌টোৱে আপোনাৰ Android TV ডিভাইচটোত ষ্ট’ৰ কৰি ৰখা সকলো কেলেণ্ডাৰৰ অনুষ্ঠান পঢ়িব পাৰে আৰু আপোনাৰ কেলেণ্ডাৰৰ ডেটা শ্বেয়াৰ অথবা ছেভ কৰিব পাৰে।"</string>
- <string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"এই এপটোৱে আপোনাৰ ফ\'নটোত সংৰক্ষিত সকলো কেলেণ্ডাৰ কাৰ্যক্ৰম পঢ়িব পাৰে আৰু আপোনাৰ কেলেণ্ডাৰৰ ডেটা শ্বেয়াৰ বা ছেভ কৰিব পাৰে।"</string>
+ <string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"এই এপ্‌টোৱে আপোনাৰ টেবলেটটোত সংৰক্ষিত আটাইবোৰ কেলেণ্ডাৰ কাৰ্যক্ৰম পঢ়িব পাৰে আৰু আপোনাৰ কেলেণ্ডাৰৰ ডেটা শ্বেয়াৰ বা ছেভ কৰিব পাৰে।"</string>
+ <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"এই এপ্‌টোৱে আপোনাৰ Android TV ডিভাইচটোত ষ্ট’ৰ কৰি ৰখা আটাইবোৰ কেলেণ্ডাৰৰ অনুষ্ঠান পঢ়িব পাৰে আৰু আপোনাৰ কেলেণ্ডাৰৰ ডেটা শ্বেয়াৰ অথবা ছেভ কৰিব পাৰে।"</string>
+ <string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"এই এপ্‌টোৱে আপোনাৰ ফ\'নটোত সংৰক্ষিত আটাইবোৰ কেলেণ্ডাৰ কাৰ্যক্ৰম পঢ়িব পাৰে আৰু আপোনাৰ কেলেণ্ডাৰৰ ডেটা শ্বেয়াৰ বা ছেভ কৰিব পাৰে।"</string>
<string name="permlab_writeCalendar" msgid="6422137308329578076">"গৰাকীয়ে নজনাকৈয়ে কেলেণ্ডাৰৰ কাৰ্যক্ৰম সংশোধন কৰি অতিথিসকললৈ ইমেইল প্ৰেৰণ কৰক"</string>
<string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"এই এপটোৱে আপোনাৰ টেবলেটত কেলেণ্ডাৰ কাৰ্যক্ৰম যোগ কৰিব, আঁতৰাব বা সলনি কৰিব পাৰে। ই এনে বাৰ্তা পঠিয়াব পাৰে যিবোৰ কেলেণ্ডাৰৰ গৰাকীৰ পৰা অহা যেন লাগিব বা ই গৰাকীক নজনোৱাকৈ কাৰ্যক্ৰম সলনি কৰিব পাৰে৷"</string>
<string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"এই এপ্‌টোৱে আপোনাৰ Android TV ডিভাইচত কেলেণ্ডাৰ অনুষ্ঠানবোৰ যোগ দিব, আঁতৰাব অথবা সলনি কৰিব পাৰে। এই এপ্‌টোৱে এনে বাৰ্তা পঠিয়াব পাৰে যিবোৰ কেলেণ্ডাৰৰ গৰাকীৰ পৰা অহা বুলি প্ৰদর্শিত হ’ব পাৰে অথবা এইটোৱে গৰাকীসকলক নজনোৱাকৈ অনুষ্ঠানবোৰ সলনি কৰিব পাৰে।"</string>
@@ -516,9 +516,9 @@
<string name="permlab_changeWifiState" msgid="7947824109713181554">"ৱাই-ফাই সংযোগ কৰক আৰু ইয়াৰ সংযোগ বিচ্ছিন্ন কৰক"</string>
<string name="permdesc_changeWifiState" msgid="7170350070554505384">"এপটোক ৱাই-ফাই এক্সেছ পইণ্টলৈ সংযোগ কৰিবলৈ আৰু তাৰ সংযোগ বিচ্ছিন্ন কৰিবলৈ আৰু ৱাই-ফাই নেটৱৰ্কসমূহৰ বাবে ডিভাইচ কনফিগাৰেশ্বনত সাল-সলনি কৰিবলৈ অনুমতি দিয়ে৷"</string>
<string name="permlab_changeWifiMulticastState" msgid="285626875870754696">"ৱাই-ফাই মাল্টিকাষ্ট প্ৰচাৰৰ অনুমতি দিয়ক"</string>
- <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"আপোনাৰ টেবলেটৰ লগতে মাল্টিকাষ্ট ঠিকনাবোৰ ও ব্যৱহাৰ কৰি এপক ৱাই-ফাই নেটৱর্কত থকা সকলো ডিভাইচলৈ পঠোৱা পেকেট প্ৰাপ্ত কৰিবলৈ অনুমতি দিয়ে। এই কার্যই ন\'ন মাল্টিকাষ্ট ম\'ডতকৈ বেটাৰিৰ অধিক চ্চাৰ্জ ব্যৱহাৰ কৰে।"</string>
- <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"কেৱল আপোনাৰ Android TV ডিভাইচটোৱেই নহয়, মাল্টিকাষ্ট ঠিকনাবোৰ ব্যৱহাৰ কৰি এটা ৱাই-ফাই নেটৱর্কত থকা সকলো ডিভাইচলৈ পঠোৱা পেকেটবোৰ লাভ কৰিবলৈ এপ্‌টোক অনুমতি দিয়ে। এই কার্যই ন’ন-মাল্টিকাষ্ট ম’ডতকৈ অধিক পাৱাৰ ব্যৱহাৰ কৰে।"</string>
- <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"আপোনাৰ ফ\'নৰ লগতে মাল্টিকাষ্ট ঠিকনাবোৰ ও ব্যৱহাৰ কৰি এপক ৱাই-ফাই নেটৱর্কত থকা সকলো ডিভাইচলৈ পঠোৱা পেকেট প্ৰাপ্ত কৰিবলৈ অনুমতি দিয়ে। এই কার্যই ন\'ন মাল্টিকাষ্ট ম\'ডতকৈ বেটাৰিৰ অধিক চ্চাৰ্জ ব্যৱহাৰ কৰে।"</string>
+ <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"কেৱল আপোনাৰ টেবলেটটোৱেই নহয়, মাল্টিকাষ্ট ঠিকনা ব্যৱহাৰ কৰি এটা ৱাই-ফাই নেটৱর্কত থকা আটাইবোৰ ডিভাইচলৈ পঠিওৱা পেকেট লাভ কৰিবলৈ এপ্‌টোক অনুমতি দিয়ে। এই কার্যই নন মাল্টিকাষ্ট ম\'ডতকৈ অধিক বেটাৰী ব্যৱহাৰ কৰে।"</string>
+ <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"কেৱল আপোনাৰ Android TV ডিভাইচটোৱেই নহয়, মাল্টিকাষ্ট ঠিকনাবোৰ ব্যৱহাৰ কৰি এটা ৱাই-ফাই নেটৱর্কত থকা আটাইবোৰ ডিভাইচলৈ পঠিওৱা পেকেট লাভ কৰিবলৈ এপ্‌টোক অনুমতি দিয়ে। এই কার্যই নন-মাল্টিকাষ্ট ম’ডতকৈ অধিক পাৱাৰ ব্যৱহাৰ কৰে।"</string>
+ <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"আপোনাৰ ফ\'নৰ লগতে ৱাই-ফাই নেটৱর্কত থকা আটাইবোৰ ডিভাইচলৈ মাল্টিকাষ্ট ঠিকনা ব্যৱহাৰ কৰি পঠিওৱা পেকেট লাভ কৰিবলৈ এপক অনুমতি দিয়ে। এই কার্যই নন-মাল্টিকাষ্ট ম\'ডতকৈ বেটাৰীৰ অধিক চাৰ্জ ব্যৱহাৰ কৰে।"</string>
<string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"ব্লুটুথ ছেটিং এক্সেছ কৰক"</string>
<string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"স্থানীয় ব্লুটুথ টে\'বলেট কনফিগাৰ কৰিবলৈ আৰু দূৰৱৰ্তী ডিভাইচসমূহৰ সৈতে যোৰা লগাবলৈ আৰু বিচাৰি উলিয়াবলৈ এপটোক অনুমতি দিয়ে।"</string>
<string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"এপ্‌টোক আপোনাৰ Android TV ডিভাইচটোত ব্লুটুথ কনফিগাৰ কৰিবলৈ আৰু ৰিম’ট ডিভাইচসমূহ বিচাৰি উলিয়াবলৈ আৰু পেয়াৰ কৰিবলৈ অনুমতি দিয়ে।"</string>
@@ -737,7 +737,7 @@
<string name="policydesc_resetPassword" msgid="4626419138439341851">"স্ক্ৰীন লক সলনি কৰক।"</string>
<string name="policylab_forceLock" msgid="7360335502968476434">"স্ক্ৰীনখন লক কৰক"</string>
<string name="policydesc_forceLock" msgid="1008844760853899693">"স্ক্ৰীন কেনেকৈ আৰু কেতিয়া লক হয় সেয়া নিয়ন্ত্ৰণ কৰক।"</string>
- <string name="policylab_wipeData" msgid="1359485247727537311">"সকলো ডেটা মচক"</string>
+ <string name="policylab_wipeData" msgid="1359485247727537311">"আটাইবোৰ ডেটা মচক"</string>
<string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"সতৰ্কবাণী প্ৰেৰণ নকৰাকৈয়ে ফেক্টৰী ডেটা ৰিছেট কৰি টেবলেটৰ ডেটা মচক।"</string>
<string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"কোনো সতর্কবার্তা নপঠিওৱাকৈ ফেক্টৰী ডেটা ৰিছেট কৰি আপোনাৰ Android TV ডিভাইচৰ ডেটা মচক।"</string>
<string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"সতৰ্কবাণী প্ৰেৰণ নকৰাকৈয়ে ফেক্টৰী ডেটা ৰিছেট কৰি ফ\'নৰ ডেটা মচক।"</string>
@@ -752,7 +752,7 @@
<string name="policylab_encryptedStorage" msgid="9012936958126670110">"সঞ্চয়াগাৰৰ এনক্ৰিপশ্বন ছেট কৰক"</string>
<string name="policydesc_encryptedStorage" msgid="1102516950740375617">"সঞ্চয় কৰি ৰখা ডেটাক এনক্ৰিপ্ট কৰাৰ প্ৰয়োজন।"</string>
<string name="policylab_disableCamera" msgid="5749486347810162018">"কেমেৰাবোৰ অক্ষম কৰক"</string>
- <string name="policydesc_disableCamera" msgid="3204405908799676104">"সকলো ডিভাইচৰ কেমেৰাবোৰ ব্যৱহাৰ কৰাত বাধা দিয়ক।"</string>
+ <string name="policydesc_disableCamera" msgid="3204405908799676104">"আটাইবোৰ ডিভাইচৰ কেমেৰা ব্যৱহাৰ কৰাত বাধা দিয়ক।"</string>
<string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"স্ক্ৰীন লকৰ কিছুমান সুবিধা অক্ষম কৰক"</string>
<string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"স্ক্ৰীন লকৰ কিছুমান সুবিধা ব্যৱহাৰ হোৱাত বাধা দিয়ক।"</string>
<string-array name="phoneTypes">
@@ -889,7 +889,7 @@
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"শুদ্ধ!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"আকৌ চেষ্টা কৰক"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"আকৌ চেষ্টা কৰক"</string>
- <string name="lockscreen_storage_locked" msgid="634993789186443380">"সকলো সুবিধা আৰু ডেটাৰ বাবে আনলক কৰক"</string>
+ <string name="lockscreen_storage_locked" msgid="634993789186443380">"আটাইবোৰ সুবিধা আৰু ডেটাৰ বাবে আনলক কৰক"</string>
<string name="faceunlock_multiple_failures" msgid="681991538434031708">"গৰাকীৰ ফেচ আনলক কৰা সৰ্বাধিক সীমা অতিক্ৰম কৰা হ’ল"</string>
<string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"কোনো ছিম কাৰ্ড নাই"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"টে\'বলেটত ছিম কার্ড নাই।"</string>
@@ -918,9 +918,9 @@
<string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"আপুনি অশুদ্ধভাৱে আপোনাৰ লক খোলাৰ আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ আঁকিলে৷ <xliff:g id="NUMBER_1">%2$d</xliff:g> তকৈ অধিকবাৰ অসফলভাৱে কৰা প্ৰয়াসৰ পিছত, আপোনাৰ ফ\'নটো আনলক কৰিবৰ বাবে Google ছাইন ইনৰ জৰিয়তে কাৰ্যটো কৰিবলৈ কোৱা হ\'ব৷\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পিছত পুনৰ চেষ্টা কৰক৷"</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"আপুনি নিজৰ আনলক আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g>বাৰ ভুলকৈ দিলে। আকৌ <xliff:g id="NUMBER_1">%2$d</xliff:g>বাৰ ভুলকৈ প্ৰয়াস কৰাৰ পাছত আপোনাক নিজৰ Google ছাইন ইন ব্যৱহাৰ কৰি আপোনাৰ Android TV ডিভাইচটো আনলক কৰিবলৈ কোৱা হ’ব।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g>ছেকেণ্ডৰ পাছত পুনৰ চেষ্টা কৰক।"</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"আপুনি অশুদ্ধভাৱে আপোনাৰ লক খোলাৰ আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ আঁকিলে৷ <xliff:g id="NUMBER_1">%2$d</xliff:g> তকৈ অধিকবাৰ অসফলভাৱে কৰা প্ৰয়াসৰ পিছত, আপোনাৰ ফ\'নটো আনলক কৰিবৰ বাবে Google ছাইন ইনৰ জৰিয়তে কাৰ্যটো কৰিবলৈ কোৱা হ\'ব৷\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পিছত পুনৰ চেষ্টা কৰক৷"</string>
- <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"আপুনি টে\'বলেটটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আনলক কৰিবলৈ প্ৰয়াস কৰিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰতকৈ বেছি প্ৰয়াস কৰিলে টে\'বলেটটো ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব আৰু সকলো ব্যৱহাৰকাৰী ডেটা হেৰুৱাব।"</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"আপুনি টে\'বলেটটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আনলক কৰিবলৈ প্ৰয়াস কৰিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰতকৈ বেছি প্ৰয়াস কৰিলে টে\'বলেটটো ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব আৰু আটাইবোৰ ব্যৱহাৰকাৰী ডেটা হেৰুৱাব।"</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"আপুনি নিজৰ Android TV ডিভাইচটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g>বাৰ ভুলকৈ প্ৰয়াস কৰিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুলকৈ প্ৰয়াস কৰাৰ পাছত আপোনাৰ Android TV ডিভাইচটো ফেক্টৰী ডিফ’ল্টলৈ ৰিছেট কৰা হ’ব আৰু ব্যৱহাৰকাৰীৰ সকলো ডেটা হেৰুৱাব।"</string>
- <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"আপুনি ফ\'নটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আনলক কৰিবলৈ প্ৰয়াস কৰিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰতকৈ বেছি প্ৰয়াস কৰিলে ফ\'নটো ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব আৰু সকলো ব্যৱহাৰকাৰী ডেটা হেৰুৱাব।"</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"আপুনি ফ\'নটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আনলক কৰিবলৈ প্ৰয়াস কৰিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰতকৈ বেছি প্ৰয়াস কৰিলে ফ\'নটো ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব আৰু আটাইবোৰ ব্যৱহাৰকাৰী ডেটা হেৰুৱাব।"</string>
<string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="8682445539263683414">"আপুনি অশুদ্ধভাৱে টে\'বলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ চেষ্টা কৰিছিল। টে\'বলেটটো এতিয়া ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব।"</string>
<string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="2205435033340091883">"আপুনি নিজৰ Android TV ডিভাইচটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g>বাৰ ভুলকৈ প্ৰয়াস কৰিছে। আপোনাৰ Android TV ডিভাইচটো এতিয়া ফেক্টৰী ডিফ’ল্টলৈ ৰিছেট কৰা হ’ব।"</string>
<string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="2203704707679895487">"আপুনি অশুদ্ধভাৱে ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ চেষ্টা কৰিছিল। ফ\'নটো এতিয়া ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব।"</string>
@@ -1006,7 +1006,7 @@
<string name="autofill_area" msgid="8289022370678448983">"ক্ষেত্ৰ"</string>
<string name="autofill_emirate" msgid="2544082046790551168">"এমিৰেট"</string>
<string name="permlab_readHistoryBookmarks" msgid="9102293913842539697">"আপোনাৰ ৱেব বুকমার্কবোৰ আৰু ইতিহাস পঢ়ক"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="2323799501008967852">"ব্ৰাউজাৰৰ বুকমার্ক আৰু ব্ৰাউজাৰে ব্যৱহাৰ কৰা সকলো URLৰ ইতিহাস পঢ়িবলৈ এপক অনুমতি দিয়ে। টোকা: এই অনুমতি তৃতীয় পক্ষৰ ব্ৰাউজাৰবোৰ বা ৱেব ব্ৰাউজিং কৰিব পৰা অন্য এপ্লিকেশ্বনবোৰৰ দ্বাৰা বলৱৎ নহ\'বও পাৰে।"</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="2323799501008967852">"ব্ৰাউজাৰৰ বুকমার্ক আৰু ব্ৰাউজাৰে ব্যৱহাৰ কৰা আটাইবোৰ URLৰ ইতিহাস পঢ়িবলৈ এপক অনুমতি দিয়ে। টোকা: এই অনুমতি তৃতীয় পক্ষৰ ব্ৰাউজাৰবোৰ বা ৱেব ব্ৰাউজিং কৰিব পৰা অন্য এপ্লিকেশ্বনবোৰৰ দ্বাৰা বলৱৎ নহ\'বও পাৰে।"</string>
<string name="permlab_writeHistoryBookmarks" msgid="6090259925187986937">"আপোনাৰ ৱেব বুকমার্কবোৰ আৰু ইতিহাস লিখক"</string>
<string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"আপোনাৰ টেবলেটত সঞ্চয় কৰি ৰখা ব্ৰাউজাৰৰ বুকমার্ক আৰু ব্ৰাউজাৰৰ ইতিহাস সংশোধন কৰিবলৈ এপক অনুমতি দিয়ে। টোকা: এই অনুমতি তৃতীয় পক্ষৰ ব্ৰাউজাৰবোৰ বা ৱেব ব্ৰাউজিং কৰিব পৰা অন্য এপ্লিকেশ্বনবোৰৰ দ্বাৰা বলৱৎ নহ\'বও পাৰে।"</string>
<string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"এপ্‌টোক আপোনাৰ Android TV ডিভাইচত ষ্ট’ৰ কৰি ৰখা ব্ৰাউজাৰৰ ইতিহাস আৰু বুকমার্কবোৰ সংশোধন কৰিবলৈ অনুমতি দিয়ে। ব্ৰাউজাৰ ডাটা মোহাৰিবলৈ অথবা সংশোধন কৰিবলৈ ই এপ্‌টোক অনুমতি দিব পাৰে। টোকা: এই অনুমতি তৃতীয় পক্ষৰ ব্ৰাউজাৰবোৰ অথবা ৱেব ব্ৰাউজিঙৰ ক্ষমতা থকা অন্য এপ্লিকেশ্বনবোৰৰ দ্বাৰা বলৱৎ কৰা নহ’বও পাৰে।"</string>
@@ -1149,7 +1149,7 @@
<string name="Midnight" msgid="8176019203622191377">"মাজনিশা"</string>
<string name="elapsed_time_short_format_mm_ss" msgid="8689459651807876423">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="2302144714803345056">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="1532369154488982046">"সকলো বাছনি কৰক"</string>
+ <string name="selectAll" msgid="1532369154488982046">"আটাইবোৰ বাছনি কৰক"</string>
<string name="cut" msgid="2561199725874745819">"কাটক"</string>
<string name="copy" msgid="5472512047143665218">"প্ৰতিলিপি কৰক"</string>
<string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"ক্লিপব\'ৰ্ডত প্ৰতিলিপি কৰিব পৰা নগ\'ল"</string>
@@ -1610,7 +1610,7 @@
<string name="fingerprints" msgid="148690767172613723">"ফিংগাৰপ্ৰিণ্ট:"</string>
<string name="sha256_fingerprint" msgid="7103976380961964600">"SHA-256 ফিংগাৰপ্ৰিণ্ট:"</string>
<string name="sha1_fingerprint" msgid="2339915142825390774">"SHA-1 ফিংগাৰপ্ৰিণ্ট:"</string>
- <string name="activity_chooser_view_see_all" msgid="3917045206812726099">"সকলো চাওক"</string>
+ <string name="activity_chooser_view_see_all" msgid="3917045206812726099">"আটাইবোৰ চাওক"</string>
<string name="activity_chooser_view_dialog_title_default" msgid="8880731437191978314">"কাৰ্যকলাপ বাছনি কৰক"</string>
<string name="share_action_provider_share_with" msgid="1904096863622941880">"ইয়াৰ জৰিয়তে শ্বেয়াৰ কৰক"</string>
<string name="sending" msgid="206925243621664438">"পঠিয়াই থকা হৈছে…"</string>
@@ -1677,9 +1677,9 @@
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"আপুনি আপোনাৰ পিন <xliff:g id="NUMBER_0">%1$d</xliff:g>বাৰ ভুলকৈ লিখিছে। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g>ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"আপুনি আপোনাৰ পাছৱৰ্ড <xliff:g id="NUMBER_0">%1$d</xliff:g>বাৰ ভুলকৈ লিখিছে। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="7357404233979139075">"আপুনি আপোনাৰ ল\'ক খোলাৰ আৰ্হি <xliff:g id="NUMBER_0">%1$d</xliff:g>বাৰ ভুলকৈ আঁকিছে। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g>ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"আপুনি <xliff:g id="NUMBER_0">%1$d</xliff:g>বাৰ ভুলকৈ টেবলেটৰ ল\'ক খোলাৰ প্ৰয়াস কৰিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুল প্ৰয়াস কৰিলে টেবলেটটো ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব আৰু সকলো ব্যৱহাৰকাৰীৰ ডেটা হেৰুৱাব।"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="9064457748587850217">"আপুনি নিজৰ Android TV ডিভাইচটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g>বাৰ ভুলকৈ প্ৰয়াস কৰিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুলকৈ প্ৰয়াস কৰাৰ পাছত আপোনাৰ Android TV ডিভাইচটো ফেক্টৰী ডিফ’ল্টলৈ ৰিছেট কৰা হ’ব আৰু ব্যৱহাৰকাৰীৰ সকলো ডেটা হেৰুৱাব।"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"আপুনি <xliff:g id="NUMBER_0">%1$d</xliff:g>বাৰ ভুলকৈ ফ\'নৰ ল\'ক খোলাৰ প্ৰয়াস কৰিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুল প্ৰয়াস কৰিলে ফ\'নটো ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব আৰু সকলো ব্যৱহাৰকাৰীৰ ডেটা হেৰুৱাব।"</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"আপুনি <xliff:g id="NUMBER_0">%1$d</xliff:g>বাৰ ভুলকৈ টেবলেটৰ ল\'ক খোলাৰ প্ৰয়াস কৰিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুল প্ৰয়াস কৰিলে টেবলেটটো ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব আৰু আটাইবোৰ ব্যৱহাৰকাৰীৰ ডেটা হেৰুৱাব।"</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="9064457748587850217">"আপুনি নিজৰ Android TV ডিভাইচটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g>বাৰ ভুলকৈ প্ৰয়াস কৰিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুলকৈ প্ৰয়াস কৰাৰ পাছত আপোনাৰ Android TV ডিভাইচটো ফেক্টৰী ডিফ’ল্টলৈ ৰিছেট কৰা হ’ব আৰু ব্যৱহাৰকাৰীৰ আটাইবোৰ ডেটা হেৰুৱাব।"</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"আপুনি <xliff:g id="NUMBER_0">%1$d</xliff:g>বাৰ ভুলকৈ ফ\'নৰ ল\'ক খোলাৰ প্ৰয়াস কৰিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুল প্ৰয়াস কৰিলে ফ\'নটো ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব আৰু ব্যৱহাৰকাৰীৰ আটাইবোৰ ডেটা হেৰুৱাব।"</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"আপুনি <xliff:g id="NUMBER">%d</xliff:g>বাৰ ভুলকৈ টেবলেটৰ ল\'ক খোলাৰ প্ৰয়াস কৰিছে। টেবলেটটো এতিয়া ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব।"</string>
<string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"আপুনি নিজৰ Android TV ডিভাইচটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g>বাৰ ভুলকৈ প্ৰয়াস কৰিছে। আপোনাৰ Android TV ডিভাইচটো এতিয়া ফেক্টৰী ডিফ’ল্টলৈ ৰিছেট কৰা হ’ব।"</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"আপুনি <xliff:g id="NUMBER">%d</xliff:g>বাৰ ভুলকৈ ফ\'নৰ ল\'ক খোলাৰ প্ৰয়াস কৰিছে। ফ\'নটো এতিয়া ফেক্টৰী ডিফ\'ল্টলৈ ৰিছেট কৰা হ\'ব।"</string>
@@ -1973,7 +1973,7 @@
<string name="search_language_hint" msgid="7004225294308793583">"ভাষাৰ নাম লিখক"</string>
<string name="language_picker_section_suggested" msgid="6556199184638990447">"প্ৰস্তাৱিত"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"সকলো ভাষা"</string>
- <string name="region_picker_section_all" msgid="756441309928774155">"সকলো অঞ্চল"</string>
+ <string name="region_picker_section_all" msgid="756441309928774155">"আটাইবোৰ অঞ্চল"</string>
<string name="locale_search_menu" msgid="6258090710176422934">"সন্ধান কৰক"</string>
<string name="app_suspended_title" msgid="888873445010322650">"এপটো নাই"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"এই মুহূৰ্তত <xliff:g id="APP_NAME_0">%1$s</xliff:g> উপলব্ধ নহয়। ইয়াক <xliff:g id="APP_NAME_1">%2$s</xliff:g>এ পৰিচালনা কৰে।"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 96d0662e729f..78ec66185bcc 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -981,7 +981,7 @@
<string name="js_dialog_title" msgid="7464775045615023241">"\'<xliff:g id="TITLE">%s</xliff:g>\' 페이지 내용:"</string>
<string name="js_dialog_title_default" msgid="3769524569903332476">"자바스크립트"</string>
<string name="js_dialog_before_unload_title" msgid="7012587995876771246">"탐색 확인"</string>
- <string name="js_dialog_before_unload_positive_button" msgid="4274257182303565509">"이 페이지 닫기"</string>
+ <string name="js_dialog_before_unload_positive_button" msgid="4274257182303565509">"이 페이지 나가기"</string>
<string name="js_dialog_before_unload_negative_button" msgid="3873765747622415310">"이 페이지에 머무르기"</string>
<string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\n다른 페이지로 이동하시겠습니까?"</string>
<string name="save_password_label" msgid="9161712335355510035">"확인"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 10fd2e131622..886f1eecb03d 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -48,7 +48,7 @@
<string name="invalidPin" msgid="7542498253319440408">"နံပါတ်(၄)ခုမှ(၈)ခုအထိပါရှိသော ပင်နံပါတ်အားထည့်ပါ"</string>
<string name="invalidPuk" msgid="8831151490931907083">"နံပါတ်(၈)ခုသို့မဟုတ် ထိုထက်ရှည်သောသော PUKအားထည့်သွင်းပါ"</string>
<string name="needPuk" msgid="7321876090152422918">"ဆင်းမ်ကတ် ရဲ့ ပင်နံပါတ် ပြန်ဖွင့်သည့် ကုဒ် သော့ကျနေပါသည်။ ဖွင့်ရန် ကုဒ်အားထည့်သွင်းပါ။"</string>
- <string name="needPuk2" msgid="7032612093451537186">"ဆင်းမ်ကဒ်အားမပိတ်ရန် PUK2အားထည့်သွင်းပါ"</string>
+ <string name="needPuk2" msgid="7032612093451537186">"ဆင်းမ်ကတ်အားမပိတ်ရန် PUK2 အားထည့်သွင်းပါ"</string>
<string name="enablePin" msgid="2543771964137091212">"မအောင်မြင်ပါ, SIM/RUIM သော့ကို အရင် သုံးခွင့်ပြုရန်"</string>
<plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
<item quantity="other">ဆင်းမ်ကတ် သော့မချခင် သင့်တွင် <xliff:g id="NUMBER_1">%d</xliff:g> ခါ ကြိုးစားခွင့်များကျန်ပါသေးသည်။</item>
@@ -331,7 +331,7 @@
<string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"တို့ထိခြင်းဖြင့် ရှာဖွေမှုကို ဖွင့်ရန်"</string>
<string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"တို့လိုက်သည့်အရာများကို အသံထွက်ဖတ်ပေးပါလိမ့်မည်။ လက်ဟန်အမူအရာများကို အသုံးပြု၍ မျက်နှာပြင်ကို လေ့လာနိုင်ပါသည်။"</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"ရိုက်သောစာများကို စောင့်ကြည့်ရန်"</string>
- <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"ကိုယ်ရေးအချက်အလက်များဖြစ်သော ခရက်ဒစ်ကဒ်နံပါတ်နှင့် စကားဝှက်များ ပါဝင်သည်။"</string>
+ <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"ကိုယ်ရေးအချက်အလက်များဖြစ်သော ခရက်ဒစ်ကတ်နံပါတ်နှင့် စကားဝှက်များ ပါဝင်သည်။"</string>
<string name="capability_title_canControlMagnification" msgid="7701572187333415795">"မျက်နှာပြင် ချဲ့ခြင်းကို ထိန်းချုပ်ရန်"</string>
<string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"မျက်နှာပြင် ဇူးမ်အရွယ်နှင့် နေရာချထားခြင်းကို ထိန်းချုပ်ပါသည်။"</string>
<string name="capability_title_canPerformGestures" msgid="9106545062106728987">"လက်ဟန်များ အသုံးပြုပါ"</string>
@@ -891,13 +891,13 @@
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"ထပ် စမ်းပါ"</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"ဝန်ဆောင်မှုနှင့် ဒေတာအားလုံးအတွက် လော့ခ်ဖွင့်ပါ"</string>
<string name="faceunlock_multiple_failures" msgid="681991538434031708">"မျက်မှာပြ လော့ခ်ဖွင့်ခြင်း ခွင့်ပြုသော အကြိမ်ရေထက် ကျော်လွန်သွားပါပြီ"</string>
- <string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"ဆင်းကဒ် မရှိပါ"</string>
- <string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"တက်ပလက်ထဲတွင်း ဆင်းကဒ် မရှိပါ"</string>
+ <string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"ဆင်းမ်ကတ် မရှိပါ"</string>
+ <string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"တက်ဘလက်ထဲတွင်း ဆင်းမ်ကတ်မရှိပါ"</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"သင့် Android TV စက်ပစ္စည်းပေါ်တွင် ဆင်းမ်ကတ်မရှိပါ။"</string>
- <string name="lockscreen_missing_sim_message" product="default" msgid="1408695081255172556">"ဖုန်းထဲတွင် ဆင်းကဒ် မရှိပါ"</string>
+ <string name="lockscreen_missing_sim_message" product="default" msgid="1408695081255172556">"ဖုန်းထဲတွင် ဆင်းကတ်မရှိပါ"</string>
<string name="lockscreen_missing_sim_instructions" msgid="8473601862688263903">"ဆင်းမ်ကတ် ထည့်ပါ"</string>
<string name="lockscreen_missing_sim_instructions_long" msgid="3664999892038416334">"ဆင်းမ်ကတ် မရှိဘူး သို့မဟုတ် ဖတ်မရပါ။ ဆင်းမ်ကတ် တစ်ခုကို ထည့်ပါ။"</string>
- <string name="lockscreen_permanent_disabled_sim_message_short" msgid="3812893366715730539">"သုံးစွဲ မရတော့သော ဆင်းကဒ်"</string>
+ <string name="lockscreen_permanent_disabled_sim_message_short" msgid="3812893366715730539">"သုံး၍ မရတော့သော ဆင်းမ်ကတ်"</string>
<string name="lockscreen_permanent_disabled_sim_instructions" msgid="4358929052509450807">"သင့် ဆင်းမ်ကတ်ကို ထာဝရ ပိတ်လိုက်ပါပြီ။\n နောက် ဆင်းမ်ကတ် တစ်ခု အတွက် သင်၏ ကြိုးမဲ့ ဝန်ဆောင်မှု စီမံပေးသူကို ဆက်သွယ်ပါ"</string>
<string name="lockscreen_transport_prev_description" msgid="2879469521751181478">"ယခင် တစ်ပုဒ်"</string>
<string name="lockscreen_transport_next_description" msgid="2931509904881099919">"နောက် တစ်ပုဒ်"</string>
@@ -1340,8 +1340,8 @@
<string name="sms_short_code_remember_undo_instruction" msgid="2620984439143080410">"နောင်တွင် ဆက်တင် &gt; အပလီကေးရှင်းများ မှပြောင်းနိုင်သည်"</string>
<string name="sms_short_code_confirm_always_allow" msgid="2223014893129755950">"အမြဲခွင့်ပြုရန်"</string>
<string name="sms_short_code_confirm_never_allow" msgid="2688828813521652079">"ဘယ်တော့မှခွင့်မပြုပါ"</string>
- <string name="sim_removed_title" msgid="5387212933992546283">"SIMကဒ်ဖယ်ရှားခြင်း"</string>
- <string name="sim_removed_message" msgid="9051174064474904617">"သတ်မှတ်ထားသောဆင်းမ်ကဒ်ဖြင့် ပြန်လည်ဖွင့်သည့်အထိ မိုဘိုင်းကွန်ယက်ရရှိမည်မဟုတ်ပါ"</string>
+ <string name="sim_removed_title" msgid="5387212933992546283">"SIM ကတ်ဖယ်ရှားခြင်း"</string>
+ <string name="sim_removed_message" msgid="9051174064474904617">"သတ်မှတ်ထားသောဆင်းမ်ကတ်ဖြင့် ပြန်လည်ဖွင့်သည့်အထိ မိုဘိုင်းကွန်ရက်ရရှိမည်မဟုတ်ပါ"</string>
<string name="sim_done_button" msgid="6464250841528410598">"ပြီးပါပြီ"</string>
<string name="sim_added_title" msgid="7930779986759414595">"ဆင်းမ်ကတ် ထည့်ပါသည်"</string>
<string name="sim_added_message" msgid="6602906609509958680">"မိုးဘိုင်းကွန်ရက်ကို ဆက်သွယ်ရန် စက်ကို ပြန် စ ပါ"</string>
@@ -2046,7 +2046,7 @@
<string name="autofill_continue_yes" msgid="7914985605534510385">"ရှေ့ဆက်ရန်"</string>
<string name="autofill_save_type_password" msgid="5624528786144539944">"စကားဝှက်"</string>
<string name="autofill_save_type_address" msgid="3111006395818252885">"လိပ်စာ"</string>
- <string name="autofill_save_type_credit_card" msgid="3583795235862046693">"ခရက်တစ်ကတ်"</string>
+ <string name="autofill_save_type_credit_card" msgid="3583795235862046693">"ခရက်ဒစ်ကတ်"</string>
<string name="autofill_save_type_debit_card" msgid="3169397504133097468">"ဒက်ဘစ် ကတ်"</string>
<string name="autofill_save_type_payment_card" msgid="6555012156728690856">"ငွေပေးချေမှုကတ်"</string>
<string name="autofill_save_type_generic_card" msgid="1019367283921448608">"ကတ်"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 70e0d1f37e63..9b6129f7cf61 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -226,9 +226,9 @@
<string name="reboot_to_update_title" msgid="2125818841916373708">"Android ਸਿਸਟਮ ਅੱਪਡੇਟ"</string>
<string name="reboot_to_update_prepare" msgid="6978842143587422365">"ਅੱਪਡੇਟ ਦੀ ਤਿਆਰੀ ਕਰ ਰਿਹਾ ਹੈ…"</string>
<string name="reboot_to_update_package" msgid="4644104795527534811">"ਅੱਪਡੇਟ ਪੈਕੇਜ ਦੀ ਕਾਰਵਾਈ ਕਰ ਰਿਹਾ ਹੈ..."</string>
- <string name="reboot_to_update_reboot" msgid="4474726009984452312">"ਰੀਸਟਾਰਟ ਹੋ ਰਿਹਾ ਹੈ…"</string>
+ <string name="reboot_to_update_reboot" msgid="4474726009984452312">"ਮੁੜ-ਸ਼ੁਰੂ ਹੋ ਰਿਹਾ ਹੈ…"</string>
<string name="reboot_to_reset_title" msgid="2226229680017882787">"ਫੈਕਟਰੀ ਡਾਟਾ ਰੀਸੈੱਟ"</string>
- <string name="reboot_to_reset_message" msgid="3347690497972074356">"ਰੀਸਟਾਰਟ ਹੋ ਰਿਹਾ ਹੈ…"</string>
+ <string name="reboot_to_reset_message" msgid="3347690497972074356">"ਮੁੜ-ਸ਼ੁਰੂ ਹੋ ਰਿਹਾ ਹੈ…"</string>
<string name="shutdown_progress" msgid="5017145516412657345">"ਬੰਦ ਹੋ ਰਿਹਾ ਹੈ…"</string>
<string name="shutdown_confirm" product="tablet" msgid="2872769463279602432">"ਤੁਹਾਡਾ ਟੈਬਲੈੱਟ ਬੰਦ ਕੀਤਾ ਜਾਵੇਗਾ।"</string>
<string name="shutdown_confirm" product="tv" msgid="7975942887313518330">"ਤੁਹਾਡਾ Android TV ਡੀਵਾਈਸ ਜਲਦ ਬੰਦ ਕੀਤਾ ਜਾਵੇਗਾ।"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 15ec82c380b7..4ae1a17d9922 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1018,7 +1018,7 @@
<string name="permlab_writeGeolocationPermissions" msgid="8605631647492879449">"sửa đổi các quyền về vị trí địa lý của Trình duyệt"</string>
<string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"Cho phép ứng dụng sửa đổi cấp phép vị trí địa lý của Trình duyệt. Ứng dụng độc hại có thể lợi dụng quyền này để cho phép gửi thông tin vị trí tới các trang web tùy ý."</string>
<string name="save_password_message" msgid="2146409467245462965">"Bạn có muốn trình duyệt nhớ mật khẩu này không?"</string>
- <string name="save_password_notnow" msgid="2878327088951240061">"Không phải bây giờ"</string>
+ <string name="save_password_notnow" msgid="2878327088951240061">"Để sau"</string>
<string name="save_password_remember" msgid="6490888932657708341">"Nhớ"</string>
<string name="save_password_never" msgid="6776808375903410659">"Chưa bao giờ"</string>
<string name="open_permission_deny" msgid="5136793905306987251">"Bạn không được phép mở trang này."</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index beecd9350b4c..f621a67a1bf1 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -980,7 +980,7 @@
<string name="factorytest_reboot" msgid="2050147445567257365">"重新開機"</string>
<string name="js_dialog_title" msgid="7464775045615023241">"「<xliff:g id="TITLE">%s</xliff:g>」網頁指出:"</string>
<string name="js_dialog_title_default" msgid="3769524569903332476">"JavaScript"</string>
- <string name="js_dialog_before_unload_title" msgid="7012587995876771246">"確認瀏覽"</string>
+ <string name="js_dialog_before_unload_title" msgid="7012587995876771246">"確認離開網頁"</string>
<string name="js_dialog_before_unload_positive_button" msgid="4274257182303565509">"離開這一頁"</string>
<string name="js_dialog_before_unload_negative_button" msgid="3873765747622415310">"停留在這一頁"</string>
<string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\n你確定要前往其他網頁瀏覽嗎?"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index ab39152fc10f..5cd5c2604e28 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8717,9 +8717,14 @@
<declare-styleable name="VoiceInteractionService">
<!-- The service that hosts active voice interaction sessions. This is required. -->
<attr name="sessionService" format="string" />
- <!-- The service that provides voice recognition. This is required. When the user
- selects this voice interaction service, they will also be implicitly selecting
- the component here for their recognition service. -->
+ <!-- The service that provides voice recognition. This is required. On Android 11 and
+ earlier, this must be a valid RecognitionService.
+ <p>
+ From Android 12 onward, this attribute does nothing. However, we still require it to
+ be set to something to reduce the risk that an app with an unspecified value gets
+ pushed to older platform versions, where it will cause a boot loop. To make sure
+ developers don't miss it, the system will reset the current assistant if this isn't
+ specified.-->
<attr name="recognitionService" format="string" />
<attr name="settingsActivity" />
<!-- Flag indicating whether this voice interaction service is capable of handling the
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 32db1866c151..90646a8674b6 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1930,8 +1930,9 @@
STREAM_MUSIC as if it's on TV platform. -->
<bool name="config_single_volume">false</bool>
- <!-- Flag indicating whether the volume panel should show remote sessions. -->
- <bool name="config_volumeShowRemoteSessions">true</bool>
+ <!-- Flag indicating whether platform level volume adjustments are enabled for remote sessions
+ on grouped devices. -->
+ <bool name="config_volumeAdjustmentForRemoteGroupSessions">true</bool>
<!-- Flag indicating that an outbound call must have a call capable phone account
that has declared it can process the call's handle. -->
diff --git a/core/res/res/values/dimens_car.xml b/core/res/res/values/dimens_car.xml
index 36f1edb4d417..c5dddb8f7d8a 100644
--- a/core/res/res/values/dimens_car.xml
+++ b/core/res/res/values/dimens_car.xml
@@ -17,7 +17,7 @@
-->
<resources>
<dimen name="car_large_avatar_size">96dp</dimen>
- <dimen name="car_large_avatar_badge_size">32dp</dimen>
+ <dimen name="car_large_avatar_badge_size">24dp</dimen>
<!-- Application Bar -->
<dimen name="car_app_bar_height">80dp</dimen>
<!-- Margin -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 7d489049d112..1e30131ae6f9 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1235,7 +1235,6 @@
<public type="attr" name="author" id="0x010102b4" />
<public type="attr" name="autoStart" id="0x010102b5" />
-
<!-- ===============================================================
Resources added in version 8 of the platform (Eclair MR2).
=============================================================== -->
@@ -3202,89 +3201,23 @@
<!-- ===============================================================
Resources added in version S-V2 of the platform
-
- NOTE: add <public> elements within a <staging-public-group> like so:
-
- <staging-public-group type="attr" first-id="0x01ff0000">
- <public name="exampleAttr1" />
- <public name="exampleAttr2" />
- </staging-public-group>
-
- To add a new <staging-public-group> block, find the id value for the
- last <staging-public-group> block defined for thie API level, and
- subtract 0x00010000 from it to get to the id of the new block.
-
- For example, if the block closest to the end of this file has an id of
- 0x01ee0000, the id of the new block should be 0x01ed0000
- (0x01ee0000 - 0x00010000 = 0x01ed0000).
=============================================================== -->
<eat-comment />
- <staging-public-group type="attr" first-id="0x01ff0000">
+ <staging-public-group-final type="attr" first-id="0x01ff0000">
<public name="shouldUseDefaultUnfoldTransition" />
- </staging-public-group>
+ </staging-public-group-final>
+
+ <public type="attr" name="shouldUseDefaultUnfoldTransition" id="0x0101064c" />
- <staging-public-group type="id" first-id="0x01fe0000">
+ <staging-public-group-final type="id" first-id="0x01fe0000">
<public name="accessibilityActionDragStart" />
<public name="accessibilityActionDragDrop" />
<public name="accessibilityActionDragCancel" />
- </staging-public-group>
-
- <staging-public-group type="style" first-id="0x01fd0000">
- </staging-public-group>
-
- <staging-public-group type="string" first-id="0x01fc0000">
- </staging-public-group>
-
- <staging-public-group type="dimen" first-id="0x01fb0000">
- </staging-public-group>
-
- <staging-public-group type="color" first-id="0x01fa0000">
- </staging-public-group>
-
- <staging-public-group type="array" first-id="0x01f90000">
- </staging-public-group>
-
- <staging-public-group type="drawable" first-id="0x01f80000">
- </staging-public-group>
-
- <staging-public-group type="layout" first-id="0x01f70000">
- </staging-public-group>
+ </staging-public-group-final>
- <staging-public-group type="anim" first-id="0x01f60000">
- </staging-public-group>
-
- <staging-public-group type="animator" first-id="0x01f50000">
- </staging-public-group>
-
- <staging-public-group type="interpolator" first-id="0x01f40000">
- </staging-public-group>
-
- <staging-public-group type="mipmap" first-id="0x01f30000">
- </staging-public-group>
-
- <staging-public-group type="integer" first-id="0x01f20000">
- </staging-public-group>
-
- <staging-public-group type="transition" first-id="0x01f10000">
- </staging-public-group>
-
- <staging-public-group type="raw" first-id="0x01f00000">
- </staging-public-group>
-
- <staging-public-group type="bool" first-id="0x01ef0000">
- </staging-public-group>
-
- <staging-public-group type="fraction" first-id="0x01ee0000">
- </staging-public-group>
-
- <!-- ===============================================================
- DO NOT ADD UN-GROUPED ITEMS HERE
-
- Any new items (attrs, styles, ids, etc.) *must* be added in a
- staging-public-group block, as the preceding comment explains.
- Items added outside of a group may have their value recalculated
- every time something new is added to this file.
- =============================================================== -->
+ <public type="id" name="accessibilityActionDragStart" id="0x01020055" />
+ <public type="id" name="accessibilityActionDragDrop" id="0x01020056" />
+ <public type="id" name="accessibilityActionDragCancel" id="0x01020057" />
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 758990df7159..9bb92e6c93cc 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4444,7 +4444,7 @@
<java-symbol type="dimen" name="config_wallpaperDimAmount" />
- <java-symbol type="bool" name="config_volumeShowRemoteSessions" />
+ <java-symbol type="bool" name="config_volumeAdjustmentForRemoteGroupSessions" />
<java-symbol type="integer" name="config_customizedMaxCachedProcesses" />
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 d7a5e2613175..0d2d047b7f0b 100644
--- a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
@@ -16,6 +16,8 @@
package com.android.internal.jank;
+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.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_TO_STATSD_INTERACTION_TYPE;
@@ -34,6 +36,7 @@ import static org.mockito.Mockito.when;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.SystemClock;
import android.provider.DeviceConfig;
import android.view.View;
import android.view.ViewAttachTestActivity;
@@ -82,36 +85,23 @@ public class InteractionJankMonitorTest {
Handler handler = spy(new Handler(mActivity.getMainLooper()));
doReturn(true).when(handler).sendMessageAtTime(any(), anyLong());
- mWorker = spy(new HandlerThread("Interaction-jank-monitor-test"));
- doNothing().when(mWorker).start();
+ mWorker = mock(HandlerThread.class);
doReturn(handler).when(mWorker).getThreadHandler();
}
@Test
public void testBeginEnd() {
- // Should return false if the view is not attached.
- InteractionJankMonitor monitor = spy(new InteractionJankMonitor(mWorker));
- 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(ChoreographerWrapper.class),
- new FrameMetricsWrapper(),
- /* traceThresholdMissedFrames= */ 1, /* traceThresholdFrameTimeMillis= */ -1,
- /* FrameTrackerListener */ null, config));
+ InteractionJankMonitor monitor = createMockedInteractionJankMonitor();
+ FrameTracker tracker = createMockedFrameTracker(null);
doReturn(tracker).when(monitor).createFrameTracker(any(), any());
- doNothing().when(tracker).triggerPerfetto();
- doNothing().when(tracker).postTraceStartMarker();
+ doNothing().when(tracker).begin();
+ doReturn(true).when(tracker).end(anyInt());
// Simulate a trace session and see if begin / end are invoked.
- assertThat(monitor.begin(mView, session.getCuj())).isTrue();
+ assertThat(monitor.begin(mView, CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isTrue();
verify(tracker).begin();
- assertThat(monitor.end(session.getCuj())).isTrue();
- verify(tracker).end(FrameTracker.REASON_END_NORMAL);
+ assertThat(monitor.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isTrue();
+ verify(tracker).end(REASON_END_NORMAL);
}
@Test
@@ -140,33 +130,23 @@ public class InteractionJankMonitorTest {
}
@Test
- public void testBeginCancel() {
- InteractionJankMonitor monitor = spy(new InteractionJankMonitor(mWorker));
-
+ public void testBeginTimeout() {
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,
- /* FrameTrackerListener */ null, config));
+ InteractionJankMonitor monitor = createMockedInteractionJankMonitor();
+ FrameTracker tracker = createMockedFrameTracker(null);
doReturn(tracker).when(monitor).createFrameTracker(any(), any());
- doNothing().when(tracker).triggerPerfetto();
- doNothing().when(tracker).postTraceStartMarker();
+ doNothing().when(tracker).begin();
+ doReturn(true).when(tracker).cancel(anyInt());
- assertThat(monitor.begin(mView, session.getCuj())).isTrue();
+ assertThat(monitor.begin(mView, CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isTrue();
verify(tracker).begin();
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_TIMEOUT);
+ verify(monitor).cancel(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, REASON_CANCEL_TIMEOUT);
+ verify(tracker).cancel(REASON_CANCEL_TIMEOUT);
}
@Test
@@ -192,4 +172,43 @@ public class InteractionJankMonitorTest {
.isTrue();
}
}
+
+ private InteractionJankMonitor createMockedInteractionJankMonitor() {
+ InteractionJankMonitor monitor = spy(new InteractionJankMonitor(mWorker));
+ doReturn(true).when(monitor).shouldMonitor(anyInt());
+ doNothing().when(monitor).notifyEvents(any(), any(), any());
+ return monitor;
+ }
+
+ private FrameTracker createMockedFrameTracker(FrameTracker.FrameTrackerListener listener) {
+ Session session = spy(new Session(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, CUJ_POSTFIX));
+ doReturn(false).when(session).logToStatsd();
+
+ ThreadedRendererWrapper threadedRenderer = mock(ThreadedRendererWrapper.class);
+ doNothing().when(threadedRenderer).addObserver(any());
+ doNothing().when(threadedRenderer).removeObserver(any());
+
+ ViewRootWrapper viewRoot = spy(new ViewRootWrapper(mView.getViewRootImpl()));
+ doNothing().when(viewRoot).addSurfaceChangedCallback(any());
+
+ SurfaceControlWrapper surfaceControl = mock(SurfaceControlWrapper.class);
+ doNothing().when(surfaceControl).addJankStatsListener(any(), any());
+ doNothing().when(surfaceControl).removeJankStatsListener(any());
+
+ final ChoreographerWrapper choreographer = mock(ChoreographerWrapper.class);
+ doReturn(SystemClock.elapsedRealtime()).when(choreographer).getVsyncId();
+
+ Configuration configuration = mock(Configuration.class);
+ when(configuration.isSurfaceOnly()).thenReturn(false);
+
+ FrameTracker tracker = spy(new FrameTracker(session, mWorker.getThreadHandler(),
+ threadedRenderer, viewRoot, surfaceControl, choreographer,
+ new FrameMetricsWrapper(), /* traceThresholdMissedFrames= */ 1,
+ /* traceThresholdFrameTimeMillis= */ -1, listener, configuration));
+
+ doNothing().when(tracker).postTraceStartMarker();
+ doNothing().when(tracker).triggerPerfetto();
+
+ return tracker;
+ }
}
diff --git a/data/etc/car/com.android.car.shell.xml b/data/etc/car/com.android.car.shell.xml
index c058cb91cf9d..992840db1a27 100644
--- a/data/etc/car/com.android.car.shell.xml
+++ b/data/etc/car/com.android.car.shell.xml
@@ -19,6 +19,7 @@
is ok. -->
<privapp-permissions package="com.android.shell">
<permission name="android.permission.INSTALL_PACKAGES" />
+ <permission name="android.permission.MODIFY_AUDIO_ROUTING"/>
<permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
<permission name="android.car.permission.CAR_CONTROL_AUDIO_SETTINGS"/>
<permission name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"/>
diff --git a/data/etc/car/com.google.android.car.kitchensink.xml b/data/etc/car/com.google.android.car.kitchensink.xml
index ab162dd590a1..2c59c7390ebf 100644
--- a/data/etc/car/com.google.android.car.kitchensink.xml
+++ b/data/etc/car/com.google.android.car.kitchensink.xml
@@ -67,6 +67,7 @@
<permission name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"/>
<permission name="android.car.permission.CAR_MILEAGE"/>
<permission name="android.car.permission.CAR_MOCK_VEHICLE_HAL"/>
+ <permission name="android.car.permission.CAR_MONITOR_CLUSTER_NAVIGATION_STATE"/>
<permission name="android.car.permission.CAR_NAVIGATION_MANAGER"/>
<permission name="android.car.permission.CAR_POWER"/>
<permission name="android.car.permission.CAR_PROJECTION"/>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 6e92755be98e..8b3780590d44 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1561,6 +1561,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DisplayRotation.java"
},
+ "-436553282": {
+ "message": "Remove sleep token: tag=%s, displayId=%d",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+ },
"-415865166": {
"message": "findFocusedWindow: Found new focus @ %s",
"level": "VERBOSE",
@@ -1669,6 +1675,12 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "-317761482": {
+ "message": "Create sleep token: tag=%s, displayId=%d",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_STATES",
+ "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+ },
"-317194205": {
"message": "clearLockedTasks: %s",
"level": "INFO",
diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java
index 36215ecc1403..fca4de91a352 100644
--- a/graphics/java/android/graphics/BLASTBufferQueue.java
+++ b/graphics/java/android/graphics/BLASTBufferQueue.java
@@ -34,7 +34,6 @@ public final class BLASTBufferQueue {
private static native void nativeSetNextTransaction(long ptr, long transactionPtr);
private static native void nativeUpdate(long ptr, long surfaceControl, long width, long height,
int format, long transactionPtr);
- private static native void nativeFlushShadowQueue(long ptr);
private static native void nativeMergeWithNextTransaction(long ptr, long transactionPtr,
long frameNumber);
private static native void nativeSetTransactionCompleteCallback(long ptr, long frameNumber,
@@ -124,10 +123,6 @@ public final class BLASTBufferQueue {
}
}
- public void flushShadowQueue() {
- nativeFlushShadowQueue(mNativeObject);
- }
-
/**
* Merge the transaction passed in to the next transaction in BlastBufferQueue. The next
* transaction will be applied or merged when the next frame with specified frame number
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonDisplayFeature.java b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonDisplayFeature.java
index e6ad011e617e..eb9429747b66 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonDisplayFeature.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonDisplayFeature.java
@@ -30,18 +30,21 @@ import java.util.regex.Pattern;
/** Wrapper for both Extension and Sidecar versions of DisplayFeature. */
final class CommonDisplayFeature implements DisplayFeature {
private static final Pattern FEATURE_PATTERN =
- Pattern.compile("([a-z]+)-\\[(\\d+),(\\d+),(\\d+),(\\d+)]");
+ Pattern.compile("([a-z]+)-\\[(\\d+),(\\d+),(\\d+),(\\d+)]-?(flat|half-opened)?");
private static final String FEATURE_TYPE_FOLD = "fold";
private static final String FEATURE_TYPE_HINGE = "hinge";
+ private static final String PATTERN_STATE_FLAT = "flat";
+ private static final String PATTERN_STATE_HALF_OPENED = "half-opened";
+
// TODO(b/183049815): Support feature strings that include the state of the feature.
+
/**
* Parses a display feature from a string.
*
* @throws IllegalArgumentException if the provided string is improperly formatted or could not
- * otherwise be parsed.
- *
+ * otherwise be parsed.
* @see #FEATURE_PATTERN
*/
@NonNull
@@ -52,6 +55,7 @@ final class CommonDisplayFeature implements DisplayFeature {
}
try {
String featureType = featureMatcher.group(1);
+ featureType = featureType == null ? "" : featureType;
int type;
switch (featureType) {
case FEATURE_TYPE_FOLD:
@@ -73,8 +77,21 @@ final class CommonDisplayFeature implements DisplayFeature {
if (isZero(featureRect)) {
throw new IllegalArgumentException("Feature has empty bounds: " + string);
}
-
- return new CommonDisplayFeature(type, null, featureRect);
+ String stateString = featureMatcher.group(6);
+ stateString = stateString == null ? "" : stateString;
+ Integer state;
+ switch (stateString) {
+ case PATTERN_STATE_FLAT:
+ state = COMMON_STATE_FLAT;
+ break;
+ case PATTERN_STATE_HALF_OPENED:
+ state = COMMON_STATE_HALF_OPENED;
+ break;
+ default:
+ state = null;
+ break;
+ }
+ return new CommonDisplayFeature(type, state, featureRect);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Malformed feature description: " + string, e);
}
@@ -87,6 +104,7 @@ final class CommonDisplayFeature implements DisplayFeature {
private final Rect mRect;
CommonDisplayFeature(int type, @Nullable Integer state, @NonNull Rect rect) {
+ assertValidState(state);
this.mType = type;
this.mState = state;
if (rect.width() == 0 && rect.height() == 0) {
@@ -125,4 +143,11 @@ final class CommonDisplayFeature implements DisplayFeature {
public int hashCode() {
return Objects.hash(mType, mState, mRect);
}
+
+ private static void assertValidState(@Nullable Integer state) {
+ if (state != null && state != COMMON_STATE_FLAT && state != COMMON_STATE_HALF_OPENED) {
+ throw new IllegalArgumentException("Invalid state: " + state
+ + "must be either COMMON_STATE_FLAT or COMMON_STATE_HALF_OPENED");
+ }
+ }
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/DisplayFeature.java b/libs/WindowManager/Jetpack/src/androidx/window/common/DisplayFeature.java
index b6c4c436d0b1..573641857b99 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/DisplayFeature.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/DisplayFeature.java
@@ -16,11 +16,15 @@
package androidx.window.common;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.graphics.Rect;
import androidx.annotation.NonNull;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/** Wrapper for both Extension and Sidecar versions of DisplayFeature. */
public interface DisplayFeature {
/** Returns the type of the feature. */
@@ -28,9 +32,29 @@ public interface DisplayFeature {
/** Returns the state of the feature, or {@code null} if the feature has no state. */
@Nullable
+ @State
Integer getState();
/** Returns the bounds of the feature. */
@NonNull
Rect getRect();
+
+ /**
+ * A common state to represent a FLAT hinge. This is needed because the definitions in Sidecar
+ * and Extensions do not match exactly.
+ */
+ int COMMON_STATE_FLAT = 3;
+ /**
+ * A common state to represent a HALF_OPENED hinge. This is needed because the definitions in
+ * Sidecar and Extensions do not match exactly.
+ */
+ int COMMON_STATE_HALF_OPENED = 2;
+
+ /**
+ * The possible states for a folding hinge.
+ */
+ @IntDef({COMMON_STATE_FLAT, COMMON_STATE_HALF_OPENED})
+ @Retention(RetentionPolicy.SOURCE)
+ @interface State {}
+
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
index 06e7d1457417..44af1a9fd780 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
@@ -73,14 +73,61 @@ class SplitContainer {
static boolean shouldFinishPrimaryWithSecondary(@NonNull SplitRule splitRule) {
final boolean isPlaceholderContainer = splitRule instanceof SplitPlaceholderRule;
final boolean shouldFinishPrimaryWithSecondary = (splitRule instanceof SplitPairRule)
- && ((SplitPairRule) splitRule).shouldFinishPrimaryWithSecondary();
+ && ((SplitPairRule) splitRule).getFinishPrimaryWithSecondary()
+ != SplitRule.FINISH_NEVER;
return shouldFinishPrimaryWithSecondary || isPlaceholderContainer;
}
static boolean shouldFinishSecondaryWithPrimary(@NonNull SplitRule splitRule) {
final boolean isPlaceholderContainer = splitRule instanceof SplitPlaceholderRule;
final boolean shouldFinishSecondaryWithPrimary = (splitRule instanceof SplitPairRule)
- && ((SplitPairRule) splitRule).shouldFinishSecondaryWithPrimary();
+ && ((SplitPairRule) splitRule).getFinishSecondaryWithPrimary()
+ != SplitRule.FINISH_NEVER;
return shouldFinishSecondaryWithPrimary || isPlaceholderContainer;
}
+
+ static boolean shouldFinishAssociatedContainerWhenStacked(int finishBehavior) {
+ return finishBehavior == SplitRule.FINISH_ALWAYS;
+ }
+
+ static boolean shouldFinishAssociatedContainerWhenAdjacent(int finishBehavior) {
+ return finishBehavior == SplitRule.FINISH_ALWAYS
+ || finishBehavior == SplitRule.FINISH_ADJACENT;
+ }
+
+ static int getFinishPrimaryWithSecondaryBehavior(@NonNull SplitRule splitRule) {
+ if (splitRule instanceof SplitPlaceholderRule) {
+ return ((SplitPlaceholderRule) splitRule).getFinishPrimaryWithSecondary();
+ }
+ if (splitRule instanceof SplitPairRule) {
+ return ((SplitPairRule) splitRule).getFinishPrimaryWithSecondary();
+ }
+ return SplitRule.FINISH_NEVER;
+ }
+
+ static int getFinishSecondaryWithPrimaryBehavior(@NonNull SplitRule splitRule) {
+ if (splitRule instanceof SplitPlaceholderRule) {
+ return SplitRule.FINISH_ALWAYS;
+ }
+ if (splitRule instanceof SplitPairRule) {
+ return ((SplitPairRule) splitRule).getFinishSecondaryWithPrimary();
+ }
+ return SplitRule.FINISH_NEVER;
+ }
+
+ static boolean isStickyPlaceholderRule(@NonNull SplitRule splitRule) {
+ if (!(splitRule instanceof SplitPlaceholderRule)) {
+ return false;
+ }
+ return ((SplitPlaceholderRule) splitRule).isSticky();
+ }
+
+ @Override
+ public String toString() {
+ return "SplitContainer{"
+ + " primaryContainer=" + mPrimaryContainer
+ + " secondaryContainer=" + mSecondaryContainer
+ + " splitRule=" + mSplitRule
+ + "}";
+ }
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 42b438041d7a..68c19041940c 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -16,6 +16,12 @@
package androidx.window.extensions.embedding;
+import static androidx.window.extensions.embedding.SplitContainer.getFinishPrimaryWithSecondaryBehavior;
+import static androidx.window.extensions.embedding.SplitContainer.getFinishSecondaryWithPrimaryBehavior;
+import static androidx.window.extensions.embedding.SplitContainer.isStickyPlaceholderRule;
+import static androidx.window.extensions.embedding.SplitContainer.shouldFinishAssociatedContainerWhenAdjacent;
+import static androidx.window.extensions.embedding.SplitContainer.shouldFinishAssociatedContainerWhenStacked;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
@@ -460,6 +466,11 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
return false;
}
+ if (isStickyPlaceholderRule(splitContainer.getSplitRule())) {
+ // The placeholder should remain after it was first shown.
+ return false;
+ }
+
if (mPresenter.shouldShowSideBySide(splitContainer)) {
return false;
}
@@ -497,7 +508,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
return;
}
List<SplitInfo> currentSplitStates = getActiveSplitStates();
- if (mLastReportedSplitStates.equals(currentSplitStates)) {
+ if (currentSplitStates == null || mLastReportedSplitStates.equals(currentSplitStates)) {
return;
}
mLastReportedSplitStates.clear();
@@ -506,22 +517,22 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
}
/**
- * Returns a list of descriptors for currently active split states.
+ * @return a list of descriptors for currently active split states. If the value returned is
+ * null, that indicates that the active split states are in an intermediate state and should
+ * not be reported.
*/
+ @Nullable
private List<SplitInfo> getActiveSplitStates() {
List<SplitInfo> splitStates = new ArrayList<>();
for (SplitContainer container : mSplitContainers) {
if (container.getPrimaryContainer().isEmpty()
|| container.getSecondaryContainer().isEmpty()) {
- // Skipping containers that do not have any activities to report.
- continue;
+ // We are in an intermediate state because either the split container is about to be
+ // removed or the primary or secondary container are about to receive an activity.
+ return null;
}
- ActivityStack primaryContainer =
- new ActivityStack(
- container.getPrimaryContainer().collectActivities());
- ActivityStack secondaryContainer =
- new ActivityStack(
- container.getSecondaryContainer().collectActivities());
+ ActivityStack primaryContainer = container.getPrimaryContainer().toActivityStack();
+ ActivityStack secondaryContainer = container.getSecondaryContainer().toActivityStack();
SplitInfo splitState = new SplitInfo(primaryContainer,
secondaryContainer,
// Splits that are not showing side-by-side are reported as having 0 split
@@ -643,6 +654,52 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
return false;
}
+ /**
+ * Checks whether the associated container should be destroyed together with a finishing
+ * container. There is a case when primary containers for placeholders should be retained
+ * despite the rule configuration to finish primary with secondary - if they are marked as
+ * 'sticky' and the placeholder was finished when fully overlapping the primary container.
+ * @return {@code true} if the associated container should be retained (and not be finished).
+ */
+ boolean shouldRetainAssociatedContainer(@NonNull TaskFragmentContainer finishingContainer,
+ @NonNull TaskFragmentContainer associatedContainer) {
+ SplitContainer splitContainer = getActiveSplitForContainers(associatedContainer,
+ finishingContainer);
+ if (splitContainer == null) {
+ // Containers are not in the same split, no need to retain.
+ return false;
+ }
+ // Find the finish behavior for the associated container
+ int finishBehavior;
+ SplitRule splitRule = splitContainer.getSplitRule();
+ if (finishingContainer == splitContainer.getPrimaryContainer()) {
+ finishBehavior = getFinishSecondaryWithPrimaryBehavior(splitRule);
+ } else {
+ finishBehavior = getFinishPrimaryWithSecondaryBehavior(splitRule);
+ }
+ // Decide whether the associated container should be retained based on the current
+ // presentation mode.
+ if (mPresenter.shouldShowSideBySide(splitContainer)) {
+ return !shouldFinishAssociatedContainerWhenAdjacent(finishBehavior);
+ } else {
+ return !shouldFinishAssociatedContainerWhenStacked(finishBehavior);
+ }
+ }
+
+ /**
+ * @see #shouldRetainAssociatedContainer(TaskFragmentContainer, TaskFragmentContainer)
+ */
+ boolean shouldRetainAssociatedActivity(@NonNull TaskFragmentContainer finishingContainer,
+ @NonNull Activity associatedActivity) {
+ TaskFragmentContainer associatedContainer = getContainerWithActivity(
+ associatedActivity.getActivityToken());
+ if (associatedContainer == null) {
+ return false;
+ }
+
+ return shouldRetainAssociatedContainer(finishingContainer, associatedContainer);
+ }
+
private final class LifecycleCallbacks implements ActivityLifecycleCallbacks {
@Override
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 54e44a70ed40..a1a53bc93781 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -27,6 +27,7 @@ import android.window.TaskFragmentInfo;
import android.window.WindowContainerTransaction;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
/**
@@ -109,6 +110,10 @@ class TaskFragmentContainer {
return allActivities;
}
+ ActivityStack toActivityStack() {
+ return new ActivityStack(collectActivities(), mInfo.getRunningActivityCount() == 0);
+ }
+
void addPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
mPendingAppearedActivities.add(pendingAppearedActivity);
}
@@ -223,6 +228,9 @@ class TaskFragmentContainer {
// Finish dependent containers
for (TaskFragmentContainer container : mContainersToFinishOnExit) {
+ if (controller.shouldRetainAssociatedContainer(this, container)) {
+ continue;
+ }
container.finish(true /* shouldFinishDependent */, presenter,
wct, controller);
}
@@ -230,6 +238,9 @@ class TaskFragmentContainer {
// Finish associated activities
for (Activity activity : mActivitiesToFinishOnExit) {
+ if (controller.shouldRetainAssociatedActivity(this, activity)) {
+ continue;
+ }
activity.finish();
}
mActivitiesToFinishOnExit.clear();
@@ -263,4 +274,42 @@ class TaskFragmentContainer {
mLastRequestedBounds.set(bounds);
}
}
+
+ @Override
+ public String toString() {
+ return toString(true /* includeContainersToFinishOnExit */);
+ }
+
+ /**
+ * @return string for this TaskFragmentContainer and includes containers to finish on exit
+ * based on {@code includeContainersToFinishOnExit}. If containers to finish on exit are always
+ * included in the string, then calling {@link #toString()} on a container that mutually
+ * finishes with another container would cause a stack overflow.
+ */
+ private String toString(boolean includeContainersToFinishOnExit) {
+ return "TaskFragmentContainer{"
+ + " token=" + mToken
+ + " info=" + mInfo
+ + " topNonFinishingActivity=" + getTopNonFinishingActivity()
+ + " pendingAppearedActivities=" + mPendingAppearedActivities
+ + (includeContainersToFinishOnExit ? " containersToFinishOnExit="
+ + containersToFinishOnExitToString() : "")
+ + " activitiesToFinishOnExit=" + mActivitiesToFinishOnExit
+ + " isFinished=" + mIsFinished
+ + " lastRequestedBounds=" + mLastRequestedBounds
+ + "}";
+ }
+
+ private String containersToFinishOnExitToString() {
+ StringBuilder sb = new StringBuilder("[");
+ Iterator<TaskFragmentContainer> containerIterator = mContainersToFinishOnExit.iterator();
+ while (containerIterator.hasNext()) {
+ sb.append(containerIterator.next().toString(
+ false /* includeContainersToFinishOnExit */));
+ if (containerIterator.hasNext()) {
+ sb.append(", ");
+ }
+ }
+ return sb.append("]").toString();
+ }
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
index 383d91da6af8..32d447ef1586 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
@@ -122,8 +122,19 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
private int getFeatureState(DisplayFeature feature) {
Integer featureState = feature.getState();
Optional<Integer> posture = mDevicePostureProducer.getData();
- int fallbackPosture = posture.orElse(FoldingFeature.STATE_FLAT);
- return featureState == null ? fallbackPosture : featureState;
+ int fallbackPosture = posture.orElse(DisplayFeature.COMMON_STATE_FLAT);
+ int displayFeatureState = featureState == null ? fallbackPosture : featureState;
+ return convertToExtensionState(displayFeatureState);
+ }
+
+ private int convertToExtensionState(int state) {
+ switch (state) {
+ case DisplayFeature.COMMON_STATE_FLAT:
+ return FoldingFeature.STATE_FLAT;
+ case DisplayFeature.COMMON_STATE_HALF_OPENED:
+ return FoldingFeature.STATE_HALF_OPENED;
+ }
+ return FoldingFeature.STATE_FLAT;
}
private void onDisplayFeaturesChanged() {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
index ece198cad818..aa949f126154 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
@@ -38,6 +38,7 @@ import androidx.window.util.DataProducer;
import androidx.window.util.PriorityDataProducer;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Optional;
@@ -47,6 +48,7 @@ import java.util.Optional;
*/
class SampleSidecarImpl extends StubSidecar {
private static final String TAG = "SampleSidecar";
+ private static final boolean DEBUG = false;
private final SettingsDevicePostureProducer mSettingsDevicePostureProducer;
private final DataProducer<Integer> mDevicePostureProducer;
@@ -88,10 +90,30 @@ class SampleSidecarImpl extends StubSidecar {
Optional<Integer> posture = mDevicePostureProducer.getData();
SidecarDeviceState deviceState = new SidecarDeviceState();
- deviceState.posture = posture.orElse(SidecarDeviceState.POSTURE_UNKNOWN);
+ deviceState.posture = posture.orElse(deviceStateFromFeature());
return deviceState;
}
+ private int deviceStateFromFeature() {
+ List<DisplayFeature> storedFeatures = mDisplayFeatureProducer.getData()
+ .orElse(Collections.emptyList());
+ for (int i = 0; i < storedFeatures.size(); i++) {
+ DisplayFeature feature = storedFeatures.get(i);
+ final int state = feature.getState() == null ? -1 : feature.getState();
+ if (DEBUG && feature.getState() == null) {
+ Log.d(TAG, "feature#getState was null for DisplayFeature: " + feature);
+ }
+
+ switch (state) {
+ case DisplayFeature.COMMON_STATE_FLAT:
+ return SidecarDeviceState.POSTURE_OPENED;
+ case DisplayFeature.COMMON_STATE_HALF_OPENED:
+ return SidecarDeviceState.POSTURE_HALF_OPENED;
+ }
+ }
+ return SidecarDeviceState.POSTURE_UNKNOWN;
+ }
+
@NonNull
@Override
public SidecarWindowLayoutInfo getWindowLayoutInfo(@NonNull IBinder windowToken) {
diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
index 4f36c9c690c9..d6678bf9b320 100644
--- a/libs/WindowManager/Jetpack/window-extensions-release.aar
+++ b/libs/WindowManager/Jetpack/window-extensions-release.aar
Binary files differ
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 3ba1a34bd432..8e3d726362f2 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -38,6 +38,7 @@ filegroup {
path: "src",
}
+// Sources that have no dependencies that can be used directly downstream of this library
filegroup {
name: "wm_shell_util-sources",
srcs: [
@@ -46,6 +47,7 @@ filegroup {
path: "src",
}
+// Aidls which can be used directly downstream of this library
filegroup {
name: "wm_shell-aidls",
srcs: [
@@ -130,11 +132,12 @@ android_library {
"kotlinx-coroutines-android",
"kotlinx-coroutines-core",
"iconloader_base",
- "jsr330",
"protolog-lib",
"WindowManager-Shell-proto",
+ "dagger2",
"jsr330",
],
kotlincflags: ["-Xjvm-default=enable"],
manifest: "AndroidManifest.xml",
+ plugins: ["dagger2-compiler"],
}
diff --git a/packages/SystemUI/res/drawable/ic_exit_to_app.xml b/libs/WindowManager/Shell/res/drawable/pip_split.xml
index a2f3c6831c84..2cfdf6ed259b 100644
--- a/packages/SystemUI/res/drawable/ic_exit_to_app.xml
+++ b/libs/WindowManager/Shell/res/drawable/pip_split.xml
@@ -1,5 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ 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,14 +15,13 @@
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="@dimen/pip_expand_action_inner_size"
+ android:height="@dimen/pip_expand_action_inner_size"
android:viewportWidth="24"
android:viewportHeight="24">
<path
- android:pathData="M10.09 15.59L11.5 17l5-5-5-5-1.41 1.41L12.67 11H3v2h9.67l-2.58 2.59zM19 3H5c-1.11 0-2 .9-2 2v4h2V5h14v14H5v-4H3v4c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"
- android:fillColor="#ffffff"
- android:fillType="evenOdd"/>
-
+ android:fillColor="#FFFFFF"
+ android:pathData="M20,18h-5V6h5V18z M22,18V6c0-1.1-0.9-2-2-2h-5c-1.1,0-2,0.9-2,2v12c0,1.1,0.9,2,2,2h5C21.1,20,22,19.1,22,18z M9,18H4V6h5
+ V18z M11,18V6c0-1.1-0.9-2-2-2H4C2.9,4,2,4.9,2,6v12c0,1.1,0.9,2,2,2h5C10.1,20,11,19.1,11,18z" />
</vector>
diff --git a/packages/SystemUI/res/drawable/screenshot_rounded_corners.xml b/libs/WindowManager/Shell/res/drawable/size_compat_hint_bubble.xml
index fb8e9b7373f5..94165a11eccb 100644
--- a/packages/SystemUI/res/drawable/screenshot_rounded_corners.xml
+++ b/libs/WindowManager/Shell/res/drawable/size_compat_hint_bubble.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ 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.
@@ -15,6 +15,7 @@
~ limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <corners android:radius="@dimen/screenshot_button_corner_radius"/>
-</shape>
+ android:shape="rectangle">
+ <solid android:color="@color/size_compat_hint_bubble"/>
+ <corners android:radius="@dimen/size_compat_hint_corner_radius"/>
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/color/prv_color_surface.xml b/libs/WindowManager/Shell/res/drawable/size_compat_hint_point.xml
index b9d016c46ba0..a8f0f76ef27f 100644
--- a/packages/SystemUI/res/color/prv_color_surface.xml
+++ b/libs/WindowManager/Shell/res/drawable/size_compat_hint_point.xml
@@ -14,7 +14,12 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<selector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="?androidprv:attr/colorSurface" />
-</selector> \ No newline at end of file
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/size_compat_hint_point_width"
+ android:height="8dp"
+ android:viewportWidth="10"
+ android:viewportHeight="8">
+ <path
+ android:fillColor="@color/size_compat_hint_bubble"
+ android:pathData="M10,0 l-4.1875,6.6875 a1,1 0 0,1 -1.625,0 l-4.1875,-6.6875z"/>
+</vector>
diff --git a/libs/WindowManager/Shell/res/drawable/size_compat_restart_button.xml b/libs/WindowManager/Shell/res/drawable/size_compat_restart_button.xml
index 73a48d31a814..3e486df71f91 100644
--- a/libs/WindowManager/Shell/res/drawable/size_compat_restart_button.xml
+++ b/libs/WindowManager/Shell/res/drawable/size_compat_restart_button.xml
@@ -15,14 +15,21 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
<path
- android:fillColor="#aa000000"
- android:pathData="M0,12 a12,12 0 1,0 24,0 a12,12 0 1,0 -24,0" />
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17.65,6.35c-1.63,-1.63 -3.94,-2.57 -6.48,-2.31c-3.67,0.37 -6.69,3.35 -7.1,7.02C3.52,15.91 7.27,20 12,20c3.19,0 5.93,-1.87 7.21,-4.57c0.31,-0.66 -0.16,-1.43 -0.89,-1.43h-0.01c-0.37,0 -0.72,0.2 -0.88,0.53c-1.13,2.43 -3.84,3.97 -6.81,3.32c-2.22,-0.49 -4.01,-2.3 -4.49,-4.52C5.31,9.44 8.26,6 12,6c1.66,0 3.14,0.69 4.22,1.78l-2.37,2.37C13.54,10.46 13.76,11 14.21,11H19c0.55,0 1,-0.45 1,-1V5.21c0,-0.45 -0.54,-0.67 -0.85,-0.35L17.65,6.35z"/>
+ android:fillColor="#53534D"
+ android:pathData="M0,24 a24,24 0 1,0 48,0 a24,24 0 1,0 -48,0" />
+ <group
+ android:translateX="12"
+ android:translateY="12">
+ <path
+ android:fillColor="#E4E3DA"
+ android:pathData="M6,13c0,-1.65 0.67,-3.15 1.76,-4.24L6.34,7.34C4.9,8.79 4,10.79 4,13c0,4.08 3.05,7.44 7,7.93v-2.02C8.17,18.43 6,15.97 6,13z"/>
+ <path
+ android:fillColor="#E4E3DA"
+ android:pathData="M20,13c0,-4.42 -3.58,-8 -8,-8c-0.06,0 -0.12,0.01 -0.18,0.01v0l1.09,-1.09L11.5,2.5L8,6l3.5,3.5l1.41,-1.41l-1.08,-1.08C11.89,7.01 11.95,7 12,7c3.31,0 6,2.69 6,6c0,2.97 -2.17,5.43 -5,5.91v2.02C16.95,20.44 20,17.08 20,13z"/>
+ </group>
</vector>
diff --git a/libs/WindowManager/Shell/res/layout/bubble_overflow_view.xml b/libs/WindowManager/Shell/res/layout/bubble_overflow_view.xml
index 544b731bb550..05b15060946d 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_overflow_view.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_overflow_view.xml
@@ -32,7 +32,7 @@
android:id="@+id/bubble_view_name"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textSize="13sp"
- android:layout_width="wrap_content"
+ android:layout_width="@dimen/bubble_name_width"
android:layout_height="wrap_content"
android:maxLines="1"
android:lines="2"
diff --git a/libs/WindowManager/Shell/res/layout/pip_menu.xml b/libs/WindowManager/Shell/res/layout/pip_menu.xml
index 9fe024748610..1dd17bad155b 100644
--- a/libs/WindowManager/Shell/res/layout/pip_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/pip_menu.xml
@@ -65,25 +65,29 @@
<LinearLayout
android:id="@+id/top_end_container"
android:layout_gravity="top|end"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
+
<ImageButton
android:id="@+id/settings"
android:layout_width="@dimen/pip_action_size"
android:layout_height="@dimen/pip_action_size"
android:contentDescription="@string/pip_phone_settings"
+ android:layout_gravity="top|start"
android:gravity="center"
android:src="@drawable/pip_ic_settings"
android:background="?android:selectableItemBackgroundBorderless" />
<ImageButton
- android:id="@+id/dismiss"
- android:layout_width="@dimen/pip_action_size"
- android:layout_height="@dimen/pip_action_size"
- android:contentDescription="@string/pip_phone_close"
+ android:id="@+id/enter_split"
+ android:layout_width="@dimen/pip_split_icon_size"
+ android:layout_height="@dimen/pip_split_icon_size"
+ android:layout_gravity="top|start"
+ android:layout_margin="@dimen/pip_split_icon_margin"
android:gravity="center"
- android:src="@drawable/pip_ic_close_white"
+ android:contentDescription="@string/pip_phone_enter_split"
+ android:src="@drawable/pip_split"
android:background="?android:selectableItemBackgroundBorderless" />
</LinearLayout>
@@ -97,4 +101,14 @@
android:padding="@dimen/pip_resize_handle_padding"
android:src="@drawable/pip_resize_handle"
android:background="?android:selectableItemBackgroundBorderless" />
+
+ <ImageButton
+ android:id="@+id/dismiss"
+ android:layout_width="@dimen/pip_action_size"
+ android:layout_height="@dimen/pip_action_size"
+ android:contentDescription="@string/pip_phone_close"
+ android:layout_gravity="top|end"
+ android:gravity="center"
+ android:src="@drawable/pip_ic_close_white"
+ android:background="?android:selectableItemBackgroundBorderless" />
</FrameLayout>
diff --git a/libs/WindowManager/Shell/res/layout/size_compat_mode_hint.xml b/libs/WindowManager/Shell/res/layout/size_compat_mode_hint.xml
index 0dea87c6b7fc..17347f627049 100644
--- a/libs/WindowManager/Shell/res/layout/size_compat_mode_hint.xml
+++ b/libs/WindowManager/Shell/res/layout/size_compat_mode_hint.xml
@@ -22,41 +22,34 @@
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:gravity="center"
android:clipToPadding="false"
- android:padding="@dimen/bubble_elevation">
+ android:paddingBottom="5dp">
<LinearLayout
+ android:id="@+id/size_compat_hint_popup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:background="@android:color/background_light"
- android:elevation="@dimen/bubble_elevation"
- android:orientation="vertical">
+ android:orientation="vertical"
+ android:clickable="true">
<TextView
- android:layout_width="180dp"
+ android:layout_width="188dp"
android:layout_height="wrap_content"
- android:paddingLeft="10dp"
- android:paddingRight="10dp"
- android:paddingTop="10dp"
+ android:lineSpacingExtra="4sp"
+ android:background="@drawable/size_compat_hint_bubble"
+ android:padding="16dp"
android:text="@string/restart_button_description"
android:textAlignment="viewStart"
- android:textColor="@android:color/primary_text_light"
- android:textSize="16sp"/>
+ android:textColor="#E4E3DA"
+ android:textSize="14sp"/>
- <Button
- android:id="@+id/got_it"
+ <ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:includeFontPadding="false"
android:layout_gravity="end"
- android:minHeight="36dp"
- android:background="?android:attr/selectableItemBackground"
- android:text="@string/got_it"
- android:textAllCaps="true"
- android:textColor="#3c78d8"
- android:textSize="16sp"
- android:textStyle="bold"/>
+ android:src="@drawable/size_compat_hint_point"
+ android:paddingHorizontal="@dimen/size_compat_hint_corner_radius"
+ android:contentDescription="@null"/>
</LinearLayout>
diff --git a/libs/WindowManager/Shell/res/layout/size_compat_ui.xml b/libs/WindowManager/Shell/res/layout/size_compat_ui.xml
index cd3153145be3..47e76f061877 100644
--- a/libs/WindowManager/Shell/res/layout/size_compat_ui.xml
+++ b/libs/WindowManager/Shell/res/layout/size_compat_ui.xml
@@ -19,12 +19,21 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content">
- <ImageButton
- android:id="@+id/size_compat_restart_button"
- android:layout_width="@dimen/size_compat_button_size"
- android:layout_height="@dimen/size_compat_button_size"
- android:layout_gravity="center"
- android:src="@drawable/size_compat_restart_button"
- android:contentDescription="@string/restart_button_description"/>
+ <FrameLayout
+ android:layout_width="@dimen/size_compat_button_width"
+ android:layout_height="@dimen/size_compat_button_height"
+ android:clipToPadding="false"
+ android:paddingBottom="16dp">
+
+ <ImageButton
+ android:id="@+id/size_compat_restart_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:src="@drawable/size_compat_restart_button"
+ android:background="@android:color/transparent"
+ android:contentDescription="@string/restart_button_description"/>
+
+ </FrameLayout>
</com.android.wm.shell.sizecompatui.SizeCompatRestartButton>
diff --git a/packages/SystemUI/res/drawable/screenrecord_switch_track.xml b/libs/WindowManager/Shell/res/layout/split_decor.xml
index 82595e4d6d65..9ffa5e8aa179 100644
--- a/packages/SystemUI/res/drawable/screenrecord_switch_track.xml
+++ b/libs/WindowManager/Shell/res/layout/split_decor.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2021 The Android Open Source Project
~
@@ -14,11 +13,18 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<shape
+
+<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle"
- android:width="52dp"
- android:height="28dp">
- <solid android:color="@color/screenrecord_switch_track_color" />
- <corners android:radius="35dp" />
-</shape> \ No newline at end of file
+ android:layout_height="match_parent"
+ android:layout_width="match_parent">
+
+ <ImageView android:id="@+id/split_resizing_icon"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center"
+ android:padding="0dp"
+ android:visibility="gone"
+ android:background="@null"/>
+
+</FrameLayout>
diff --git a/libs/WindowManager/Shell/res/layout/split_outline.xml b/libs/WindowManager/Shell/res/layout/split_outline.xml
index 13a30f5a0423..6cb9ebb72790 100644
--- a/libs/WindowManager/Shell/res/layout/split_outline.xml
+++ b/libs/WindowManager/Shell/res/layout/split_outline.xml
@@ -1,18 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
+<!--
+ ~ 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.
+ -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
diff --git a/libs/WindowManager/Shell/res/values-land/styles.xml b/libs/WindowManager/Shell/res/values-land/styles.xml
index 9eddac48e6de..0ed9368aa067 100644
--- a/libs/WindowManager/Shell/res/values-land/styles.xml
+++ b/libs/WindowManager/Shell/res/values-land/styles.xml
@@ -23,7 +23,7 @@
</style>
<style name="DockedDividerHandle">
- <item name="android:layout_gravity">center_vertical</item>
+ <item name="android:layout_gravity">center</item>
<item name="android:layout_width">48dp</item>
<item name="android:layout_height">96dp</item>
</style>
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index 93c0352a2ad3..b25a2189cd4d 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -29,6 +29,7 @@
<color name="bubbles_light">#FFFFFF</color>
<color name="bubbles_dark">@color/GM2_grey_800</color>
<color name="bubbles_icon_tint">@color/GM2_grey_700</color>
+ <color name="size_compat_hint_bubble">#30312B</color>
<!-- GM2 colors -->
<color name="GM2_grey_200">#E8EAED</color>
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index d0e4f7a02ffc..0cdaa206c156 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -15,6 +15,10 @@
limitations under the License.
-->
<resources>
+ <!-- Determines whether the shell features all run on another thread. This is to be overrided
+ by the resources of the app using the Shell library. -->
+ <bool name="config_enableShellMainThread">false</bool>
+
<!-- Animation duration for PIP when entering. -->
<integer name="config_pipEnterAnimationDuration">425</integer>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index f85766437b44..9e77578eafd8 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -67,6 +67,10 @@
<dimen name="pip_resize_handle_margin">4dp</dimen>
<dimen name="pip_resize_handle_padding">0dp</dimen>
+ <!-- PIP Split icon size and margin. -->
+ <dimen name="pip_split_icon_size">24dp</dimen>
+ <dimen name="pip_split_icon_margin">12dp</dimen>
+
<!-- PIP stash offset size, which is the width of visible PIP region when stashed. -->
<dimen name="pip_stash_offset">32dp</dimen>
@@ -115,6 +119,8 @@
<dimen name="bubble_spacing">3dp</dimen>
<!-- Size of the bubble. -->
<dimen name="bubble_size">60dp</dimen>
+ <!-- Width of bubble name view -->
+ <dimen name="bubble_name_width">90dp</dimen>
<!-- Size of the badge shown on the bubble. -->
<dimen name="bubble_badge_size">24dp</dimen>
<!-- Extra padding added to the touchable rect for bubbles so they are easier to grab. -->
@@ -194,8 +200,17 @@
<!-- Size of user education views on large screens (phone is just match parent). -->
<dimen name="bubbles_user_education_width_large_screen">400dp</dimen>
- <!-- The width/height of the size compat restart button. -->
- <dimen name="size_compat_button_size">48dp</dimen>
+ <!-- The width of the size compat restart button including padding. -->
+ <dimen name="size_compat_button_width">80dp</dimen>
+
+ <!-- The height of the size compat restart button including padding. -->
+ <dimen name="size_compat_button_height">64dp</dimen>
+
+ <!-- The radius of the corners of the size compat hint bubble. -->
+ <dimen name="size_compat_hint_corner_radius">28dp</dimen>
+
+ <!-- The width of the size compat hint point. -->
+ <dimen name="size_compat_hint_point_width">10dp</dimen>
<!-- The width of the brand image on staring surface. -->
<dimen name="starting_surface_brand_image_width">200dp</dimen>
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index e512698ab66c..c88fc16e218e 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -24,6 +24,9 @@
<!-- Label for PIP settings button [CHAR LIMIT=NONE]-->
<string name="pip_phone_settings">Settings</string>
+ <!-- Label for the PIP enter split button [CHAR LIMIT=NONE] -->
+ <string name="pip_phone_enter_split">Enter split screen</string>
+
<!-- Title of menu shown over picture-in-picture. Used for accessibility. -->
<string name="pip_menu_title">Menu</string>
@@ -155,7 +158,4 @@
<!-- Description of the restart button in the hint of size compatibility mode. [CHAR LIMIT=NONE] -->
<string name="restart_button_description">Tap to restart this app and go full screen.</string>
-
- <!-- Generic "got it" acceptance of dialog or cling [CHAR LIMIT=NONE] -->
- <string name="got_it">Got it</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml
index cb6d4de71a45..7733201d2465 100644
--- a/libs/WindowManager/Shell/res/values/styles.xml
+++ b/libs/WindowManager/Shell/res/values/styles.xml
@@ -43,7 +43,7 @@
</style>
<style name="DockedDividerHandle">
- <item name="android:layout_gravity">center_horizontal</item>
+ <item name="android:layout_gravity">center</item>
<item name="android:layout_width">96dp</item>
<item name="android:layout_height">48dp</item>
</style>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
index 9113c79d40f8..358553d70501 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
@@ -24,6 +24,7 @@ import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.Pip;
+import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.io.PrintWriter;
@@ -43,6 +44,7 @@ public final class ShellCommandHandlerImpl {
private final Optional<OneHandedController> mOneHandedOptional;
private final Optional<HideDisplayCutoutController> mHideDisplayCutout;
private final Optional<AppPairsController> mAppPairsOptional;
+ private final Optional<RecentTasksController> mRecentTasks;
private final ShellTaskOrganizer mShellTaskOrganizer;
private final ShellExecutor mMainExecutor;
private final HandlerImpl mImpl = new HandlerImpl();
@@ -55,8 +57,10 @@ public final class ShellCommandHandlerImpl {
Optional<OneHandedController> oneHandedOptional,
Optional<HideDisplayCutoutController> hideDisplayCutout,
Optional<AppPairsController> appPairsOptional,
+ Optional<RecentTasksController> recentTasks,
ShellExecutor mainExecutor) {
mShellTaskOrganizer = shellTaskOrganizer;
+ mRecentTasks = recentTasks;
mLegacySplitScreenOptional = legacySplitScreenOptional;
mSplitScreenOptional = splitScreenOptional;
mPipOptional = pipOptional;
@@ -85,6 +89,9 @@ public final class ShellCommandHandlerImpl {
pw.println();
pw.println();
mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.dump(pw, ""));
+ pw.println();
+ pw.println();
+ mRecentTasks.ifPresent(recentTasks -> recentTasks.dump(pw, ""));
}
@@ -103,8 +110,6 @@ public final class ShellCommandHandlerImpl {
return runMoveToSideStage(args, pw);
case "removeFromSideStage":
return runRemoveFromSideStage(args, pw);
- case "setSideStageOutline":
- return runSetSideStageOutline(args, pw);
case "setSideStagePosition":
return runSetSideStagePosition(args, pw);
case "setSideStageVisibility":
@@ -163,18 +168,6 @@ public final class ShellCommandHandlerImpl {
return true;
}
- private boolean runSetSideStageOutline(String[] args, PrintWriter pw) {
- if (args.length < 3) {
- // First arguments are "WMShell" and command name.
- pw.println("Error: whether to enable or disable side stage outline border should be"
- + " provided as arguments");
- return false;
- }
- final boolean enable = new Boolean(args[2]);
- mSplitScreenOptional.ifPresent(split -> split.setSideStageOutline(enable));
- return true;
- }
-
private boolean runSetSideStagePosition(String[] args, PrintWriter pw) {
if (args.length < 3) {
// First arguments are "WMShell" and command name.
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 fa58fcda3d3b..f5678776ed78 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
@@ -29,8 +29,8 @@ import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformTaskListener;
import com.android.wm.shell.fullscreen.FullscreenTaskListener;
import com.android.wm.shell.fullscreen.FullscreenUnfoldController;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.pip.phone.PipTouchHandler;
+import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.startingsurface.StartingWindowController;
import com.android.wm.shell.transition.Transitions;
@@ -49,7 +49,6 @@ public class ShellInitImpl {
private final DragAndDropController mDragAndDropController;
private final ShellTaskOrganizer mShellTaskOrganizer;
private final Optional<BubbleController> mBubblesOptional;
- private final Optional<LegacySplitScreenController> mLegacySplitScreenOptional;
private final Optional<SplitScreenController> mSplitScreenOptional;
private final Optional<AppPairsController> mAppPairsOptional;
private final Optional<PipTouchHandler> mPipTouchHandlerOptional;
@@ -59,6 +58,7 @@ public class ShellInitImpl {
private final ShellExecutor mMainExecutor;
private final Transitions mTransitions;
private final StartingWindowController mStartingWindow;
+ private final Optional<RecentTasksController> mRecentTasks;
private final InitImpl mImpl = new InitImpl();
@@ -69,13 +69,13 @@ public class ShellInitImpl {
DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer,
Optional<BubbleController> bubblesOptional,
- Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<AppPairsController> appPairsOptional,
Optional<PipTouchHandler> pipTouchHandlerOptional,
FullscreenTaskListener fullscreenTaskListener,
Optional<FullscreenUnfoldController> fullscreenUnfoldTransitionController,
Optional<Optional<FreeformTaskListener>> freeformTaskListenerOptional,
+ Optional<RecentTasksController> recentTasks,
Transitions transitions,
StartingWindowController startingWindow,
ShellExecutor mainExecutor) {
@@ -85,13 +85,13 @@ public class ShellInitImpl {
mDragAndDropController = dragAndDropController;
mShellTaskOrganizer = shellTaskOrganizer;
mBubblesOptional = bubblesOptional;
- mLegacySplitScreenOptional = legacySplitScreenOptional;
mSplitScreenOptional = splitScreenOptional;
mAppPairsOptional = appPairsOptional;
mFullscreenTaskListener = fullscreenTaskListener;
mPipTouchHandlerOptional = pipTouchHandlerOptional;
mFullscreenUnfoldController = fullscreenUnfoldTransitionController;
mFreeformTaskListenerOptional = freeformTaskListenerOptional.flatMap(f -> f);
+ mRecentTasks = recentTasks;
mTransitions = transitions;
mMainExecutor = mainExecutor;
mStartingWindow = startingWindow;
@@ -135,6 +135,7 @@ public class ShellInitImpl {
f, ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM));
mFullscreenUnfoldController.ifPresent(FullscreenUnfoldController::init);
+ mRecentTasks.ifPresent(RecentTasksController::init);
}
@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 020ecb7186ed..75bc46125324 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -51,6 +51,7 @@ import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.FrameworkStatsLog;
import com.android.wm.shell.common.ScreenshotUtils;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.sizecompatui.SizeCompatUIController;
import com.android.wm.shell.startingsurface.StartingWindowController;
@@ -59,6 +60,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import java.util.function.Consumer;
/**
@@ -150,20 +152,34 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
@Nullable
private final SizeCompatUIController mSizeCompatUI;
+ @Nullable
+ private final Optional<RecentTasksController> mRecentTasks;
+
public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context) {
- this(null /* taskOrganizerController */, mainExecutor, context, null /* sizeCompatUI */);
+ this(null /* taskOrganizerController */, mainExecutor, context, null /* sizeCompatUI */,
+ Optional.empty() /* recentTasksController */);
}
public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context, @Nullable
SizeCompatUIController sizeCompatUI) {
- this(null /* taskOrganizerController */, mainExecutor, context, sizeCompatUI);
+ this(null /* taskOrganizerController */, mainExecutor, context, sizeCompatUI,
+ Optional.empty() /* recentTasksController */);
+ }
+
+ public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context, @Nullable
+ SizeCompatUIController sizeCompatUI,
+ Optional<RecentTasksController> recentTasks) {
+ this(null /* taskOrganizerController */, mainExecutor, context, sizeCompatUI,
+ recentTasks);
}
@VisibleForTesting
ShellTaskOrganizer(ITaskOrganizerController taskOrganizerController, ShellExecutor mainExecutor,
- Context context, @Nullable SizeCompatUIController sizeCompatUI) {
+ Context context, @Nullable SizeCompatUIController sizeCompatUI,
+ Optional<RecentTasksController> recentTasks) {
super(taskOrganizerController, mainExecutor);
mSizeCompatUI = sizeCompatUI;
+ mRecentTasks = recentTasks;
if (sizeCompatUI != null) {
sizeCompatUI.setSizeCompatUICallback(this);
}
@@ -401,6 +417,11 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
// Notify the size compat UI if the listener or task info changed.
notifySizeCompatUI(taskInfo, newListener);
}
+ if (data.getTaskInfo().getWindowingMode() != taskInfo.getWindowingMode()) {
+ // Notify the recent tasks when a task changes windowing modes
+ mRecentTasks.ifPresent(recentTasks ->
+ recentTasks.onTaskWindowingModeChanged(taskInfo));
+ }
}
}
@@ -428,6 +449,8 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
notifyLocusVisibilityIfNeeded(taskInfo);
// Pass null for listener to remove the size compat UI on this task if there is any.
notifySizeCompatUI(taskInfo, null /* taskListener */);
+ // Notify the recent tasks that a task has been removed
+ mRecentTasks.ifPresent(recentTasks -> recentTasks.onTaskRemoved(taskInfo));
}
}
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 6a252e0d7dcb..c8449a362988 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
@@ -131,7 +131,8 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou
mSplitLayout = new SplitLayout(TAG + "SplitDivider",
mDisplayController.getDisplayContext(mRootTaskInfo.displayId),
mRootTaskInfo.configuration, this /* layoutChangeListener */,
- mParentContainerCallbacks, mDisplayImeController, mController.getTaskOrganizer());
+ mParentContainerCallbacks, mDisplayImeController, mController.getTaskOrganizer(),
+ true /* applyDismissingParallax */);
mDisplayInsetsController.addInsetsChangedListener(mRootTaskInfo.displayId, mSplitLayout);
final WindowContainerToken token1 = task1.token;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index b6d65bebff28..caa532761f1c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -1028,15 +1028,17 @@ public class BubbleController {
// If this entry is no longer allowed to bubble, dismiss with the BLOCKED reason.
// This means that the app or channel's ability to bubble has been revoked.
mBubbleData.dismissBubbleWithKey(key, DISMISS_BLOCKED);
- } else if (isActiveBubble && !shouldBubbleUp) {
- // If this entry is allowed to bubble, but cannot currently bubble up, dismiss it.
- // This happens when DND is enabled and configured to hide bubbles. Dismissing with
- // the reason DISMISS_NO_BUBBLE_UP will retain the underlying notification, so that
- // the bubble will be re-created if shouldBubbleUp returns true.
+ } else if (isActiveBubble && (!shouldBubbleUp || entry.getRanking().isSuspended())) {
+ // If this entry is allowed to bubble, but cannot currently bubble up or is
+ // suspended, dismiss it. This happens when DND is enabled and configured to hide
+ // bubbles, or focus mode is enabled and the app is designated as distracting.
+ // Dismissing with the reason DISMISS_NO_BUBBLE_UP will retain the underlying
+ // notification, so that the bubble will be re-created if shouldBubbleUp returns
+ // true.
mBubbleData.dismissBubbleWithKey(key, DISMISS_NO_BUBBLE_UP);
} else if (entry != null && mTmpRanking.isBubble() && !isActiveBubble) {
entry.setFlagBubble(true);
- onEntryUpdated(entry, true /* shouldBubbleUp */);
+ onEntryUpdated(entry, shouldBubbleUp && !entry.getRanking().isSuspended());
}
}
}
@@ -1134,7 +1136,8 @@ public class BubbleController {
if (reason == DISMISS_USER_CHANGED || reason == DISMISS_NO_BUBBLE_UP) {
continue;
}
- if (reason == DISMISS_NOTIF_CANCEL) {
+ if (reason == DISMISS_NOTIF_CANCEL
+ || reason == DISMISS_SHORTCUT_REMOVED) {
bubblesToBeRemovedFromRepository.add(bubble);
}
if (!mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SingleInstanceRemoteListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SingleInstanceRemoteListener.java
new file mode 100644
index 000000000000..b77ac8a2b951
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SingleInstanceRemoteListener.java
@@ -0,0 +1,123 @@
+/*
+ * 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.common;
+
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import androidx.annotation.BinderThread;
+
+import java.util.function.Consumer;
+
+/**
+ * Manages the lifecycle of a single instance of a remote listener, including the clean up if the
+ * remote process dies. All calls on this class should happen on the main shell thread.
+ *
+ * @param <C> The controller (must be RemoteCallable)
+ * @param <L> The remote listener interface type
+ */
+public class SingleInstanceRemoteListener<C extends RemoteCallable, L extends IInterface> {
+ private static final String TAG = SingleInstanceRemoteListener.class.getSimpleName();
+
+ /**
+ * Simple callable interface that throws a remote exception.
+ */
+ public interface RemoteCall<L> {
+ void accept(L l) throws RemoteException;
+ }
+
+ private final C mCallableController;
+ private final Consumer<C> mOnRegisterCallback;
+ private final Consumer<C> mOnUnregisterCallback;
+
+ L mListener;
+
+ private final IBinder.DeathRecipient mListenerDeathRecipient =
+ new IBinder.DeathRecipient() {
+ @Override
+ @BinderThread
+ public void binderDied() {
+ final C callableController = mCallableController;
+ mCallableController.getRemoteCallExecutor().execute(() -> {
+ mListener = null;
+ mOnUnregisterCallback.accept(callableController);
+ });
+ }
+ };
+
+ /**
+ * @param onRegisterCallback Callback when register() is called (same thread)
+ * @param onUnregisterCallback Callback when unregister() is called (same thread as unregister()
+ * or the callableController.getRemoteCallbackExecutor() thread)
+ */
+ public SingleInstanceRemoteListener(C callableController,
+ Consumer<C> onRegisterCallback,
+ Consumer<C> onUnregisterCallback) {
+ mCallableController = callableController;
+ mOnRegisterCallback = onRegisterCallback;
+ mOnUnregisterCallback = onUnregisterCallback;
+ }
+
+ /**
+ * Registers this listener, storing a reference to it and calls the provided method in the
+ * constructor.
+ */
+ public void register(L listener) {
+ if (mListener != null) {
+ mListener.asBinder().unlinkToDeath(mListenerDeathRecipient, 0 /* flags */);
+ }
+ if (listener != null) {
+ try {
+ listener.asBinder().linkToDeath(mListenerDeathRecipient, 0 /* flags */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to link to death");
+ return;
+ }
+ }
+ mListener = listener;
+ mOnRegisterCallback.accept(mCallableController);
+ }
+
+ /**
+ * Unregisters this listener, removing all references to it and calls the provided method in the
+ * constructor.
+ */
+ public void unregister() {
+ if (mListener != null) {
+ mListener.asBinder().unlinkToDeath(mListenerDeathRecipient, 0 /* flags */);
+ }
+ mListener = null;
+ mOnUnregisterCallback.accept(mCallableController);
+ }
+
+ /**
+ * Safely wraps a call to the remote listener.
+ */
+ public void call(RemoteCall<L> handler) {
+ if (mListener == null) {
+ Slog.e(TAG, "Failed remote call on null listener");
+ return;
+ }
+ try {
+ handler.accept(mListener);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed remote call", e);
+ }
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SurfaceUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SurfaceUtils.java
index 55c5125f0a00..4b138e43bc3f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SurfaceUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SurfaceUtils.java
@@ -23,16 +23,22 @@ import android.view.SurfaceSession;
* Helpers for handling surface.
*/
public class SurfaceUtils {
- /** Creates a dim layer above indicated host surface. */
+ /** Creates a dim layer above host surface. */
public static SurfaceControl makeDimLayer(SurfaceControl.Transaction t, SurfaceControl host,
String name, SurfaceSession surfaceSession) {
- SurfaceControl dimLayer = new SurfaceControl.Builder(surfaceSession)
+ final SurfaceControl dimLayer = makeColorLayer(host, name, surfaceSession);
+ t.setLayer(dimLayer, Integer.MAX_VALUE).setColor(dimLayer, new float[]{0f, 0f, 0f});
+ return dimLayer;
+ }
+
+ /** Creates a color layer for host surface. */
+ public static SurfaceControl makeColorLayer(SurfaceControl host, String name,
+ SurfaceSession surfaceSession) {
+ return new SurfaceControl.Builder(surfaceSession)
.setParent(host)
.setColorLayer()
.setName(name)
- .setCallsite("SurfaceUtils.makeDimLayer")
+ .setCallsite("SurfaceUtils.makeColorLayer")
.build();
- t.setLayer(dimLayer, Integer.MAX_VALUE).setColor(dimLayer, new float[]{0f, 0f, 0f});
- return dimLayer;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ExternalMainThread.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ExternalMainThread.java
new file mode 100644
index 000000000000..9ac7a12bc509
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ExternalMainThread.java
@@ -0,0 +1,34 @@
+/*
+ * 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.common.annotations;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/**
+ * Annotates a method or qualifies a provider that runs on the main-thread of the process using
+ * this library.
+ */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface ExternalMainThread {
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index 6ea806bd3799..4b125b118ceb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -19,6 +19,8 @@ package com.android.wm.shell.common.split;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Rect;
@@ -57,6 +59,7 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
private final int mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
private SplitLayout mSplitLayout;
+ private SplitWindowManager mSplitWindowManager;
private SurfaceControlViewHost mViewHost;
private DividerHandleView mHandle;
private View mBackground;
@@ -67,6 +70,7 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
private int mStartPos;
private GestureDetector mDoubleTapDetector;
private boolean mInteractive;
+ private boolean mSetTouchRegion = true;
/**
* Tracks divider bar visible bounds in screen-based coordination. Used to calculate with
@@ -93,6 +97,18 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
}
};
+ private AnimatorListenerAdapter mAnimatorListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mSetTouchRegion = true;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mSetTouchRegion = true;
+ }
+ };
+
public DividerView(@NonNull Context context) {
super(context);
}
@@ -114,9 +130,11 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
/** Sets up essential dependencies of the divider bar. */
public void setup(
SplitLayout layout,
+ SplitWindowManager splitWindowManager,
SurfaceControlViewHost viewHost,
InsetsState insetsState) {
mSplitLayout = layout;
+ mSplitWindowManager = splitWindowManager;
mViewHost = viewHost;
mDividerBounds.set(layout.getDividerBounds());
onInsetsChanged(insetsState, false /* animate */);
@@ -138,9 +156,11 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
DIVIDER_HEIGHT_PROPERTY, mDividerBounds.height(), mTempRect.height());
animator.setInterpolator(InsetsController.RESIZE_INTERPOLATOR);
animator.setDuration(InsetsController.ANIMATION_DURATION_RESIZE);
+ animator.addListener(mAnimatorListener);
animator.start();
} else {
DIVIDER_HEIGHT_PROPERTY.set(this, mTempRect.height());
+ mSetTouchRegion = true;
}
mDividerBounds.set(mTempRect);
}
@@ -162,6 +182,17 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
}
@Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ if (mSetTouchRegion) {
+ mTempRect.set(mHandle.getLeft(), mHandle.getTop(), mHandle.getRight(),
+ mHandle.getBottom());
+ mSplitWindowManager.setTouchRegion(mTempRect);
+ mSetTouchRegion = false;
+ }
+ }
+
+ @Override
public boolean onTouch(View v, MotionEvent event) {
if (mSplitLayout == null || !mInteractive) {
return false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
new file mode 100644
index 000000000000..ad9ebb2ef6ae
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
@@ -0,0 +1,184 @@
+/*
+ * 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.common.split;
+
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static android.view.WindowManagerPolicyConstants.SPLIT_DIVIDER_LAYER;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Binder;
+import android.view.IWindow;
+import android.view.LayoutInflater;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+import android.view.SurfaceSession;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowlessWindowManager;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.android.launcher3.icons.IconProvider;
+import com.android.wm.shell.R;
+import com.android.wm.shell.common.SurfaceUtils;
+
+/**
+ * Handles split decor like showing resizing hint for a specific split.
+ */
+public class SplitDecorManager extends WindowlessWindowManager {
+ private static final String TAG = SplitDecorManager.class.getSimpleName();
+ private static final String RESIZING_BACKGROUND_SURFACE_NAME = "ResizingBackground";
+
+ private final IconProvider mIconProvider;
+ private final SurfaceSession mSurfaceSession;
+
+ private Drawable mIcon;
+ private ImageView mResizingIconView;
+ private SurfaceControlViewHost mViewHost;
+ private SurfaceControl mHostLeash;
+ private SurfaceControl mIconLeash;
+ private SurfaceControl mBackgroundLeash;
+
+ public SplitDecorManager(Configuration configuration, IconProvider iconProvider,
+ SurfaceSession surfaceSession) {
+ super(configuration, null /* rootSurface */, null /* hostInputToken */);
+ mIconProvider = iconProvider;
+ mSurfaceSession = surfaceSession;
+ }
+
+ @Override
+ protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
+ // Can't set position for the ViewRootImpl SC directly. Create a leash to manipulate later.
+ final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
+ .setContainerLayer()
+ .setName(TAG)
+ .setHidden(true)
+ .setParent(mHostLeash)
+ .setCallsite("SplitDecorManager#attachToParentSurface");
+ mIconLeash = builder.build();
+ b.setParent(mIconLeash);
+ }
+
+ /** Inflates split decor surface on the root surface. */
+ public void inflate(Context context, SurfaceControl rootLeash, Rect rootBounds) {
+ if (mIconLeash != null && mViewHost != null) {
+ return;
+ }
+
+ context = context.createWindowContext(context.getDisplay(), TYPE_APPLICATION_OVERLAY,
+ null /* options */);
+ mHostLeash = rootLeash;
+ mViewHost = new SurfaceControlViewHost(context, context.getDisplay(), this);
+
+ final FrameLayout rootLayout = (FrameLayout) LayoutInflater.from(context)
+ .inflate(R.layout.split_decor, null);
+ mResizingIconView = rootLayout.findViewById(R.id.split_resizing_icon);
+
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ 0 /* width */, 0 /* height */, TYPE_APPLICATION_OVERLAY,
+ FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT);
+ lp.width = rootBounds.width();
+ lp.height = rootBounds.height();
+ lp.token = new Binder();
+ lp.setTitle(TAG);
+ lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
+ // TODO(b/189839391): Set INPUT_FEATURE_NO_INPUT_CHANNEL after WM supports
+ // TRUSTED_OVERLAY for windowless window without input channel.
+ mViewHost.setView(rootLayout, lp);
+ }
+
+ /** Releases the surfaces for split decor. */
+ public void release(SurfaceControl.Transaction t) {
+ if (mViewHost != null) {
+ mViewHost.release();
+ mViewHost = null;
+ }
+ if (mIconLeash != null) {
+ t.remove(mIconLeash);
+ mIconLeash = null;
+ }
+ if (mBackgroundLeash != null) {
+ t.remove(mBackgroundLeash);
+ mBackgroundLeash = null;
+ }
+ mHostLeash = null;
+ mIcon = null;
+ mResizingIconView = null;
+ }
+
+ /** Showing resizing hint. */
+ public void onResizing(ActivityManager.RunningTaskInfo resizingTask, Rect newBounds,
+ SurfaceControl.Transaction t) {
+ if (mResizingIconView == null) {
+ return;
+ }
+
+ if (mIcon == null) {
+ // TODO: add fade-in animation.
+ mBackgroundLeash = SurfaceUtils.makeColorLayer(mHostLeash,
+ RESIZING_BACKGROUND_SURFACE_NAME, mSurfaceSession);
+ t.setColor(mBackgroundLeash, getResizingBackgroundColor(resizingTask))
+ .setLayer(mBackgroundLeash, SPLIT_DIVIDER_LAYER - 1)
+ .show(mBackgroundLeash);
+
+ mIcon = mIconProvider.getIcon(resizingTask.topActivityInfo);
+ mResizingIconView.setImageDrawable(mIcon);
+ mResizingIconView.setVisibility(View.VISIBLE);
+
+ WindowManager.LayoutParams lp =
+ (WindowManager.LayoutParams) mViewHost.getView().getLayoutParams();
+ lp.width = mIcon.getIntrinsicWidth();
+ lp.height = mIcon.getIntrinsicHeight();
+ mViewHost.relayout(lp);
+ t.show(mIconLeash).setLayer(mIconLeash, SPLIT_DIVIDER_LAYER);
+ }
+
+ t.setPosition(mIconLeash,
+ newBounds.width() / 2 - mIcon.getIntrinsicWidth() / 2,
+ newBounds.height() / 2 - mIcon.getIntrinsicWidth() / 2);
+ }
+
+ /** Stops showing resizing hint. */
+ public void onResized(Rect newBounds, SurfaceControl.Transaction t) {
+ if (mResizingIconView == null) {
+ return;
+ }
+
+ if (mIcon != null) {
+ mResizingIconView.setVisibility(View.GONE);
+ mResizingIconView.setImageDrawable(null);
+ t.remove(mBackgroundLeash).hide(mIconLeash);
+ mIcon = null;
+ mBackgroundLeash = null;
+ }
+ }
+
+ private static float[] getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo) {
+ final int taskBgColor = taskInfo.taskDescription.getBackgroundColor();
+ return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor).getComponents();
+ }
+}
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 5b3ce2dbaeb9..625bcee673b5 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
@@ -40,8 +40,10 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
+import android.view.Display;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
+import android.view.RoundedCorner;
import android.view.SurfaceControl;
import android.view.WindowInsets;
import android.view.WindowManager;
@@ -53,6 +55,7 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.internal.policy.DockedDividerUtils;
+import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.DisplayImeController;
@@ -103,7 +106,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
private final SplitWindowManager mSplitWindowManager;
private final DisplayImeController mDisplayImeController;
private final ImePositionProcessor mImePositionProcessor;
- private final DismissingParallaxPolicy mDismissingParallaxPolicy;
+ private final DismissingEffectPolicy mDismissingEffectPolicy;
private final ShellTaskOrganizer mTaskOrganizer;
private final InsetsState mInsetsState = new InsetsState();
@@ -119,7 +122,8 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
public SplitLayout(String windowName, Context context, Configuration configuration,
SplitLayoutHandler splitLayoutHandler,
SplitWindowManager.ParentContainerCallbacks parentContainerCallbacks,
- DisplayImeController displayImeController, ShellTaskOrganizer taskOrganizer) {
+ DisplayImeController displayImeController, ShellTaskOrganizer taskOrganizer,
+ boolean applyDismissingParallax) {
mContext = context.createConfigurationContext(configuration);
mOrientation = configuration.orientation;
mRotation = configuration.windowConfiguration.getRotation();
@@ -129,20 +133,35 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
parentContainerCallbacks);
mTaskOrganizer = taskOrganizer;
mImePositionProcessor = new ImePositionProcessor(mContext.getDisplayId());
- mDismissingParallaxPolicy = new DismissingParallaxPolicy();
+ mDismissingEffectPolicy = new DismissingEffectPolicy(applyDismissingParallax);
final Resources resources = context.getResources();
- mDividerWindowWidth = resources.getDimensionPixelSize(
- com.android.internal.R.dimen.docked_stack_divider_thickness);
- mDividerInsets = resources.getDimensionPixelSize(
- com.android.internal.R.dimen.docked_stack_divider_insets);
- mDividerSize = mDividerWindowWidth - mDividerInsets * 2;
+ mDividerSize = resources.getDimensionPixelSize(R.dimen.split_divider_bar_width);
+ mDividerInsets = getDividerInsets(resources, context.getDisplay());
+ mDividerWindowWidth = mDividerSize + 2 * mDividerInsets;
mRootBounds.set(configuration.windowConfiguration.getBounds());
mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds);
resetDividerPosition();
}
+ private int getDividerInsets(Resources resources, Display display) {
+ final int dividerInset = resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.docked_stack_divider_insets);
+
+ int radius = 0;
+ RoundedCorner corner = display.getRoundedCorner(RoundedCorner.POSITION_TOP_LEFT);
+ radius = corner != null ? Math.max(radius, corner.getRadius()) : radius;
+ corner = display.getRoundedCorner(RoundedCorner.POSITION_TOP_RIGHT);
+ radius = corner != null ? Math.max(radius, corner.getRadius()) : radius;
+ corner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT);
+ radius = corner != null ? Math.max(radius, corner.getRadius()) : radius;
+ corner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT);
+ radius = corner != null ? Math.max(radius, corner.getRadius()) : radius;
+
+ return Math.max(dividerInset, radius);
+ }
+
/** Gets bounds of the primary split. */
public Rect getBounds1() {
return new Rect(mBounds1);
@@ -247,7 +266,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
}
DockedDividerUtils.sanitizeStackBounds(mBounds1, true /** topLeft */);
DockedDividerUtils.sanitizeStackBounds(mBounds2, false /** topLeft */);
- mDismissingParallaxPolicy.applyDividerPosition(position, isLandscape);
+ mDismissingEffectPolicy.applyDividerPosition(position, isLandscape);
}
/** Inflates {@link DividerView} on the root surface. */
@@ -290,7 +309,6 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
*/
void updateDivideBounds(int position) {
updateBounds(position);
- mSplitWindowManager.setResizingSplits(true);
mSplitLayoutHandler.onLayoutSizeChanging(this);
}
@@ -298,13 +316,11 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
mDividePosition = position;
updateBounds(mDividePosition);
mSplitLayoutHandler.onLayoutSizeChanged(this);
- mSplitWindowManager.setResizingSplits(false);
}
/** Resets divider position. */
public void resetDividerPosition() {
mDividePosition = mDividerSnapAlgorithm.getMiddleTarget().position;
- mSplitWindowManager.setResizingSplits(false);
updateBounds(mDividePosition);
mWinToken1 = null;
mWinToken2 = null;
@@ -360,8 +376,8 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
@VisibleForTesting
void flingDividePosition(int from, int to, @Nullable Runnable flingFinishedCallback) {
if (from == to) {
- // No animation run, it should stop resizing here.
- mSplitWindowManager.setResizingSplits(false);
+ // No animation run, still callback to stop resizing.
+ mSplitLayoutHandler.onLayoutSizeChanged(this);
return;
}
ValueAnimator animator = ValueAnimator
@@ -425,7 +441,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
return;
}
- mDismissingParallaxPolicy.adjustDismissingSurface(t, leash1, leash2, dimLayer1, dimLayer2);
+ mDismissingEffectPolicy.adjustDismissingSurface(t, leash1, leash2, dimLayer1, dimLayer2);
}
/** Apply recorded task layout to the {@link WindowContainerTransaction}. */
@@ -543,7 +559,10 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
* Calculates and applies proper dismissing parallax offset and dimming value to hint users
* dismissing gesture.
*/
- private class DismissingParallaxPolicy {
+ private class DismissingEffectPolicy {
+ /** Indicates whether to offset splitting bounds to hint dismissing progress or not. */
+ private final boolean mApplyParallax;
+
// The current dismissing side.
int mDismissingSide = DOCKED_INVALID;
@@ -553,6 +572,10 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
// The dimming value to hint the dismissing side and progress.
float mDismissingDimValue = 0.0f;
+ DismissingEffectPolicy(boolean applyDismissingParallax) {
+ mApplyParallax = applyDismissingParallax;
+ }
+
/**
* Applies a parallax to the task to hint dismissing progress.
*
@@ -565,11 +588,11 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
mDismissingDimValue = 0;
int totalDismissingDistance = 0;
- if (position <= mDividerSnapAlgorithm.getFirstSplitTarget().position) {
+ if (position < mDividerSnapAlgorithm.getFirstSplitTarget().position) {
mDismissingSide = isLandscape ? DOCKED_LEFT : DOCKED_TOP;
totalDismissingDistance = mDividerSnapAlgorithm.getDismissStartTarget().position
- mDividerSnapAlgorithm.getFirstSplitTarget().position;
- } else if (position >= mDividerSnapAlgorithm.getLastSplitTarget().position) {
+ } else if (position > mDividerSnapAlgorithm.getLastSplitTarget().position) {
mDismissingSide = isLandscape ? DOCKED_RIGHT : DOCKED_BOTTOM;
totalDismissingDistance = mDividerSnapAlgorithm.getLastSplitTarget().position
- mDividerSnapAlgorithm.getDismissEndTarget().position;
@@ -627,12 +650,14 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
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);
+ if (mApplyParallax) {
+ 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;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
index 47dceb392183..4903f9d46dc7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
@@ -25,16 +25,12 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Binder;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Slog;
import android.view.IWindow;
import android.view.InsetsState;
import android.view.LayoutInflater;
@@ -44,6 +40,7 @@ import android.view.SurfaceSession;
import android.view.WindowManager;
import android.view.WindowlessWindowManager;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.wm.shell.R;
@@ -59,7 +56,6 @@ public final class SplitWindowManager extends WindowlessWindowManager {
private Context mContext;
private SurfaceControlViewHost mViewHost;
private SurfaceControl mLeash;
- private boolean mResizingSplits;
private DividerView mDividerView;
public interface ParentContainerCallbacks {
@@ -75,9 +71,10 @@ public final class SplitWindowManager extends WindowlessWindowManager {
mWindowName = windowName;
}
- @Override
- public void setTouchRegion(IBinder window, Region region) {
- super.setTouchRegion(window, region);
+ void setTouchRegion(@NonNull Rect region) {
+ if (mViewHost != null) {
+ setTouchRegion(mViewHost.getWindowToken().asBinder(), new Region(region));
+ }
}
@Override
@@ -126,7 +123,7 @@ public final class SplitWindowManager extends WindowlessWindowManager {
lp.setTitle(mWindowName);
lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
mViewHost.setView(mDividerView, lp);
- mDividerView.setup(splitLayout, mViewHost, insetsState);
+ mDividerView.setup(splitLayout, this, mViewHost, insetsState);
}
/**
@@ -154,16 +151,6 @@ public final class SplitWindowManager extends WindowlessWindowManager {
mDividerView.setInteractive(interactive);
}
- void setResizingSplits(boolean resizing) {
- if (resizing == mResizingSplits) return;
- try {
- ActivityTaskManager.getService().setSplitScreenResizing(resizing);
- mResizingSplits = resizing;
- } catch (RemoteException e) {
- Slog.w(TAG, "Error calling setSplitScreenResizing", e);
- }
- }
-
/**
* Gets {@link SurfaceControl} of the surface holding divider view. @return {@code null} if not
* feasible.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/README.txt b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/README.txt
new file mode 100644
index 000000000000..1cd69edf7cd2
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/README.txt
@@ -0,0 +1,13 @@
+The dagger modules in this directory can be included by the host SysUI using the Shell library for
+explicity injection of Shell components. Apps using this library are not required to use these
+dagger modules for setup, but it is recommended for them to include them as needed.
+
+The modules are currently inherited as such:
+
++- WMShellBaseModule (common shell features across SysUI)
+ |
+ +- WMShellModule (handheld)
+ |
+ +- TvPipModule (tv pip)
+ |
+ +- TvWMShellModule (tv) \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
index 3be1d3cab869..711a0ac76702 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.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,12 +14,11 @@
* limitations under the License.
*/
-package com.android.systemui.wmshell;
+package com.android.wm.shell.dagger;
import android.content.Context;
import android.os.Handler;
-import com.android.systemui.dagger.WMSingleton;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
@@ -44,6 +43,7 @@ import com.android.wm.shell.pip.tv.TvPipController;
import com.android.wm.shell.pip.tv.TvPipMenuController;
import com.android.wm.shell.pip.tv.TvPipNotificationController;
import com.android.wm.shell.pip.tv.TvPipTransition;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.transition.Transitions;
import java.util.Optional;
@@ -161,13 +161,14 @@ public abstract class TvPipModule {
PipTransitionController pipTransitionController,
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
Optional<LegacySplitScreenController> splitScreenOptional,
+ Optional<SplitScreenController> newSplitScreenOptional,
DisplayController displayController,
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
@ShellMainThread ShellExecutor mainExecutor) {
return new PipTaskOrganizer(context,
syncTransactionQueue, pipTransitionState, pipBoundsState, pipBoundsAlgorithm,
tvPipMenuController, pipAnimationController, pipSurfaceTransactionHelper,
- pipTransitionController, splitScreenOptional, displayController, pipUiEventLogger,
- shellTaskOrganizer, mainExecutor);
+ pipTransitionController, splitScreenOptional, newSplitScreenOptional,
+ displayController, pipUiEventLogger, shellTaskOrganizer, mainExecutor);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java
index dbdc460b7d83..6997d60c75f1 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java
@@ -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,14 +14,12 @@
* limitations under the License.
*/
-package com.android.systemui.wmshell;
+package com.android.wm.shell.dagger;
import android.animation.AnimationHandler;
import android.content.Context;
import android.view.IWindowManager;
-import com.android.systemui.dagger.WMComponent;
-import com.android.systemui.dagger.WMSingleton;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index fd9783a392a5..ac2e448eab58 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -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,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.wmshell;
+package com.android.wm.shell.dagger;
import android.app.ActivityTaskManager;
import android.content.Context;
@@ -27,8 +27,6 @@ import android.view.WindowManager;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.launcher3.icons.IconProvider;
-import com.android.systemui.dagger.WMComponent;
-import com.android.systemui.dagger.WMSingleton;
import com.android.wm.shell.RootDisplayAreaOrganizer;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellCommandHandler;
@@ -74,6 +72,8 @@ import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.pip.phone.PipAppOpsListener;
import com.android.wm.shell.pip.phone.PipTouchHandler;
+import com.android.wm.shell.recents.RecentTasks;
+import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.sizecompatui.SizeCompatUIController;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -144,16 +144,20 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
static ShellTaskOrganizer provideShellTaskOrganizer(@ShellMainThread ShellExecutor mainExecutor,
- Context context, SizeCompatUIController sizeCompatUI) {
- return new ShellTaskOrganizer(mainExecutor, context, sizeCompatUI);
+ Context context,
+ SizeCompatUIController sizeCompatUI,
+ Optional<RecentTasksController> recentTasksOptional
+ ) {
+ return new ShellTaskOrganizer(mainExecutor, context, sizeCompatUI, recentTasksOptional);
}
@WMSingleton
@Provides
static SizeCompatUIController provideSizeCompatUIController(Context context,
- DisplayController displayController, DisplayImeController imeController,
- SyncTransactionQueue syncQueue) {
- return new SizeCompatUIController(context, displayController, imeController, syncQueue);
+ DisplayController displayController, DisplayInsetsController displayInsetsController,
+ DisplayImeController imeController, SyncTransactionQueue syncQueue) {
+ return new SizeCompatUIController(context, displayController, displayInsetsController,
+ imeController, syncQueue);
}
@WMSingleton
@@ -236,8 +240,12 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
static FullscreenTaskListener provideFullscreenTaskListener(
- SyncTransactionQueue syncQueue, Optional<FullscreenUnfoldController> controller) {
- return new FullscreenTaskListener(syncQueue, controller);
+ SyncTransactionQueue syncQueue,
+ Optional<FullscreenUnfoldController> optionalFullscreenUnfoldController,
+ Optional<RecentTasksController> recentTasksOptional
+ ) {
+ return new FullscreenTaskListener(syncQueue, optionalFullscreenUnfoldController,
+ recentTasksOptional);
}
//
@@ -410,6 +418,28 @@ public abstract class WMShellBaseModule {
abstract PipTouchHandler optionalPipTouchHandler();
//
+ // Recent tasks
+ //
+
+ @WMSingleton
+ @Provides
+ static Optional<RecentTasks> provideRecentTasks(
+ Optional<RecentTasksController> recentTasksController) {
+ return recentTasksController.map((controller) -> controller.asRecentTasks());
+ }
+
+ @WMSingleton
+ @Provides
+ static Optional<RecentTasksController> provideRecentTasksController(
+ Context context,
+ TaskStackListenerImpl taskStackListener,
+ @ShellMainThread ShellExecutor mainExecutor
+ ) {
+ return Optional.ofNullable(
+ RecentTasksController.create(context, taskStackListener, mainExecutor));
+ }
+
+ //
// Shell transitions
//
@@ -463,13 +493,14 @@ public abstract class WMShellBaseModule {
@ShellMainThread ShellExecutor mainExecutor,
DisplayImeController displayImeController,
DisplayInsetsController displayInsetsController, Transitions transitions,
- TransactionPool transactionPool,
+ TransactionPool transactionPool, IconProvider iconProvider,
+ Optional<RecentTasksController> recentTasks,
Provider<Optional<StageTaskUnfoldController>> stageTaskUnfoldControllerProvider) {
if (ActivityTaskManager.supportsSplitScreenMultiWindow(context)) {
return Optional.of(new SplitScreenController(shellTaskOrganizer, syncQueue, context,
rootTaskDisplayAreaOrganizer, mainExecutor, displayImeController,
- displayInsetsController, transitions,
- transactionPool, stageTaskUnfoldControllerProvider));
+ displayInsetsController, transitions, transactionPool, iconProvider,
+ recentTasks, stageTaskUnfoldControllerProvider));
} else {
return Optional.empty();
}
@@ -555,13 +586,13 @@ public abstract class WMShellBaseModule {
DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer,
Optional<BubbleController> bubblesOptional,
- Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<AppPairsController> appPairsOptional,
Optional<PipTouchHandler> pipTouchHandlerOptional,
FullscreenTaskListener fullscreenTaskListener,
Optional<FullscreenUnfoldController> appUnfoldTransitionController,
Optional<Optional<FreeformTaskListener>> freeformTaskListener,
+ Optional<RecentTasksController> recentTasksOptional,
Transitions transitions,
StartingWindowController startingWindow,
@ShellMainThread ShellExecutor mainExecutor) {
@@ -571,13 +602,13 @@ public abstract class WMShellBaseModule {
dragAndDropController,
shellTaskOrganizer,
bubblesOptional,
- legacySplitScreenOptional,
splitScreenOptional,
appPairsOptional,
pipTouchHandlerOptional,
fullscreenTaskListener,
appUnfoldTransitionController,
freeformTaskListener,
+ recentTasksOptional,
transitions,
startingWindow,
mainExecutor);
@@ -603,9 +634,10 @@ public abstract class WMShellBaseModule {
Optional<OneHandedController> oneHandedOptional,
Optional<HideDisplayCutoutController> hideDisplayCutout,
Optional<AppPairsController> appPairsOptional,
+ Optional<RecentTasksController> recentTasksOptional,
@ShellMainThread ShellExecutor mainExecutor) {
return new ShellCommandHandlerImpl(shellTaskOrganizer,
legacySplitScreenOptional, splitScreenOptional, pipOptional, oneHandedOptional,
- hideDisplayCutout, appPairsOptional, mainExecutor);
+ hideDisplayCutout, appPairsOptional, recentTasksOptional, mainExecutor);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellConcurrencyModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java
index 61f50b5aae30..5c205f97beb7 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellConcurrencyModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java
@@ -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,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.wmshell;
+package com.android.wm.shell.dagger;
import static android.os.Process.THREAD_PRIORITY_DISPLAY;
import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST;
@@ -24,18 +24,18 @@ import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.Looper;
import android.os.Trace;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
-import com.android.systemui.R;
-import com.android.systemui.dagger.WMSingleton;
-import com.android.systemui.dagger.qualifiers.Main;
import com.android.wm.shell.common.HandlerExecutor;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.annotations.ChoreographerSfVsync;
+import com.android.wm.shell.common.annotations.ExternalMainThread;
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.R;
import dagger.Module;
import dagger.Provides;
@@ -61,13 +61,26 @@ public abstract class WMShellConcurrencyModule {
// Shell Concurrency - Components used for managing threading in the Shell and SysUI
//
+
+ /**
+ * Provide a SysUI main-thread Handler.
+ *
+ * Prefer the Main Executor when possible.
+ */
+ @Provides
+ @ExternalMainThread
+ public static Handler provideMainHandler() {
+ return new Handler(Looper.getMainLooper());
+ }
+
/**
* Provide a SysUI main-thread Executor.
*/
@WMSingleton
@Provides
- @Main
- public static ShellExecutor provideSysUIMainExecutor(@Main Handler sysuiMainHandler) {
+ @ExternalMainThread
+ public static ShellExecutor provideSysUIMainExecutor(
+ @ExternalMainThread Handler sysuiMainHandler) {
return new HandlerExecutor(sysuiMainHandler);
}
@@ -78,7 +91,8 @@ public abstract class WMShellConcurrencyModule {
@WMSingleton
@Provides
@ShellMainThread
- public static Handler provideShellMainHandler(Context context, @Main Handler sysuiMainHandler) {
+ public static Handler provideShellMainHandler(Context context,
+ @ExternalMainThread Handler sysuiMainHandler) {
if (enableShellMainThread(context)) {
HandlerThread mainThread = new HandlerThread("wmshell.main", THREAD_PRIORITY_DISPLAY);
mainThread.start();
@@ -99,7 +113,8 @@ public abstract class WMShellConcurrencyModule {
@Provides
@ShellMainThread
public static ShellExecutor provideShellMainExecutor(Context context,
- @ShellMainThread Handler mainHandler, @Main ShellExecutor sysuiMainExecutor) {
+ @ShellMainThread Handler mainHandler,
+ @ExternalMainThread ShellExecutor sysuiMainExecutor) {
if (enableShellMainThread(context)) {
return new HandlerExecutor(mainHandler);
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index a7c5ad2e3716..ec701470354c 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -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,15 +14,13 @@
* limitations under the License.
*/
-package com.android.systemui.wmshell;
+package com.android.wm.shell.dagger;
import android.animation.AnimationHandler;
import android.content.Context;
import android.os.Handler;
import android.view.IWindowManager;
-import com.android.systemui.dagger.WMComponent;
-import com.android.systemui.dagger.WMSingleton;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.apppairs.AppPairsController;
@@ -57,6 +55,7 @@ import com.android.wm.shell.pip.phone.PipAppOpsListener;
import com.android.wm.shell.pip.phone.PipController;
import com.android.wm.shell.pip.phone.PipMotionHelper;
import com.android.wm.shell.pip.phone.PipTouchHandler;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm;
import com.android.wm.shell.startingsurface.phone.PhoneStartingWindowTypeAlgorithm;
import com.android.wm.shell.transition.Transitions;
@@ -217,14 +216,15 @@ public class WMShellModule {
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
PipTransitionController pipTransitionController,
Optional<LegacySplitScreenController> splitScreenOptional,
+ Optional<SplitScreenController> newSplitScreenOptional,
DisplayController displayController,
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
@ShellMainThread ShellExecutor mainExecutor) {
return new PipTaskOrganizer(context,
syncTransactionQueue, pipTransitionState, pipBoundsState, pipBoundsAlgorithm,
menuPhoneController, pipAnimationController, pipSurfaceTransactionHelper,
- pipTransitionController, splitScreenOptional, displayController, pipUiEventLogger,
- shellTaskOrganizer, mainExecutor);
+ pipTransitionController, splitScreenOptional, newSplitScreenOptional,
+ displayController, pipUiEventLogger, shellTaskOrganizer, mainExecutor);
}
@WMSingleton
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMSingleton.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMSingleton.java
index 7292b9e459e0..7f45c38d19a3 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMSingleton.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMSingleton.java
@@ -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,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.dagger;
+package com.android.wm.shell.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropEventLogger.java
index 6e4b81563441..2a7dd5aeb341 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropEventLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropEventLogger.java
@@ -25,6 +25,8 @@ import android.content.ClipDescription;
import android.content.pm.ActivityInfo;
import android.view.DragEvent;
+import androidx.annotation.Nullable;
+
import com.android.internal.logging.InstanceId;
import com.android.internal.logging.InstanceIdSequence;
import com.android.internal.logging.UiEvent;
@@ -61,9 +63,7 @@ public class DragAndDropEventLogger {
mInstanceId = mIdSequence.newInstanceId();
}
mActivityInfo = item.getActivityInfo();
- mUiEventLogger.logWithInstanceId(getStartEnum(description),
- mActivityInfo.applicationInfo.uid,
- mActivityInfo.applicationInfo.packageName, mInstanceId);
+ log(getStartEnum(description), mActivityInfo);
return mInstanceId;
}
@@ -71,18 +71,21 @@ public class DragAndDropEventLogger {
* Logs a successful drop.
*/
public void logDrop() {
- mUiEventLogger.logWithInstanceId(DragAndDropUiEventEnum.GLOBAL_APP_DRAG_DROPPED,
- mActivityInfo.applicationInfo.uid,
- mActivityInfo.applicationInfo.packageName, mInstanceId);
+ log(DragAndDropUiEventEnum.GLOBAL_APP_DRAG_DROPPED, mActivityInfo);
}
/**
* Logs the end of a drag.
*/
public void logEnd() {
- mUiEventLogger.logWithInstanceId(DragAndDropUiEventEnum.GLOBAL_APP_DRAG_END,
- mActivityInfo.applicationInfo.uid,
- mActivityInfo.applicationInfo.packageName, mInstanceId);
+ log(DragAndDropUiEventEnum.GLOBAL_APP_DRAG_END, mActivityInfo);
+ }
+
+ private void log(UiEventLogger.UiEventEnum event, @Nullable ActivityInfo activityInfo) {
+ mUiEventLogger.logWithInstanceId(event,
+ activityInfo == null ? 0 : activityInfo.applicationInfo.uid,
+ activityInfo == null ? null : activityInfo.applicationInfo.packageName,
+ mInstanceId);
}
/**
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
index 5fb3297aa6d3..8a8d7c68d9f6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.freeform;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
@@ -27,6 +28,7 @@ import android.provider.Settings;
import android.util.Slog;
import android.util.SparseArray;
import android.view.SurfaceControl;
+import android.window.WindowContainerTransaction;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
@@ -83,6 +85,13 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener {
Slog.e(TAG, "Task already vanished: #" + taskInfo.taskId);
return;
}
+
+ // Clears windowing mode and window bounds to let the task inherits from its new parent.
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.setBounds(taskInfo.token, null)
+ .setWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED);
+ mSyncQueue.queue(wct);
+
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Vanished: #%d",
taskInfo.taskId);
mTasks.remove(taskInfo.taskId);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
index 3f17f2ba9394..6e38e421d4b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
@@ -35,6 +35,7 @@ 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 com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.transition.Transitions;
import java.io.PrintWriter;
@@ -47,15 +48,23 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
private static final String TAG = "FullscreenTaskListener";
private final SyncTransactionQueue mSyncQueue;
+ private final FullscreenUnfoldController mFullscreenUnfoldController;
+ private final Optional<RecentTasksController> mRecentTasksOptional;
private final SparseArray<TaskData> mDataByTaskId = new SparseArray<>();
private final AnimatableTasksListener mAnimatableTasksListener = new AnimatableTasksListener();
- private final FullscreenUnfoldController mFullscreenUnfoldController;
public FullscreenTaskListener(SyncTransactionQueue syncQueue,
Optional<FullscreenUnfoldController> unfoldController) {
+ this(syncQueue, unfoldController, Optional.empty());
+ }
+
+ public FullscreenTaskListener(SyncTransactionQueue syncQueue,
+ Optional<FullscreenUnfoldController> unfoldController,
+ Optional<RecentTasksController> recentTasks) {
mSyncQueue = syncQueue;
mFullscreenUnfoldController = unfoldController.orElse(null);
+ mRecentTasksOptional = recentTasks;
}
@Override
@@ -79,6 +88,7 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
});
mAnimatableTasksListener.onTaskAppeared(taskInfo);
+ updateRecentsForVisibleFullscreenTask(taskInfo);
}
@Override
@@ -86,6 +96,7 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
mAnimatableTasksListener.onTaskInfoChanged(taskInfo);
+ updateRecentsForVisibleFullscreenTask(taskInfo);
final TaskData data = mDataByTaskId.get(taskInfo.taskId);
final Point positionInParent = taskInfo.positionInParent;
@@ -111,6 +122,15 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
taskInfo.taskId);
}
+ private void updateRecentsForVisibleFullscreenTask(RunningTaskInfo taskInfo) {
+ mRecentTasksOptional.ifPresent(recentTasks -> {
+ if (taskInfo.isVisible) {
+ // Remove any persisted splits if either tasks are now made fullscreen and visible
+ recentTasks.removeSplitPair(taskInfo.taskId);
+ }
+ });
+ }
+
@Override
public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
if (!mDataByTaskId.contains(taskId)) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenUnfoldController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenUnfoldController.java
index fc1b704e95ad..aa3868cfca84 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenUnfoldController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenUnfoldController.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.fullscreen;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.util.MathUtils.lerp;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -163,7 +164,10 @@ public final class FullscreenUnfoldController implements UnfoldListener,
public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
AnimationContext animationContext = mAnimationContextByTaskId.get(taskInfo.taskId);
if (animationContext != null) {
- resetSurface(animationContext);
+ // PiP task has its own cleanup path, ignore surface reset to avoid conflict.
+ if (taskInfo.getWindowingMode() != WINDOWING_MODE_PINNED) {
+ resetSurface(animationContext);
+ }
mAnimationContextByTaskId.remove(taskInfo.taskId);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index 38079aff9a6f..900743712227 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -689,6 +689,8 @@ public class OneHandedController implements RemoteCallable<OneHandedController>,
pw.println(mUserId);
pw.print(innerPrefix + "isShortcutEnabled=");
pw.println(isShortcutEnabled());
+ pw.print(innerPrefix + "mIsSwipeToNotificationEnabled=");
+ pw.println(mIsSwipeToNotificationEnabled);
if (mBackgroundPanelOrganizer != null) {
mBackgroundPanelOrganizer.dump(pw);
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 ff333c8c659d..2cb7d1b0fa0d 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
@@ -244,6 +244,8 @@ public final class OneHandedSettingsUtil {
pw.println(TAG);
pw.print(innerPrefix + "isOneHandedModeEnable=");
pw.println(getSettingsOneHandedModeEnabled(resolver, userId));
+ pw.print(innerPrefix + "isSwipeToNotificationEnabled=");
+ pw.println(getSettingsSwipeToNotificationEnabled(resolver, userId));
pw.print(innerPrefix + "oneHandedTimeOut=");
pw.println(getSettingsOneHandedModeTimeout(resolver, userId));
pw.print(innerPrefix + "tapsAppToExit=");
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 291cbb3676dc..6cc5f09827af 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
@@ -77,6 +77,7 @@ import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.pip.phone.PipMotionHelper;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.transition.Transitions;
import java.io.PrintWriter;
@@ -126,7 +127,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private final int mExitAnimationDuration;
private final int mCrossFadeAnimationDuration;
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
- private final Optional<LegacySplitScreenController> mSplitScreenOptional;
+ private final Optional<LegacySplitScreenController> mLegacySplitScreenOptional;
+ private final Optional<SplitScreenController> mSplitScreenOptional;
protected final ShellTaskOrganizer mTaskOrganizer;
protected final ShellExecutor mMainExecutor;
@@ -252,7 +254,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
@NonNull PipAnimationController pipAnimationController,
@NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
@NonNull PipTransitionController pipTransitionController,
- Optional<LegacySplitScreenController> splitScreenOptional,
+ Optional<LegacySplitScreenController> legacySplitScreenOptional,
+ Optional<SplitScreenController> splitScreenOptional,
@NonNull DisplayController displayController,
@NonNull PipUiEventLogger pipUiEventLogger,
@NonNull ShellTaskOrganizer shellTaskOrganizer,
@@ -274,6 +277,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mPipAnimationController = pipAnimationController;
mPipUiEventLoggerLogger = pipUiEventLogger;
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
+ mLegacySplitScreenOptional = legacySplitScreenOptional;
mSplitScreenOptional = splitScreenOptional;
mTaskOrganizer = shellTaskOrganizer;
mMainExecutor = mainExecutor;
@@ -373,8 +377,11 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
* activity render it's final configuration while the Task is still in PiP.
* - setWindowingMode to undefined at the end of transition
* @param animationDurationMs duration in millisecond for the exiting PiP transition
+ * @param requestEnterSplit whether the enterSplit button is pressed on PiP or not.
+ * Indicate the user wishes to directly put PiP into split screen
+ * mode.
*/
- public void exitPip(int animationDurationMs) {
+ public void exitPip(int animationDurationMs, boolean requestEnterSplit) {
if (!mPipTransitionState.isInPip()
|| mPipTransitionState.getTransitionState() == PipTransitionState.EXITING_PIP
|| mToken == null) {
@@ -387,7 +394,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN);
final WindowContainerTransaction wct = new WindowContainerTransaction();
final Rect destinationBounds = mPipBoundsState.getDisplayBounds();
- final int direction = syncWithSplitScreenBounds(destinationBounds)
+ final int direction = syncWithSplitScreenBounds(destinationBounds, requestEnterSplit)
? TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
: TRANSITION_DIRECTION_LEAVE_PIP;
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
@@ -396,7 +403,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
// We set to fullscreen here for now, but later it will be set to UNDEFINED for
// the proper windowing mode to take place. See #applyWindowingModeChangeOnExit.
wct.setActivityWindowingMode(mToken,
- direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
+ direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN && !requestEnterSplit
? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
: WINDOWING_MODE_FULLSCREEN);
wct.setBounds(mToken, destinationBounds);
@@ -435,7 +442,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
wct.setWindowingMode(mToken, getOutPipWindowingMode());
// Simply reset the activity mode set prior to the animation running.
wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
- mSplitScreenOptional.ifPresent(splitScreen -> {
+ mLegacySplitScreenOptional.ifPresent(splitScreen -> {
if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
wct.reparent(mToken, splitScreen.getSecondaryRoot(), true /* onTop */);
}
@@ -1165,6 +1172,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
@PipAnimationController.TransitionDirection int direction,
@PipAnimationController.AnimationType int type) {
final Rect preResizeBounds = new Rect(mPipBoundsState.getBounds());
+ final boolean isPipTopLeft = isPipTopLeft();
mPipBoundsState.setBounds(destinationBounds);
if (direction == TRANSITION_DIRECTION_REMOVE_STACK) {
removePipImmediately();
@@ -1210,10 +1218,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
null /* callback */, false /* withStartDelay */);
});
} else {
- applyFinishBoundsResize(wct, direction);
+ applyFinishBoundsResize(wct, direction, isPipTopLeft);
}
} else {
- applyFinishBoundsResize(wct, direction);
+ applyFinishBoundsResize(wct, direction, isPipTopLeft);
}
finishResizeForMenu(destinationBounds);
@@ -1241,7 +1249,11 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
} else if (isOutPipDirection(direction)) {
// If we are animating to fullscreen or split screen, then we need to reset the
// override bounds on the task to ensure that the task "matches" the parent's bounds.
- taskBounds = null;
+ if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
+ taskBounds = destinationBounds;
+ } else {
+ taskBounds = null;
+ }
applyWindowingModeChangeOnExit(wct, direction);
} else {
// Just a resize in PIP
@@ -1261,8 +1273,20 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
* applying it.
*/
public void applyFinishBoundsResize(@NonNull WindowContainerTransaction wct,
- @PipAnimationController.TransitionDirection int direction) {
- mTaskOrganizer.applyTransaction(wct);
+ @PipAnimationController.TransitionDirection int direction, boolean wasPipTopLeft) {
+ if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
+ mSplitScreenOptional.get().enterSplitScreen(mTaskInfo.taskId, wasPipTopLeft, wct);
+ } else {
+ mTaskOrganizer.applyTransaction(wct);
+ }
+ }
+
+ private boolean isPipTopLeft() {
+ final Rect topLeft = new Rect();
+ final Rect bottomRight = new Rect();
+ mSplitScreenOptional.get().getStageBounds(topLeft, bottomRight);
+
+ return topLeft.contains(mPipBoundsState.getBounds());
}
/**
@@ -1292,13 +1316,17 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
Rect baseBounds = direction == TRANSITION_DIRECTION_SNAP_AFTER_RESIZE
? mPipBoundsState.getBounds() : currentBounds;
+ final boolean existingAnimatorRunning = mPipAnimationController.getCurrentAnimator() != null
+ && mPipAnimationController.getCurrentAnimator().isRunning();
final PipAnimationController.PipTransitionAnimator<?> animator = mPipAnimationController
.getAnimator(mTaskInfo, mLeash, baseBounds, currentBounds, destinationBounds,
sourceHintRect, direction, startingAngle, rotationDelta);
animator.setTransitionDirection(direction)
- .setPipAnimationCallback(mPipAnimationCallback)
.setPipTransactionHandler(mPipTransactionHandler)
.setDuration(durationMs);
+ if (!existingAnimatorRunning) {
+ animator.setPipAnimationCallback(mPipAnimationCallback);
+ }
if (isInPipDirection(direction)) {
// Similar to auto-enter-pip transition, we use content overlay when there is no
// source rect hint to enter PiP use bounds animation.
@@ -1343,18 +1371,27 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
/**
- * Sync with {@link LegacySplitScreenController} on destination bounds if PiP is going to split
- * screen.
+ * Sync with {@link LegacySplitScreenController} or {@link SplitScreenController} on destination
+ * bounds if PiP is going to split screen.
*
* @param destinationBoundsOut contain the updated destination bounds if applicable
* @return {@code true} if destinationBounds is altered for split screen
*/
- private boolean syncWithSplitScreenBounds(Rect destinationBoundsOut) {
- if (!mSplitScreenOptional.isPresent()) {
+ private boolean syncWithSplitScreenBounds(Rect destinationBoundsOut, boolean enterSplit) {
+ if (enterSplit && mSplitScreenOptional.isPresent()) {
+ final Rect topLeft = new Rect();
+ final Rect bottomRight = new Rect();
+ mSplitScreenOptional.get().getStageBounds(topLeft, bottomRight);
+ final boolean isPipTopLeft = isPipTopLeft();
+ destinationBoundsOut.set(isPipTopLeft ? topLeft : bottomRight);
+ return true;
+ }
+
+ if (!mLegacySplitScreenOptional.isPresent()) {
return false;
}
- LegacySplitScreenController legacySplitScreen = mSplitScreenOptional.get();
+ LegacySplitScreenController legacySplitScreen = mLegacySplitScreenOptional.get();
if (!legacySplitScreen.isDividerVisible()) {
// fail early if system is not in split screen mode
return false;
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 328f3ed73f2e..b31e6e0750ce 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
@@ -116,6 +116,12 @@ public class PipTransition extends PipTransitionController {
if (mExitTransition == transition || info.getType() == TRANSIT_EXIT_PIP) {
mExitTransition = null;
if (info.getChanges().size() == 1) {
+ if (mFinishCallback != null) {
+ mFinishCallback.onTransitionFinished(null, null);
+ mFinishCallback = null;
+ throw new RuntimeException("Previous callback not called, aborting exit PIP.");
+ }
+
final TransitionInfo.Change change = info.getChanges().get(0);
mFinishCallback = finishCallback;
startTransaction.apply();
@@ -129,6 +135,12 @@ public class PipTransition extends PipTransitionController {
}
if (info.getType() == TRANSIT_REMOVE_PIP) {
+ if (mFinishCallback != null) {
+ mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
+ mFinishCallback = null;
+ throw new RuntimeException("Previous callback not called, aborting remove PIP.");
+ }
+
startTransaction.apply();
finishTransaction.setWindowCrop(info.getChanges().get(0).getLeash(),
mPipBoundsState.getDisplayBounds());
@@ -159,6 +171,12 @@ public class PipTransition extends PipTransitionController {
return false;
}
+ if (mFinishCallback != null) {
+ mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
+ mFinishCallback = null;
+ throw new RuntimeException("Previous callback not called, aborting entering PIP.");
+ }
+
// Show the wallpaper if there is a wallpaper change.
if (wallpaper != null) {
startTransaction.show(wallpaper.getLeash());
@@ -231,7 +249,7 @@ public class PipTransition extends PipTransitionController {
if (tx != null) {
wct.setBoundsChangeTransaction(taskInfo.token, tx);
}
- mFinishCallback.onTransitionFinished(wct, null /* wctCallback */);
+ mFinishCallback.onTransitionFinished(wct, null /* callback */);
mFinishCallback = null;
}
finishResizeForMenu(destinationBounds);
@@ -240,7 +258,7 @@ public class PipTransition extends PipTransitionController {
@Override
public void forceFinishTransition() {
if (mFinishCallback == null) return;
- mFinishCallback.onTransitionFinished(null /* wct */, null /* wctCallback */);
+ mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
mFinishCallback = null;
}
@@ -286,7 +304,6 @@ public class PipTransition extends PipTransitionController {
mPipBoundsState.setBounds(destinationBounds);
onFinishResize(taskInfo, destinationBounds, TRANSITION_DIRECTION_TO_PIP, null /* tx */);
sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
- mFinishCallback = null;
mPipTransitionState.setInSwipePipToHomeTransition(false);
return true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index ae8c1b6f8c1a..5687f4d62444 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -95,6 +95,11 @@ public class PhonePipMenuController implements PipMenuController {
* Called when the PIP requested to show the menu.
*/
void onPipShowMenu();
+
+ /**
+ * Called when the PIP requested to enter Split.
+ */
+ void onEnterSplit();
}
private final Matrix mMoveTransform = new Matrix();
@@ -458,6 +463,10 @@ public class PhonePipMenuController implements PipMenuController {
mListeners.forEach(Listener::onPipDismiss);
}
+ void onEnterSplit() {
+ mListeners.forEach(Listener::onEnterSplit);
+ }
+
/**
* @return the best set of actions to show in the PiP menu.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
index 47a8c67a22e6..69ae45d12795 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
@@ -151,7 +151,7 @@ public class PipAccessibilityInteractionConnection {
result = true;
break;
case AccessibilityNodeInfo.ACTION_EXPAND:
- mMotionHelper.expandLeavePip();
+ mMotionHelper.expandLeavePip(false /* skipAnimation */);
result = true;
break;
default:
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 8e5c5c52cb3f..6ce43a041299 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
@@ -43,7 +43,6 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ParceledListSlice;
import android.content.res.Configuration;
import android.graphics.Rect;
-import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -69,6 +68,7 @@ import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SingleInstanceRemoteListener;
import com.android.wm.shell.common.TaskStackListenerCallback;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.onehanded.OneHandedController;
@@ -117,13 +117,28 @@ public class PipController implements PipTransitionController.PipTransitionCallb
private final Rect mTmpInsetBounds = new Rect();
private boolean mIsInFixedRotation;
- private IPipAnimationListener mPinnedStackAnimationRecentsCallback;
+ private PipAnimationListener mPinnedStackAnimationRecentsCallback;
protected PhonePipMenuController mMenuController;
protected PipTaskOrganizer mPipTaskOrganizer;
protected PinnedStackListenerForwarder.PinnedTaskListener mPinnedTaskListener =
new PipControllerPinnedTaskListener();
+ private interface PipAnimationListener {
+ /**
+ * Notifies the listener that the Pip animation is started.
+ */
+ void onPipAnimationStarted();
+
+ /**
+ * Notifies the listener about PiP round corner radius changes.
+ * Listener can expect an immediate callback the first time they attach.
+ *
+ * @param cornerRadius the pixel value of the corner radius, zero means it's disabled.
+ */
+ void onPipCornerRadiusChanged(int cornerRadius);
+ }
+
/**
* Handler for display rotation changes.
*/
@@ -448,6 +463,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
}
private void onOverlayChanged() {
+ mTouchHandler.onOverlayChanged();
onDisplayChanged(new DisplayLayout(mContext, mContext.getDisplay()),
false /* saveRestoreSnapFraction */);
}
@@ -467,19 +483,33 @@ public class PipController implements PipTransitionController.PipTransitionCallb
false /* fromShelfAdjustment */,
wct /* windowContainerTransaction */);
if (wct != null) {
- mPipTaskOrganizer.applyFinishBoundsResize(wct, TRANSITION_DIRECTION_SAME);
+ mPipTaskOrganizer.applyFinishBoundsResize(wct, TRANSITION_DIRECTION_SAME,
+ false /* wasPipTopLeft */);
}
};
if (mPipTaskOrganizer.isInPip() && saveRestoreSnapFraction) {
// Calculate the snap fraction of the current stack along the old movement bounds
final PipSnapAlgorithm pipSnapAlgorithm = mPipBoundsAlgorithm.getSnapAlgorithm();
- final Rect postChangeStackBounds = new Rect(mPipBoundsState.getBounds());
- final float snapFraction = pipSnapAlgorithm.getSnapFraction(postChangeStackBounds,
- mPipBoundsAlgorithm.getMovementBounds(postChangeStackBounds),
+ final float snapFraction = pipSnapAlgorithm.getSnapFraction(mPipBoundsState.getBounds(),
+ mPipBoundsAlgorithm.getMovementBounds(mPipBoundsState.getBounds()),
mPipBoundsState.getStashedState());
updateDisplayLayout.run();
+ final Rect postChangeStackBounds;
+ if (mPipBoundsState.getBounds() != null
+ && (mPipBoundsState.getBounds().width() > mPipBoundsState.getMaxSize().x
+ || mPipBoundsState.getBounds().height() > mPipBoundsState.getMaxSize().y)) {
+ postChangeStackBounds = new Rect(0, 0, mPipBoundsState.getMaxSize().x,
+ mPipBoundsState.getMaxSize().y);
+ } else if (mPipBoundsState.getBounds() != null
+ && (mPipBoundsState.getBounds().width() < mPipBoundsState.getMinSize().x
+ || mPipBoundsState.getBounds().height() < mPipBoundsState.getMinSize().y)) {
+ postChangeStackBounds = new Rect(0, 0, mPipBoundsState.getMinSize().x,
+ mPipBoundsState.getMinSize().y);
+ } else {
+ postChangeStackBounds = new Rect(mPipBoundsState.getBounds());
+ }
// Calculate the stack bounds in the new orientation based on same fraction along the
// rotated movement bounds.
@@ -491,7 +521,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
mPipBoundsState.getDisplayBounds(),
mPipBoundsState.getDisplayLayout().stableInsets());
- mTouchHandler.getMotionHelper().movePip(postChangeStackBounds);
+ mTouchHandler.getMotionHelper().animateResizedBounds(postChangeStackBounds);
} else {
updateDisplayLayout.run();
}
@@ -551,7 +581,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
animationType == PipAnimationController.ANIM_TYPE_BOUNDS);
}
- private void setPinnedStackAnimationListener(IPipAnimationListener callback) {
+ private void setPinnedStackAnimationListener(PipAnimationListener callback) {
mPinnedStackAnimationRecentsCallback = callback;
onPipCornerRadiusChanged();
}
@@ -560,11 +590,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
if (mPinnedStackAnimationRecentsCallback != null) {
final int cornerRadius =
mContext.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius);
- try {
- mPinnedStackAnimationRecentsCallback.onPipCornerRadiusChanged(cornerRadius);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to call onPipCornerRadiusChanged", e);
- }
+ mPinnedStackAnimationRecentsCallback.onPipCornerRadiusChanged(cornerRadius);
}
}
@@ -623,11 +649,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
// Disable touches while the animation is running
mTouchHandler.setTouchEnabled(false);
if (mPinnedStackAnimationRecentsCallback != null) {
- try {
- mPinnedStackAnimationRecentsCallback.onPipAnimationStarted();
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to call onPinnedStackAnimationStarted()", e);
- }
+ mPinnedStackAnimationRecentsCallback.onPipAnimationStarted();
}
}
@@ -866,22 +888,25 @@ public class PipController implements PipTransitionController.PipTransitionCallb
@BinderThread
private static class IPipImpl extends IPip.Stub {
private PipController mController;
- private IPipAnimationListener mListener;
- private final IBinder.DeathRecipient mListenerDeathRecipient =
- new IBinder.DeathRecipient() {
- @Override
- @BinderThread
- public void binderDied() {
- final PipController controller = mController;
- controller.getRemoteCallExecutor().execute(() -> {
- mListener = null;
- controller.setPinnedStackAnimationListener(null);
- });
- }
- };
+ private final SingleInstanceRemoteListener<PipController,
+ IPipAnimationListener> mListener;
+ private final PipAnimationListener mPipAnimationListener = new PipAnimationListener() {
+ @Override
+ public void onPipAnimationStarted() {
+ mListener.call(l -> l.onPipAnimationStarted());
+ }
+
+ @Override
+ public void onPipCornerRadiusChanged(int cornerRadius) {
+ mListener.call(l -> l.onPipCornerRadiusChanged(cornerRadius));
+ }
+ };
IPipImpl(PipController controller) {
mController = controller;
+ mListener = new SingleInstanceRemoteListener<>(mController,
+ c -> c.setPinnedStackAnimationListener(mPipAnimationListener),
+ c -> c.setPinnedStackAnimationListener(null));
}
/**
@@ -925,23 +950,11 @@ public class PipController implements PipTransitionController.PipTransitionCallb
public void setPinnedStackAnimationListener(IPipAnimationListener listener) {
executeRemoteCallWithTaskPermission(mController, "setPinnedStackAnimationListener",
(controller) -> {
- if (mListener != null) {
- // Reset the old death recipient
- mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
- 0 /* flags */);
- }
if (listener != null) {
- // Register the death recipient for the new listener to clear the listener
- try {
- listener.asBinder().linkToDeath(mListenerDeathRecipient,
- 0 /* flags */);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to link to death");
- return;
- }
+ mListener.register(listener);
+ } else {
+ mListener.unregister();
}
- mListener = listener;
- controller.setPinnedStackAnimationListener(listener);
});
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java
index 3eeba6eb5366..06446573840c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java
@@ -18,8 +18,6 @@ package com.android.wm.shell.pip.phone;
import android.content.Context;
import android.graphics.Rect;
-import android.util.Log;
-import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -34,6 +32,7 @@ public class PipMenuIconsAlgorithm {
protected ViewGroup mViewRoot;
protected ViewGroup mTopEndContainer;
protected View mDragHandle;
+ protected View mEnterSplitButton;
protected View mSettingsButton;
protected View mDismissButton;
@@ -44,14 +43,13 @@ public class PipMenuIconsAlgorithm {
* Bind the necessary views.
*/
public void bindViews(ViewGroup viewRoot, ViewGroup topEndContainer, View dragHandle,
- View settingsButton, View dismissButton) {
+ View enterSplitButton, View settingsButton, View dismissButton) {
mViewRoot = viewRoot;
mTopEndContainer = topEndContainer;
mDragHandle = dragHandle;
+ mEnterSplitButton = enterSplitButton;
mSettingsButton = settingsButton;
mDismissButton = dismissButton;
-
- bindInitialViewState();
}
/**
@@ -72,22 +70,4 @@ public class PipMenuIconsAlgorithm {
v.setLayoutParams(params);
}
}
-
- /** Calculate the initial state of the menu icons. Called when the menu is first created. */
- private void bindInitialViewState() {
- if (mViewRoot == null || mTopEndContainer == null || mDragHandle == null
- || mSettingsButton == null || mDismissButton == null) {
- Log.e(TAG, "One of the required views is null.");
- return;
- }
- // The menu view layout starts out with the settings button aligned at the top|end of the
- // view group next to the dismiss button. On phones, the settings button should be aligned
- // to the top|start of the view, so move it to parent view group to then align it to the
- // top|start of the menu.
- mTopEndContainer.removeView(mSettingsButton);
- mViewRoot.addView(mSettingsButton);
-
- setLayoutGravity(mDragHandle, Gravity.START | Gravity.TOP);
- setLayoutGravity(mSettingsButton, Gravity.START | Gravity.TOP);
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 8ef2b6b12030..b209699c1a19 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -99,7 +99,7 @@ public class PipMenuView extends FrameLayout {
private static final float MENU_BACKGROUND_ALPHA = 0.3f;
private static final float DISABLED_ACTION_ALPHA = 0.54f;
- private static final boolean ENABLE_RESIZE_HANDLE = false;
+ private static final boolean ENABLE_ENTER_SPLIT = true;
private int mMenuState;
private boolean mAllowMenuTimeout = true;
@@ -139,7 +139,7 @@ public class PipMenuView extends FrameLayout {
protected View mViewRoot;
protected View mSettingsButton;
protected View mDismissButton;
- protected View mResizeHandle;
+ protected View mEnterSplitButton;
protected View mTopEndContainer;
protected PipMenuIconsAlgorithm mPipMenuIconsAlgorithm;
@@ -177,14 +177,23 @@ public class PipMenuView extends FrameLayout {
}
});
- mResizeHandle = findViewById(R.id.resize_handle);
- mResizeHandle.setAlpha(0);
+ mEnterSplitButton = findViewById(R.id.enter_split);
+ mEnterSplitButton.setAlpha(0);
+ mEnterSplitButton.setOnClickListener(v -> {
+ if (mMenuContainer.getAlpha() != 0) {
+ enterSplit();
+ }
+ });
+
+ findViewById(R.id.resize_handle).setAlpha(0);
+
mActionsGroup = findViewById(R.id.actions_group);
mBetweenActionPaddingLand = getResources().getDimensionPixelSize(
R.dimen.pip_between_action_padding_land);
mPipMenuIconsAlgorithm = new PipMenuIconsAlgorithm(mContext);
mPipMenuIconsAlgorithm.bindViews((ViewGroup) mViewRoot, (ViewGroup) mTopEndContainer,
- mResizeHandle, mSettingsButton, mDismissButton);
+ findViewById(R.id.resize_handle), mEnterSplitButton, mSettingsButton,
+ mDismissButton);
mDismissFadeOutDurationMs = context.getResources()
.getInteger(R.integer.config_pipExitAnimationDuration);
@@ -268,14 +277,13 @@ public class PipMenuView extends FrameLayout {
mSettingsButton.getAlpha(), 1f);
ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA,
mDismissButton.getAlpha(), 1f);
- ObjectAnimator resizeAnim = ObjectAnimator.ofFloat(mResizeHandle, View.ALPHA,
- mResizeHandle.getAlpha(),
- ENABLE_RESIZE_HANDLE && showResizeHandle ? 1f : 0f);
+ ObjectAnimator enterSplitAnim = ObjectAnimator.ofFloat(mEnterSplitButton, View.ALPHA,
+ mEnterSplitButton.getAlpha(), ENABLE_ENTER_SPLIT ? 1f : 0f);
if (menuState == MENU_STATE_FULL) {
mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim,
- resizeAnim);
+ enterSplitAnim);
} else {
- mMenuContainerAnimator.playTogether(resizeAnim);
+ mMenuContainerAnimator.playTogether(enterSplitAnim);
}
mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
mMenuContainerAnimator.setDuration(ANIMATION_HIDE_DURATION_MS);
@@ -328,7 +336,7 @@ public class PipMenuView extends FrameLayout {
mMenuContainer.setAlpha(0f);
mSettingsButton.setAlpha(0f);
mDismissButton.setAlpha(0f);
- mResizeHandle.setAlpha(0f);
+ mEnterSplitButton.setAlpha(0f);
}
void pokeMenu() {
@@ -368,9 +376,10 @@ public class PipMenuView extends FrameLayout {
mSettingsButton.getAlpha(), 0f);
ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA,
mDismissButton.getAlpha(), 0f);
- ObjectAnimator resizeAnim = ObjectAnimator.ofFloat(mResizeHandle, View.ALPHA,
- mResizeHandle.getAlpha(), 0f);
- mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim, resizeAnim);
+ ObjectAnimator enterSplitAnim = ObjectAnimator.ofFloat(mEnterSplitButton, View.ALPHA,
+ mEnterSplitButton.getAlpha(), 0f);
+ mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim,
+ enterSplitAnim);
mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_OUT);
mMenuContainerAnimator.setDuration(getFadeOutDuration(animationType));
mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
@@ -522,6 +531,14 @@ public class PipMenuView extends FrameLayout {
}
}
+ private void enterSplit() {
+ // Do not notify menu visibility when hiding the menu, the controller will do this when it
+ // handles the message
+ hideMenu(mController::onEnterSplit, false /* notifyMenuVisibility */, true /* resize */,
+ ANIM_TYPE_HIDE);
+ }
+
+
private void showSettings() {
final Pair<ComponentName, Integer> topPipActivityInfo =
PipUtils.getTopPipActivity(mContext);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index c42750d62dd4..c634b7f220b0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -69,6 +69,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
private static final int UNSTASH_DURATION = 250;
private static final int LEAVE_PIP_DURATION = 300;
private static final int SHIFT_DURATION = 300;
+ private static final int ANIMATE_PIP_RESIZE_ANIMATION = 250;
/** Friction to use for PIP when it moves via physics fling animations. */
private static final float DEFAULT_FRICTION = 1.9f;
@@ -337,22 +338,29 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
* Resizes the pinned stack back to unknown windowing mode, which could be freeform or
* * fullscreen depending on the display area's windowing mode.
*/
- void expandLeavePip() {
- expandLeavePip(false /* skipAnimation */);
+ void expandLeavePip(boolean skipAnimation) {
+ expandLeavePip(skipAnimation, false /* enterSplit */);
+ }
+
+ /**
+ * Resizes the pinned task to split-screen mode.
+ */
+ void expandIntoSplit() {
+ expandLeavePip(false, true /* enterSplit */);
}
/**
* Resizes the pinned stack back to unknown windowing mode, which could be freeform or
* fullscreen depending on the display area's windowing mode.
*/
- void expandLeavePip(boolean skipAnimation) {
+ private void expandLeavePip(boolean skipAnimation, boolean enterSplit) {
if (DEBUG) {
Log.d(TAG, "exitPip: skipAnimation=" + skipAnimation
+ " callers=\n" + Debug.getCallers(5, " "));
}
cancelPhysicsAnimation();
mMenuController.hideMenu(ANIM_TYPE_NONE, false /* resize */);
- mPipTaskOrganizer.exitPip(skipAnimation ? 0 : LEAVE_PIP_DURATION);
+ mPipTaskOrganizer.exitPip(skipAnimation ? 0 : LEAVE_PIP_DURATION, enterSplit);
}
/**
@@ -541,6 +549,14 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
}
/**
+ * Animates the PiP from an old bound to a new bound. This is mostly used when display
+ * has changed and PiP bounds needs to be changed.
+ */
+ void animateResizedBounds(Rect newBounds) {
+ resizeAndAnimatePipUnchecked(newBounds, ANIMATE_PIP_RESIZE_ANIMATION);
+ }
+
+ /**
* Animates the PiP to offset it from the IME or shelf.
*/
void animateToOffset(Rect originalBounds, int offset) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 9f2f6a575aca..3ace5f405d36 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -139,7 +139,12 @@ public class PipTouchHandler {
@Override
public void onPipExpand() {
- mMotionHelper.expandLeavePip();
+ mMotionHelper.expandLeavePip(false /* skipAnimation */);
+ }
+
+ @Override
+ public void onEnterSplit() {
+ mMotionHelper.expandIntoSplit();
}
@Override
@@ -254,6 +259,11 @@ public class PipTouchHandler {
mPipDismissTargetHandler.updateMagneticTargetSize();
}
+ public void onOverlayChanged() {
+ // onOverlayChanged is triggered upon theme change, update the dismiss target accordingly.
+ mPipDismissTargetHandler.init();
+ }
+
private boolean shouldShowResizeHandle() {
return false;
}
@@ -899,7 +909,7 @@ public class PipTouchHandler {
// Expand to fullscreen if this is a double tap
// the PiP should be frozen until the transition ends
setTouchEnabled(false);
- mMotionHelper.expandLeavePip();
+ mMotionHelper.expandLeavePip(false /* skipAnimation */);
}
} else if (mMenuState != MENU_STATE_FULL) {
if (mPipBoundsState.isStashed()) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
index a2e9b64046fd..00083d986dbe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -219,7 +219,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
public void movePipToFullscreen() {
if (DEBUG) Log.d(TAG, "movePipToFullscreen(), state=" + stateToName(mState));
- mPipTaskOrganizer.exitPip(mResizeAnimationDuration);
+ mPipTaskOrganizer.exitPip(mResizeAnimationDuration, false /* requestEnterSplit */);
onPipDisappeared();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasks.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasks.aidl
new file mode 100644
index 000000000000..6e78fcba4a00
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasks.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.recents;
+
+import com.android.wm.shell.recents.IRecentTasksListener;
+import com.android.wm.shell.util.GroupedRecentTaskInfo;
+
+/**
+ * Interface that is exposed to remote callers to fetch recent tasks.
+ */
+interface IRecentTasks {
+
+ /**
+ * Registers a recent tasks listener.
+ */
+ oneway void registerRecentTasksListener(in IRecentTasksListener listener) = 1;
+
+ /**
+ * Unregisters a recent tasks listener.
+ */
+ oneway void unregisterRecentTasksListener(in IRecentTasksListener listener) = 2;
+
+ /**
+ * Gets the set of recent tasks.
+ */
+ GroupedRecentTaskInfo[] getRecentTasks(int maxNum, int flags, int userId) = 3;
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl
new file mode 100644
index 000000000000..8efa42830d80
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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 distshellributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.recents;
+
+/**
+ * Listener interface that Launcher attaches to SystemUI to get split-screen callbacks.
+ */
+oneway interface IRecentTasksListener {
+
+ /**
+ * Called when the set of recent tasks change.
+ */
+ void onRecentTasksChanged();
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasks.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasks.java
new file mode 100644
index 000000000000..a5748f69388f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasks.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.recents;
+
+import com.android.wm.shell.common.annotations.ExternalThread;
+
+/**
+ * Interface for interacting with the recent tasks.
+ */
+@ExternalThread
+public interface RecentTasks {
+ /**
+ * Returns a binder that can be passed to an external process to fetch recent tasks.
+ */
+ default IRecentTasks createExternalInterface() {
+ return null;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
new file mode 100644
index 000000000000..7cf3bafe499a
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -0,0 +1,315 @@
+/*
+ * 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.recents;
+
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+
+import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
+
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.TaskInfo;
+import android.content.Context;
+import android.os.RemoteException;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+
+import androidx.annotation.BinderThread;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.wm.shell.common.RemoteCallable;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SingleInstanceRemoteListener;
+import com.android.wm.shell.common.TaskStackListenerCallback;
+import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.common.annotations.ExternalThread;
+import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.util.GroupedRecentTaskInfo;
+import com.android.wm.shell.util.StagedSplitBounds;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Manages the recent task list from the system, caching it as necessary.
+ */
+public class RecentTasksController implements TaskStackListenerCallback,
+ RemoteCallable<RecentTasksController> {
+ private static final String TAG = RecentTasksController.class.getSimpleName();
+
+ private final Context mContext;
+ private final ShellExecutor mMainExecutor;
+ private final TaskStackListenerImpl mTaskStackListener;
+ private final RecentTasks mImpl = new RecentTasksImpl();
+
+ private final ArrayList<Runnable> mCallbacks = new ArrayList<>();
+ // Mapping of split task ids, mappings are symmetrical (ie. if t1 is the taskid of a task in a
+ // pair, then mSplitTasks[t1] = t2, and mSplitTasks[t2] = t1)
+ private final SparseIntArray mSplitTasks = new SparseIntArray();
+ /**
+ * Maps taskId to {@link StagedSplitBounds} for both taskIDs.
+ * Meaning there will be two taskId integers mapping to the same object.
+ * If there's any ordering to the pairing than we can probably just get away with only one
+ * taskID mapping to it, leaving both for consistency with {@link #mSplitTasks} for now.
+ */
+ private final Map<Integer, StagedSplitBounds> mTaskSplitBoundsMap = new HashMap<>();
+
+ /**
+ * Creates {@link RecentTasksController}, returns {@code null} if the feature is not
+ * supported.
+ */
+ @Nullable
+ public static RecentTasksController create(
+ Context context,
+ TaskStackListenerImpl taskStackListener,
+ @ShellMainThread ShellExecutor mainExecutor
+ ) {
+ if (!context.getResources().getBoolean(com.android.internal.R.bool.config_hasRecents)) {
+ return null;
+ }
+ return new RecentTasksController(context, taskStackListener, mainExecutor);
+ }
+
+ RecentTasksController(Context context, TaskStackListenerImpl taskStackListener,
+ ShellExecutor mainExecutor) {
+ mContext = context;
+ mTaskStackListener = taskStackListener;
+ mMainExecutor = mainExecutor;
+ }
+
+ public RecentTasks asRecentTasks() {
+ return mImpl;
+ }
+
+ public void init() {
+ mTaskStackListener.addListener(this);
+ }
+
+ /**
+ * Adds a split pair. This call does not validate the taskIds, only that they are not the same.
+ */
+ public void addSplitPair(int taskId1, int taskId2, StagedSplitBounds splitBounds) {
+ if (taskId1 == taskId2) {
+ return;
+ }
+ // Remove any previous pairs
+ removeSplitPair(taskId1);
+ removeSplitPair(taskId2);
+ mTaskSplitBoundsMap.remove(taskId1);
+ mTaskSplitBoundsMap.remove(taskId2);
+
+ mSplitTasks.put(taskId1, taskId2);
+ mSplitTasks.put(taskId2, taskId1);
+ mTaskSplitBoundsMap.put(taskId1, splitBounds);
+ mTaskSplitBoundsMap.put(taskId2, splitBounds);
+ }
+
+ /**
+ * Removes a split pair.
+ */
+ public void removeSplitPair(int taskId) {
+ int pairedTaskId = mSplitTasks.get(taskId, INVALID_TASK_ID);
+ if (pairedTaskId != INVALID_TASK_ID) {
+ mSplitTasks.delete(taskId);
+ mSplitTasks.delete(pairedTaskId);
+ mTaskSplitBoundsMap.remove(taskId);
+ mTaskSplitBoundsMap.remove(pairedTaskId);
+ }
+ }
+
+ @Override
+ public Context getContext() {
+ return mContext;
+ }
+
+ @Override
+ public ShellExecutor getRemoteCallExecutor() {
+ return mMainExecutor;
+ }
+
+ @Override
+ public void onTaskStackChanged() {
+ notifyRecentTasksChanged();
+ }
+
+ @Override
+ public void onRecentTaskListUpdated() {
+ // In some cases immediately after booting, the tasks in the system recent task list may be
+ // loaded, but not in the active task hierarchy in the system. These tasks are displayed in
+ // overview, but removing them don't result in a onTaskStackChanged() nor a onTaskRemoved()
+ // callback (those are for changes to the active tasks), but the task list is still updated,
+ // so we should also invalidate the change id to ensure we load a new list instead of
+ // reusing a stale list.
+ notifyRecentTasksChanged();
+ }
+
+ public void onTaskRemoved(TaskInfo taskInfo) {
+ // Remove any split pairs associated with this task
+ removeSplitPair(taskInfo.taskId);
+ notifyRecentTasksChanged();
+ }
+
+ public void onTaskWindowingModeChanged(TaskInfo taskInfo) {
+ notifyRecentTasksChanged();
+ }
+
+ @VisibleForTesting
+ void notifyRecentTasksChanged() {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ mCallbacks.get(i).run();
+ }
+ }
+
+ private void registerRecentTasksListener(Runnable listener) {
+ if (!mCallbacks.contains(listener)) {
+ mCallbacks.add(listener);
+ }
+ }
+
+ private void unregisterRecentTasksListener(Runnable listener) {
+ mCallbacks.remove(listener);
+ }
+
+ @VisibleForTesting
+ List<ActivityManager.RecentTaskInfo> getRawRecentTasks(int maxNum, int flags, int userId) {
+ return ActivityTaskManager.getInstance().getRecentTasks(maxNum, flags, userId);
+ }
+
+ @VisibleForTesting
+ ArrayList<GroupedRecentTaskInfo> getRecentTasks(int maxNum, int flags, int userId) {
+ // Note: the returned task list is from the most-recent to least-recent order
+ final List<ActivityManager.RecentTaskInfo> rawList = getRawRecentTasks(maxNum, flags,
+ userId);
+
+ // Make a mapping of task id -> task info
+ final SparseArray<ActivityManager.RecentTaskInfo> rawMapping = new SparseArray<>();
+ for (int i = 0; i < rawList.size(); i++) {
+ final ActivityManager.RecentTaskInfo taskInfo = rawList.get(i);
+ rawMapping.put(taskInfo.taskId, taskInfo);
+ }
+
+ // Pull out the pairs as we iterate back in the list
+ ArrayList<GroupedRecentTaskInfo> recentTasks = new ArrayList<>();
+ for (int i = 0; i < rawList.size(); i++) {
+ final ActivityManager.RecentTaskInfo taskInfo = rawList.get(i);
+ if (!rawMapping.contains(taskInfo.taskId)) {
+ // If it's not in the mapping, then it was already paired with another task
+ continue;
+ }
+
+ final int pairedTaskId = mSplitTasks.get(taskInfo.taskId);
+ if (pairedTaskId != INVALID_TASK_ID) {
+ final ActivityManager.RecentTaskInfo pairedTaskInfo = rawMapping.get(pairedTaskId);
+ rawMapping.remove(pairedTaskId);
+ recentTasks.add(new GroupedRecentTaskInfo(taskInfo, pairedTaskInfo,
+ mTaskSplitBoundsMap.get(pairedTaskId)));
+ } else {
+ recentTasks.add(new GroupedRecentTaskInfo(taskInfo));
+ }
+ }
+ return recentTasks;
+ }
+
+ public void dump(@NonNull PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ pw.println(prefix + TAG);
+ ArrayList<GroupedRecentTaskInfo> recentTasks = getRecentTasks(Integer.MAX_VALUE,
+ ActivityManager.RECENT_IGNORE_UNAVAILABLE, ActivityManager.getCurrentUser());
+ for (int i = 0; i < recentTasks.size(); i++) {
+ pw.println(innerPrefix + recentTasks.get(i));
+ }
+ }
+
+ /**
+ * The interface for calls from outside the Shell, within the host process.
+ */
+ @ExternalThread
+ private class RecentTasksImpl implements RecentTasks {
+ private IRecentTasksImpl mIRecentTasks;
+
+ @Override
+ public IRecentTasks createExternalInterface() {
+ if (mIRecentTasks != null) {
+ mIRecentTasks.invalidate();
+ }
+ mIRecentTasks = new IRecentTasksImpl(RecentTasksController.this);
+ return mIRecentTasks;
+ }
+ }
+
+
+ /**
+ * The interface for calls from outside the host process.
+ */
+ @BinderThread
+ private static class IRecentTasksImpl extends IRecentTasks.Stub {
+ private RecentTasksController mController;
+ private final SingleInstanceRemoteListener<RecentTasksController,
+ IRecentTasksListener> mListener;
+ private final Runnable mRecentTasksListener =
+ new Runnable() {
+ @Override
+ public void run() {
+ mListener.call(l -> l.onRecentTasksChanged());
+ }
+ };
+
+ public IRecentTasksImpl(RecentTasksController controller) {
+ mController = controller;
+ mListener = new SingleInstanceRemoteListener<>(controller,
+ c -> c.registerRecentTasksListener(mRecentTasksListener),
+ c -> c.unregisterRecentTasksListener(mRecentTasksListener));
+ }
+
+ /**
+ * Invalidates this instance, preventing future calls from updating the controller.
+ */
+ void invalidate() {
+ mController = null;
+ }
+
+ @Override
+ public void registerRecentTasksListener(IRecentTasksListener listener)
+ throws RemoteException {
+ executeRemoteCallWithTaskPermission(mController, "registerRecentTasksListener",
+ (controller) -> mListener.register(listener));
+ }
+
+ @Override
+ public void unregisterRecentTasksListener(IRecentTasksListener listener)
+ throws RemoteException {
+ executeRemoteCallWithTaskPermission(mController, "unregisterRecentTasksListener",
+ (controller) -> mListener.unregister());
+ }
+
+ @Override
+ public GroupedRecentTaskInfo[] getRecentTasks(int maxNum, int flags, int userId)
+ throws RemoteException {
+ final GroupedRecentTaskInfo[][] out = new GroupedRecentTaskInfo[][]{null};
+ executeRemoteCallWithTaskPermission(mController, "getRecentTasks",
+ (controller) -> out[0] = controller.getRecentTasks(maxNum, flags, userId)
+ .toArray(new GroupedRecentTaskInfo[0]),
+ true /* blocking */);
+ return out[0];
+ }
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopup.java
index 78af9df30e6a..ff6f913207f6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopup.java
@@ -17,13 +17,10 @@
package com.android.wm.shell.sizecompatui;
import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.Color;
-import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
import android.view.View;
-import android.widget.Button;
import android.widget.FrameLayout;
+import android.widget.LinearLayout;
import androidx.annotation.Nullable;
@@ -58,10 +55,8 @@ public class SizeCompatHintPopup extends FrameLayout implements View.OnClickList
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- final Button gotItButton = findViewById(R.id.got_it);
- gotItButton.setBackground(new RippleDrawable(ColorStateList.valueOf(Color.LTGRAY),
- null /* content */, null /* mask */));
- gotItButton.setOnClickListener(this);
+ final LinearLayout hintPopup = findViewById(R.id.size_compat_hint_popup);
+ hintPopup.setOnClickListener(this);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButton.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButton.java
index 08a840297df1..d75fe5173c5f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButton.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButton.java
@@ -17,10 +17,6 @@
package com.android.wm.shell.sizecompatui;
import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.Color;
-import android.graphics.drawable.GradientDrawable;
-import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
@@ -63,11 +59,6 @@ public class SizeCompatRestartButton extends FrameLayout implements View.OnClick
protected void onFinishInflate() {
super.onFinishInflate();
final ImageButton restartButton = findViewById(R.id.size_compat_restart_button);
- final ColorStateList color = ColorStateList.valueOf(Color.LTGRAY);
- final GradientDrawable mask = new GradientDrawable();
- mask.setShape(GradientDrawable.OVAL);
- mask.setColor(color);
- restartButton.setBackground(new RippleDrawable(color, null /* content */, mask));
restartButton.setOnClickListener(this);
restartButton.setOnLongClickListener(this);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java
index ab3cbd655ea1..04d974a09cd7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java
@@ -24,11 +24,16 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
import android.view.Display;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
import com.android.internal.annotations.VisibleForTesting;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayController.OnDisplaysChangedListener;
import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.DisplayInsetsController.OnInsetsChangedListener;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
@@ -42,7 +47,7 @@ import java.util.function.Consumer;
* Controls to show/update restart-activity buttons on Tasks based on whether the foreground
* activities are in size compatibility mode.
*/
-public class SizeCompatUIController implements DisplayController.OnDisplaysChangedListener,
+public class SizeCompatUIController implements OnDisplaysChangedListener,
DisplayImeController.ImePositionProcessor {
/** Callback for size compat UI interaction. */
@@ -58,6 +63,10 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
/** Whether the IME is shown on display id. */
private final Set<Integer> mDisplaysWithIme = new ArraySet<>(1);
+ /** {@link PerDisplayOnInsetsChangedListener} by display id. */
+ private final SparseArray<PerDisplayOnInsetsChangedListener> mOnInsetsChangedListeners =
+ new SparseArray<>(0);
+
/** The showing UIs by task id. */
private final SparseArray<SizeCompatUILayout> mActiveLayouts = new SparseArray<>(0);
@@ -66,6 +75,7 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
private final Context mContext;
private final DisplayController mDisplayController;
+ private final DisplayInsetsController mDisplayInsetsController;
private final DisplayImeController mImeController;
private final SyncTransactionQueue mSyncQueue;
@@ -76,10 +86,12 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
public SizeCompatUIController(Context context,
DisplayController displayController,
+ DisplayInsetsController displayInsetsController,
DisplayImeController imeController,
SyncTransactionQueue syncQueue) {
mContext = context;
mDisplayController = displayController;
+ mDisplayInsetsController = displayInsetsController;
mImeController = imeController;
mSyncQueue = syncQueue;
mDisplayController.addDisplayWindowListener(this);
@@ -115,8 +127,14 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
}
@Override
+ public void onDisplayAdded(int displayId) {
+ addOnInsetsChangedListener(displayId);
+ }
+
+ @Override
public void onDisplayRemoved(int displayId) {
mDisplayContextCache.remove(displayId);
+ removeOnInsetsChangedListener(displayId);
// Remove all size compat UIs on the removed display.
final List<Integer> toRemoveTaskIds = new ArrayList<>();
@@ -126,8 +144,29 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
}
}
+ private void addOnInsetsChangedListener(int displayId) {
+ PerDisplayOnInsetsChangedListener listener = new PerDisplayOnInsetsChangedListener(
+ displayId);
+ listener.register();
+ mOnInsetsChangedListeners.put(displayId, listener);
+ }
+
+ private void removeOnInsetsChangedListener(int displayId) {
+ PerDisplayOnInsetsChangedListener listener = mOnInsetsChangedListeners.get(displayId);
+ if (listener == null) {
+ return;
+ }
+ listener.unregister();
+ mOnInsetsChangedListeners.remove(displayId);
+ }
+
+
@Override
public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+ updateDisplayLayout(displayId);
+ }
+
+ private void updateDisplayLayout(int displayId) {
final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(displayId);
forAllLayoutsOnDisplay(displayId, layout -> layout.updateDisplayLayout(displayLayout));
}
@@ -219,4 +258,37 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
}
}
}
+
+ /** An implementation of {@link OnInsetsChangedListener} for a given display id. */
+ private class PerDisplayOnInsetsChangedListener implements OnInsetsChangedListener {
+ final int mDisplayId;
+ final InsetsState mInsetsState = new InsetsState();
+
+ PerDisplayOnInsetsChangedListener(int displayId) {
+ mDisplayId = displayId;
+ }
+
+ void register() {
+ mDisplayInsetsController.addInsetsChangedListener(mDisplayId, this);
+ }
+
+ void unregister() {
+ mDisplayInsetsController.removeInsetsChangedListener(mDisplayId, this);
+ }
+
+ @Override
+ public void insetsChanged(InsetsState insetsState) {
+ if (mInsetsState.equals(insetsState)) {
+ return;
+ }
+ mInsetsState.set(insetsState);
+ updateDisplayLayout(mDisplayId);
+ }
+
+ @Override
+ public void insetsControlChanged(InsetsState insetsState,
+ InsetsSourceControl[] activeControls) {
+ insetsChanged(insetsState);
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
index 7cf95593dbaa..1a2c94fd4747 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java
@@ -25,6 +25,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Binder;
@@ -54,6 +55,11 @@ class SizeCompatUILayout {
private final int mTaskId;
private ShellTaskOrganizer.TaskListener mTaskListener;
private DisplayLayout mDisplayLayout;
+ private final Rect mStableBounds;
+ private final int mButtonWidth;
+ private final int mButtonHeight;
+ private final int mPopupOffsetX;
+ private final int mPopupOffsetY;
@VisibleForTesting
final SizeCompatUIWindowManager mButtonWindowManager;
@@ -66,9 +72,7 @@ class SizeCompatUILayout {
@VisibleForTesting
@Nullable
SizeCompatHintPopup mHint;
- final int mButtonSize;
- final int mPopupOffsetX;
- final int mPopupOffsetY;
+ @VisibleForTesting
boolean mShouldShowHint;
SizeCompatUILayout(SyncTransactionQueue syncQueue,
@@ -86,10 +90,16 @@ class SizeCompatUILayout {
mShouldShowHint = !hasShownHint;
mButtonWindowManager = new SizeCompatUIWindowManager(mContext, taskConfig, this);
- mButtonSize =
- mContext.getResources().getDimensionPixelSize(R.dimen.size_compat_button_size);
- mPopupOffsetX = mButtonSize / 4;
- mPopupOffsetY = mButtonSize;
+ mStableBounds = new Rect();
+ mDisplayLayout.getStableBounds(mStableBounds);
+
+ final Resources resources = mContext.getResources();
+ mButtonWidth = resources.getDimensionPixelSize(R.dimen.size_compat_button_width);
+ mButtonHeight = resources.getDimensionPixelSize(R.dimen.size_compat_button_height);
+ mPopupOffsetX = (mButtonWidth / 2) - resources.getDimensionPixelSize(
+ R.dimen.size_compat_hint_corner_radius) - (resources.getDimensionPixelSize(
+ R.dimen.size_compat_hint_point_width) / 2);
+ mPopupOffsetY = mButtonHeight;
}
/** Creates the activity restart button window. */
@@ -167,8 +177,7 @@ class SizeCompatUILayout {
if (!taskConfig.windowConfiguration.getBounds()
.equals(prevTaskConfig.windowConfiguration.getBounds())) {
// Reposition the UI surfaces.
- updateButtonSurfacePosition();
- updateHintSurfacePosition();
+ updateAllSurfacePositions();
}
if (taskConfig.getLayoutDirection() != prevTaskConfig.getLayoutDirection()) {
@@ -184,19 +193,14 @@ class SizeCompatUILayout {
/** Called when display layout changed. */
void updateDisplayLayout(DisplayLayout displayLayout) {
- if (displayLayout == mDisplayLayout) {
- return;
- }
-
- final Rect prevStableBounds = new Rect();
+ final Rect prevStableBounds = mStableBounds;
final Rect curStableBounds = new Rect();
- mDisplayLayout.getStableBounds(prevStableBounds);
displayLayout.getStableBounds(curStableBounds);
mDisplayLayout = displayLayout;
if (!prevStableBounds.equals(curStableBounds)) {
// Stable bounds changed, update UI surface positions.
- updateButtonSurfacePosition();
- updateHintSurfacePosition();
+ updateAllSurfacePositions();
+ mStableBounds.set(curStableBounds);
}
}
@@ -222,7 +226,7 @@ class SizeCompatUILayout {
WindowManager.LayoutParams getButtonWindowLayoutParams() {
final WindowManager.LayoutParams winParams = new WindowManager.LayoutParams(
// Cannot be wrap_content as this determines the actual window size
- mButtonSize, mButtonSize,
+ mButtonWidth, mButtonHeight,
TYPE_APPLICATION_OVERLAY,
FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT);
@@ -262,6 +266,11 @@ class SizeCompatUILayout {
createSizeCompatHint();
}
+ private void updateAllSurfacePositions() {
+ updateButtonSurfacePosition();
+ updateHintSurfacePosition();
+ }
+
@VisibleForTesting
void updateButtonSurfacePosition() {
if (mButton == null || mButtonWindowManager.getSurfaceControl() == null) {
@@ -278,12 +287,13 @@ class SizeCompatUILayout {
// Position of the button in the container coordinate.
final int positionX = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL
? stableBounds.left - taskBounds.left
- : stableBounds.right - taskBounds.left - mButtonSize;
- final int positionY = stableBounds.bottom - taskBounds.top - mButtonSize;
+ : stableBounds.right - taskBounds.left - mButtonWidth;
+ final int positionY = stableBounds.bottom - taskBounds.top - mButtonHeight;
updateSurfacePosition(leash, positionX, positionY);
}
+ @VisibleForTesting
void updateHintSurfacePosition() {
if (mHint == null || mHintWindowManager == null
|| mHintWindowManager.getSurfaceControl() == null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
index a47a15287dda..082fe9205be8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
@@ -16,14 +16,14 @@
package com.android.wm.shell.splitscreen;
-import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
-
import android.annotation.Nullable;
+import android.content.Context;
import android.graphics.Rect;
import android.view.SurfaceSession;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
+import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.SyncTransactionQueue;
@@ -37,11 +37,11 @@ class MainStage extends StageTaskListener {
private boolean mIsActive = false;
- MainStage(ShellTaskOrganizer taskOrganizer, int displayId,
+ MainStage(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
- SurfaceSession surfaceSession,
+ SurfaceSession surfaceSession, IconProvider iconProvider,
@Nullable StageTaskUnfoldController stageTaskUnfoldController) {
- super(taskOrganizer, displayId, callbacks, syncQueue, surfaceSession,
+ super(context, taskOrganizer, displayId, callbacks, syncQueue, surfaceSession, iconProvider,
stageTaskUnfoldController);
}
@@ -54,7 +54,6 @@ class MainStage extends StageTaskListener {
final WindowContainerToken rootToken = mRootTaskInfo.token;
wct.setBounds(rootToken, rootBounds)
- .setWindowingMode(rootToken, WINDOWING_MODE_MULTI_WINDOW)
// Moving the root task to top after the child tasks were re-parented , or the root
// task cannot be visible and focused.
.reorder(rootToken, true /* onTop */);
@@ -81,11 +80,7 @@ class MainStage extends StageTaskListener {
if (mRootTaskInfo == null) return;
final WindowContainerToken rootToken = mRootTaskInfo.token;
- wct.setLaunchRoot(
- rootToken,
- null,
- null)
- .reparentTasks(
+ wct.reparentTasks(
rootToken,
null /* newParent */,
CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE,
@@ -95,9 +90,4 @@ class MainStage extends StageTaskListener {
// all its tasks.
.reorder(rootToken, false /* onTop */);
}
-
- void updateConfiguration(int windowingMode, Rect bounds, WindowContainerTransaction wct) {
- wct.setBounds(mRootTaskInfo.token, bounds)
- .setWindowingMode(mRootTaskInfo.token, windowingMode);
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineManager.java
deleted file mode 100644
index a459c8dbfa34..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineManager.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.splitscreen;
-
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.os.Binder;
-import android.view.IWindow;
-import android.view.InsetsSource;
-import android.view.InsetsState;
-import android.view.LayoutInflater;
-import android.view.SurfaceControl;
-import android.view.SurfaceControlViewHost;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.WindowlessWindowManager;
-import android.widget.FrameLayout;
-
-import com.android.wm.shell.R;
-
-/**
- * Handles drawing outline of the bounds of provided root surface. The outline will be drown with
- * the consideration of display insets like status bar, navigation bar and display cutout.
- */
-class OutlineManager extends WindowlessWindowManager {
- private static final String WINDOW_NAME = "SplitOutlineLayer";
- private final Context mContext;
- private final Rect mRootBounds = new Rect();
- private final Rect mTempRect = new Rect();
- private final Rect mLastOutlineBounds = new Rect();
- private final InsetsState mInsetsState = new InsetsState();
- private final int mExpandedTaskBarHeight;
- private OutlineView mOutlineView;
- private SurfaceControlViewHost mViewHost;
- private SurfaceControl mHostLeash;
- private SurfaceControl mLeash;
-
- OutlineManager(Context context, Configuration configuration) {
- super(configuration, null /* rootSurface */, null /* hostInputToken */);
- mContext = context.createWindowContext(context.getDisplay(), TYPE_APPLICATION_OVERLAY,
- null /* options */);
- mExpandedTaskBarHeight = mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.taskbar_frame_height);
- }
-
- @Override
- protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
- b.setParent(mHostLeash);
- }
-
- void inflate(SurfaceControl rootLeash, Rect rootBounds) {
- if (mLeash != null || mViewHost != null) return;
-
- mHostLeash = rootLeash;
- mRootBounds.set(rootBounds);
- mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
-
- final FrameLayout rootLayout = (FrameLayout) LayoutInflater.from(mContext)
- .inflate(R.layout.split_outline, null);
- mOutlineView = rootLayout.findViewById(R.id.split_outline);
-
- final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- 0 /* width */, 0 /* height */, TYPE_APPLICATION_OVERLAY,
- FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT);
- lp.width = mRootBounds.width();
- lp.height = mRootBounds.height();
- lp.token = new Binder();
- lp.setTitle(WINDOW_NAME);
- lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
- // TODO(b/189839391): Set INPUT_FEATURE_NO_INPUT_CHANNEL after WM supports
- // TRUSTED_OVERLAY for windowless window without input channel.
- mViewHost.setView(rootLayout, lp);
- mLeash = getSurfaceControl(mViewHost.getWindowToken());
-
- drawOutline();
- }
-
- void release() {
- if (mViewHost != null) {
- mViewHost.release();
- mViewHost = null;
- }
- mRootBounds.setEmpty();
- mLastOutlineBounds.setEmpty();
- mOutlineView = null;
- mHostLeash = null;
- mLeash = null;
- }
-
- @Nullable
- SurfaceControl getOutlineLeash() {
- return mLeash;
- }
-
- void setVisibility(boolean visible) {
- if (mOutlineView != null) {
- mOutlineView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
- }
- }
-
- void setRootBounds(Rect rootBounds) {
- if (mViewHost == null || mViewHost.getView() == null) {
- return;
- }
-
- if (!mRootBounds.equals(rootBounds)) {
- WindowManager.LayoutParams lp =
- (WindowManager.LayoutParams) mViewHost.getView().getLayoutParams();
- lp.width = rootBounds.width();
- lp.height = rootBounds.height();
- mViewHost.relayout(lp);
- mRootBounds.set(rootBounds);
- drawOutline();
- }
- }
-
- void onInsetsChanged(InsetsState insetsState) {
- if (!mInsetsState.equals(insetsState)) {
- mInsetsState.set(insetsState);
- drawOutline();
- }
- }
-
- private void computeOutlineBounds(Rect rootBounds, InsetsState insetsState, Rect outBounds) {
- outBounds.set(rootBounds);
- final InsetsSource taskBarInsetsSource =
- insetsState.getSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
- // Only insets the divider bar with task bar when it's expanded so that the rounded corners
- // will be drawn against task bar.
- if (taskBarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight) {
- outBounds.inset(taskBarInsetsSource.calculateVisibleInsets(outBounds));
- }
-
- // Offset the coordinate from screen based to surface based.
- outBounds.offset(-rootBounds.left, -rootBounds.top);
- }
-
- void drawOutline() {
- if (mOutlineView == null) {
- return;
- }
-
- computeOutlineBounds(mRootBounds, mInsetsState, mTempRect);
- if (mTempRect.equals(mLastOutlineBounds)) {
- return;
- }
-
- ViewGroup.MarginLayoutParams lp =
- (ViewGroup.MarginLayoutParams) mOutlineView.getLayoutParams();
- lp.leftMargin = mTempRect.left;
- lp.topMargin = mTempRect.top;
- lp.width = mTempRect.width();
- lp.height = mTempRect.height();
- mOutlineView.setLayoutParams(lp);
- mLastOutlineBounds.set(mTempRect);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineView.java
deleted file mode 100644
index 94dd9b24875a..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineView.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.splitscreen;
-
-import static android.view.RoundedCorner.POSITION_BOTTOM_LEFT;
-import static android.view.RoundedCorner.POSITION_BOTTOM_RIGHT;
-import static android.view.RoundedCorner.POSITION_TOP_LEFT;
-import static android.view.RoundedCorner.POSITION_TOP_RIGHT;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.util.AttributeSet;
-import android.view.RoundedCorner;
-import android.view.View;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.internal.R;
-
-/** View for drawing split outline. */
-public class OutlineView extends View {
- private final Paint mPaint = new Paint();
- private final Path mPath = new Path();
- private final float[] mRadii = new float[8];
-
- public OutlineView(@NonNull Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- mPaint.setStyle(Paint.Style.STROKE);
- mPaint.setStrokeWidth(
- getResources().getDimension(R.dimen.accessibility_focus_highlight_stroke_width));
- mPaint.setColor(getResources().getColor(R.color.system_accent1_100, null));
- }
-
- @Override
- protected void onAttachedToWindow() {
- // TODO(b/200850654): match the screen corners with the actual display decor.
- mRadii[0] = mRadii[1] = getCornerRadius(POSITION_TOP_LEFT);
- mRadii[2] = mRadii[3] = getCornerRadius(POSITION_TOP_RIGHT);
- mRadii[4] = mRadii[5] = getCornerRadius(POSITION_BOTTOM_RIGHT);
- mRadii[6] = mRadii[7] = getCornerRadius(POSITION_BOTTOM_LEFT);
- }
-
- private int getCornerRadius(@RoundedCorner.Position int position) {
- final RoundedCorner roundedCorner = getDisplay().getRoundedCorner(position);
- return roundedCorner == null ? 0 : roundedCorner.getRadius();
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- if (changed) {
- mPath.reset();
- mPath.addRoundRect(0, 0, getWidth(), getHeight(), mRadii, Path.Direction.CW);
- }
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- canvas.drawPath(mPath, mPaint);
- }
-
- @Override
- public boolean hasOverlappingRendering() {
- return false;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
index dc8fb9fbd7a3..f8c03044c5c9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
@@ -16,20 +16,16 @@
package com.android.wm.shell.splitscreen;
-import android.annotation.CallSuper;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Rect;
-import android.view.InsetsSourceControl;
-import android.view.InsetsState;
-import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
+import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.SyncTransactionQueue;
/**
@@ -38,29 +34,24 @@ import com.android.wm.shell.common.SyncTransactionQueue;
*
* @see StageCoordinator
*/
-class SideStage extends StageTaskListener implements
- DisplayInsetsController.OnInsetsChangedListener {
+class SideStage extends StageTaskListener {
private static final String TAG = SideStage.class.getSimpleName();
- private final Context mContext;
- private OutlineManager mOutlineManager;
SideStage(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
- SurfaceSession surfaceSession,
+ SurfaceSession surfaceSession, IconProvider iconProvider,
@Nullable StageTaskUnfoldController stageTaskUnfoldController) {
- super(taskOrganizer, displayId, callbacks, syncQueue, surfaceSession,
+ super(context, taskOrganizer, displayId, callbacks, syncQueue, surfaceSession, iconProvider,
stageTaskUnfoldController);
- mContext = context;
}
- void addTask(ActivityManager.RunningTaskInfo task, Rect rootBounds,
- WindowContainerTransaction wct) {
+ void moveToTop(Rect rootBounds, WindowContainerTransaction wct) {
final WindowContainerToken rootToken = mRootTaskInfo.token;
- wct.setBounds(rootToken, rootBounds)
- .reparent(task.token, rootToken, true /* onTop*/)
- // Moving the root task to top after the child tasks were reparented , or the root
- // task cannot be visible and focused.
- .reorder(rootToken, true /* onTop */);
+ wct.setBounds(rootToken, rootBounds).reorder(rootToken, true /* onTop */);
+ }
+
+ void addTask(ActivityManager.RunningTaskInfo task, WindowContainerTransaction wct) {
+ wct.reparent(task.token, mRootTaskInfo.token, true /* onTop*/);
}
boolean removeAllTasks(WindowContainerTransaction wct, boolean toTop) {
@@ -83,62 +74,4 @@ class SideStage extends StageTaskListener implements
wct.reparent(task.token, newParent, false /* onTop */);
return true;
}
-
- @Nullable
- public SurfaceControl getOutlineLeash() {
- return mOutlineManager.getOutlineLeash();
- }
-
- @Override
- @CallSuper
- public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
- super.onTaskAppeared(taskInfo, leash);
- if (isRootTask(taskInfo)) {
- mOutlineManager = new OutlineManager(mContext, taskInfo.configuration);
- enableOutline(true);
- }
- }
-
- @Override
- @CallSuper
- public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
- super.onTaskInfoChanged(taskInfo);
- if (isRootTask(taskInfo)) {
- mOutlineManager.setRootBounds(taskInfo.configuration.windowConfiguration.getBounds());
- }
- }
-
- private boolean isRootTask(ActivityManager.RunningTaskInfo taskInfo) {
- return mRootTaskInfo != null && mRootTaskInfo.taskId == taskInfo.taskId;
- }
-
- void enableOutline(boolean enable) {
- if (mOutlineManager == null) {
- return;
- }
-
- if (enable) {
- if (mRootTaskInfo != null) {
- mOutlineManager.inflate(mRootLeash,
- mRootTaskInfo.configuration.windowConfiguration.getBounds());
- }
- } else {
- mOutlineManager.release();
- }
- }
-
- void setOutlineVisibility(boolean visible) {
- mOutlineManager.setVisibility(visible);
- }
-
- @Override
- public void insetsChanged(InsetsState insetsState) {
- mOutlineManager.onInsetsChanged(insetsState);
- }
-
- @Override
- public void insetsControlChanged(InsetsState insetsState,
- InsetsSourceControl[] activeControls) {
- insetsChanged(insetsState);
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 3b75bfb933c9..7457be2d0871 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -34,7 +34,6 @@ import android.content.Intent;
import android.content.pm.LauncherApps;
import android.graphics.Rect;
import android.os.Bundle;
-import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArrayMap;
@@ -49,26 +48,31 @@ import android.window.RemoteTransition;
import android.window.WindowContainerTransaction;
import androidx.annotation.BinderThread;
+import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.logging.InstanceId;
-import com.android.internal.util.FrameworkStatsLog;
+import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SingleInstanceRemoteListener;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.common.split.SplitLayout.SplitPosition;
import com.android.wm.shell.draganddrop.DragAndDropPolicy;
+import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.transition.LegacyTransitions;
import com.android.wm.shell.transition.Transitions;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.Optional;
import java.util.concurrent.Executor;
@@ -78,6 +82,7 @@ import javax.inject.Provider;
/**
* Class manages split-screen multitasking mode and implements the main interface
* {@link SplitScreen}.
+ *
* @see StageCoordinator
*/
// TODO(b/198577848): Implement split screen flicker test to consolidate CUJ of split screen.
@@ -85,6 +90,29 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
RemoteCallable<SplitScreenController> {
private static final String TAG = SplitScreenController.class.getSimpleName();
+ static final int EXIT_REASON_UNKNOWN = 0;
+ static final int EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW = 1;
+ static final int EXIT_REASON_APP_FINISHED = 2;
+ static final int EXIT_REASON_DEVICE_FOLDED = 3;
+ static final int EXIT_REASON_DRAG_DIVIDER = 4;
+ static final int EXIT_REASON_RETURN_HOME = 5;
+ static final int EXIT_REASON_ROOT_TASK_VANISHED = 6;
+ static final int EXIT_REASON_SCREEN_LOCKED = 7;
+ static final int EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP = 8;
+ @IntDef(value = {
+ EXIT_REASON_UNKNOWN,
+ EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW,
+ EXIT_REASON_APP_FINISHED,
+ EXIT_REASON_DEVICE_FOLDED,
+ EXIT_REASON_DRAG_DIVIDER,
+ EXIT_REASON_RETURN_HOME,
+ EXIT_REASON_ROOT_TASK_VANISHED,
+ EXIT_REASON_SCREEN_LOCKED,
+ EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface ExitReason{}
+
private final ShellTaskOrganizer mTaskOrganizer;
private final SyncTransactionQueue mSyncQueue;
private final Context mContext;
@@ -96,16 +124,32 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
private final Transitions mTransitions;
private final TransactionPool mTransactionPool;
private final SplitscreenEventLogger mLogger;
+ private final IconProvider mIconProvider;
+ private final Optional<RecentTasksController> mRecentTasksOptional;
private final Provider<Optional<StageTaskUnfoldController>> mUnfoldControllerProvider;
private StageCoordinator mStageCoordinator;
+ // TODO(b/205019015): Remove after we clean up downstream modules
public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer,
SyncTransactionQueue syncQueue, Context context,
RootTaskDisplayAreaOrganizer rootTDAOrganizer,
ShellExecutor mainExecutor, DisplayImeController displayImeController,
DisplayInsetsController displayInsetsController,
- Transitions transitions, TransactionPool transactionPool,
+ Transitions transitions, TransactionPool transactionPool, IconProvider iconProvider,
+ Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) {
+ this(shellTaskOrganizer, syncQueue, context, rootTDAOrganizer, mainExecutor,
+ displayImeController, displayInsetsController, transitions, transactionPool,
+ iconProvider, Optional.empty(), unfoldControllerProvider);
+ }
+
+ public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer,
+ SyncTransactionQueue syncQueue, Context context,
+ RootTaskDisplayAreaOrganizer rootTDAOrganizer,
+ ShellExecutor mainExecutor, DisplayImeController displayImeController,
+ DisplayInsetsController displayInsetsController,
+ Transitions transitions, TransactionPool transactionPool, IconProvider iconProvider,
+ Optional<RecentTasksController> recentTasks,
Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) {
mTaskOrganizer = shellTaskOrganizer;
mSyncQueue = syncQueue;
@@ -118,6 +162,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mTransactionPool = transactionPool;
mUnfoldControllerProvider = unfoldControllerProvider;
mLogger = new SplitscreenEventLogger();
+ mIconProvider = iconProvider;
+ mRecentTasksOptional = recentTasks;
}
public SplitScreen asSplitScreen() {
@@ -140,7 +186,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
mRootTDAOrganizer, mTaskOrganizer, mDisplayImeController,
mDisplayInsetsController, mTransitions, mTransactionPool, mLogger,
- mUnfoldControllerProvider);
+ mIconProvider, mRecentTasksOptional, mUnfoldControllerProvider);
}
}
@@ -156,17 +202,27 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
return moveToSideStage(task, sideStagePosition);
}
+ public boolean moveToSideStage(int taskId, @SplitPosition int sideStagePosition,
+ WindowContainerTransaction wct) {
+ final ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId);
+ if (task == null) {
+ throw new IllegalArgumentException("Unknown taskId" + taskId);
+ }
+ return moveToSideStage(task, sideStagePosition, wct);
+ }
+
public boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
@SplitPosition int sideStagePosition) {
return mStageCoordinator.moveToSideStage(task, sideStagePosition);
}
- public boolean removeFromSideStage(int taskId) {
- return mStageCoordinator.removeFromSideStage(taskId);
+ public boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
+ @SplitPosition int sideStagePosition, WindowContainerTransaction wct) {
+ return mStageCoordinator.moveToSideStage(task, sideStagePosition, wct);
}
- public void setSideStageOutline(boolean enable) {
- mStageCoordinator.setSideStageOutline(enable);
+ public boolean removeFromSideStage(int taskId) {
+ return mStageCoordinator.removeFromSideStage(taskId);
}
public void setSideStagePosition(@SplitPosition int sideStagePosition) {
@@ -182,7 +238,12 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT);
}
- public void exitSplitScreen(int toTopTaskId, int exitReason) {
+ public void enterSplitScreen(int taskId, boolean leftOrTop, WindowContainerTransaction wct) {
+ moveToSideStage(taskId,
+ leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT, wct);
+ }
+
+ public void exitSplitScreen(int toTopTaskId, @ExitReason int exitReason) {
mStageCoordinator.exitSplitScreen(toTopTaskId, exitReason);
}
@@ -319,9 +380,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
}
transaction.apply();
transaction.close();
- return new RemoteAnimationTarget[]{
- mStageCoordinator.getDividerBarLegacyTarget(),
- mStageCoordinator.getOutlineLegacyTarget()};
+ return new RemoteAnimationTarget[]{mStageCoordinator.getDividerBarLegacyTarget()};
}
/**
@@ -331,6 +390,34 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mStageCoordinator.logOnDroppedToSplit(position, dragSessionId);
}
+ /**
+ * Return the {@param exitReason} as a string.
+ */
+ public static String exitReasonToString(int exitReason) {
+ switch (exitReason) {
+ case EXIT_REASON_UNKNOWN:
+ return "UNKNOWN_EXIT";
+ case EXIT_REASON_DRAG_DIVIDER:
+ return "DRAG_DIVIDER";
+ case EXIT_REASON_RETURN_HOME:
+ return "RETURN_HOME";
+ case EXIT_REASON_SCREEN_LOCKED:
+ return "SCREEN_LOCKED";
+ case EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP:
+ return "SCREEN_LOCKED_SHOW_ON_TOP";
+ case EXIT_REASON_DEVICE_FOLDED:
+ return "DEVICE_FOLDED";
+ case EXIT_REASON_ROOT_TASK_VANISHED:
+ return "ROOT_TASK_VANISHED";
+ case EXIT_REASON_APP_FINISHED:
+ return "APP_FINISHED";
+ case EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW:
+ return "APP_DOES_NOT_SUPPORT_MULTIWINDOW";
+ default:
+ return "unknown reason, reason int = " + exitReason;
+ }
+ }
+
public void dump(@NonNull PrintWriter pw, String prefix) {
pw.println(prefix + TAG);
if (mStageCoordinator != null) {
@@ -435,46 +522,26 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
@BinderThread
private static class ISplitScreenImpl extends ISplitScreen.Stub {
private SplitScreenController mController;
- private ISplitScreenListener mListener;
+ private final SingleInstanceRemoteListener<SplitScreenController,
+ ISplitScreenListener> mListener;
private final SplitScreen.SplitScreenListener mSplitScreenListener =
new SplitScreen.SplitScreenListener() {
@Override
public void onStagePositionChanged(int stage, int position) {
- try {
- if (mListener != null) {
- mListener.onStagePositionChanged(stage, position);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "onStagePositionChanged", e);
- }
+ mListener.call(l -> l.onStagePositionChanged(stage, position));
}
@Override
public void onTaskStageChanged(int taskId, int stage, boolean visible) {
- try {
- if (mListener != null) {
- mListener.onTaskStageChanged(taskId, stage, visible);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "onTaskStageChanged", e);
- }
- }
- };
- private final IBinder.DeathRecipient mListenerDeathRecipient =
- new IBinder.DeathRecipient() {
- @Override
- @BinderThread
- public void binderDied() {
- final SplitScreenController controller = mController;
- controller.getRemoteCallExecutor().execute(() -> {
- mListener = null;
- controller.unregisterSplitScreenListener(mSplitScreenListener);
- });
+ mListener.call(l -> l.onTaskStageChanged(taskId, stage, visible));
}
};
public ISplitScreenImpl(SplitScreenController controller) {
mController = controller;
+ mListener = new SingleInstanceRemoteListener<>(controller,
+ c -> c.registerSplitScreenListener(mSplitScreenListener),
+ c -> c.unregisterSplitScreenListener(mSplitScreenListener));
}
/**
@@ -487,44 +554,20 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
@Override
public void registerSplitScreenListener(ISplitScreenListener listener) {
executeRemoteCallWithTaskPermission(mController, "registerSplitScreenListener",
- (controller) -> {
- if (mListener != null) {
- mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
- 0 /* flags */);
- }
- if (listener != null) {
- try {
- listener.asBinder().linkToDeath(mListenerDeathRecipient,
- 0 /* flags */);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to link to death");
- return;
- }
- }
- mListener = listener;
- controller.registerSplitScreenListener(mSplitScreenListener);
- });
+ (controller) -> mListener.register(listener));
}
@Override
public void unregisterSplitScreenListener(ISplitScreenListener listener) {
executeRemoteCallWithTaskPermission(mController, "unregisterSplitScreenListener",
- (controller) -> {
- if (mListener != null) {
- mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
- 0 /* flags */);
- }
- mListener = null;
- controller.unregisterSplitScreenListener(mSplitScreenListener);
- });
+ (controller) -> mListener.unregister());
}
@Override
public void exitSplitScreen(int toTopTaskId) {
executeRemoteCallWithTaskPermission(mController, "exitSplitScreen",
(controller) -> {
- controller.exitSplitScreen(toTopTaskId,
- FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__UNKNOWN_EXIT);
+ controller.exitSplitScreen(toTopTaskId, EXIT_REASON_UNKNOWN);
});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
index 319079baaccf..e320c2a23a0a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
@@ -17,13 +17,34 @@
package com.android.wm.shell.splitscreen;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__ENTER_REASON__OVERVIEW;
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__APP_DOES_NOT_SUPPORT_MULTIWINDOW;
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__APP_FINISHED;
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__DEVICE_FOLDED;
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__DRAG_DIVIDER;
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME;
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__ROOT_TASK_VANISHED;
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED;
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED_SHOW_ON_TOP;
+import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__UNKNOWN_EXIT;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_UNDEFINED;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_FINISHED;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DEVICE_FOLDED;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_RETURN_HOME;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_ROOT_TASK_VANISHED;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_SCREEN_LOCKED;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_UNKNOWN;
+
+import android.util.Slog;
import com.android.internal.logging.InstanceId;
import com.android.internal.logging.InstanceIdSequence;
import com.android.internal.util.FrameworkStatsLog;
import com.android.wm.shell.common.split.SplitLayout.SplitPosition;
+import com.android.wm.shell.splitscreen.SplitScreenController.ExitReason;
/**
* Helper class that to log Drag & Drop UIEvents for a single session, see also go/uievent
@@ -96,10 +117,40 @@ public class SplitscreenEventLogger {
}
/**
+ * Returns the framework logging constant given a splitscreen exit reason.
+ */
+ private int getLoggerExitReason(@ExitReason int exitReason) {
+ switch (exitReason) {
+ case EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW:
+ return SPLITSCREEN_UICHANGED__EXIT_REASON__APP_DOES_NOT_SUPPORT_MULTIWINDOW;
+ case EXIT_REASON_APP_FINISHED:
+ return SPLITSCREEN_UICHANGED__EXIT_REASON__APP_FINISHED;
+ case EXIT_REASON_DEVICE_FOLDED:
+ return SPLITSCREEN_UICHANGED__EXIT_REASON__DEVICE_FOLDED;
+ case EXIT_REASON_DRAG_DIVIDER:
+ return SPLITSCREEN_UICHANGED__EXIT_REASON__DRAG_DIVIDER;
+ case EXIT_REASON_RETURN_HOME:
+ return SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME;
+ case EXIT_REASON_ROOT_TASK_VANISHED:
+ return SPLITSCREEN_UICHANGED__EXIT_REASON__ROOT_TASK_VANISHED;
+ case EXIT_REASON_SCREEN_LOCKED:
+ return SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED;
+ case EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP:
+ return SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED_SHOW_ON_TOP;
+ case EXIT_REASON_UNKNOWN:
+ // Fall through
+ default:
+ Slog.e("SplitscreenEventLogger", "Unknown exit reason: " + exitReason);
+ return SPLITSCREEN_UICHANGED__EXIT_REASON__UNKNOWN_EXIT;
+ }
+ }
+
+ /**
* Logs when the user exits splitscreen. Only one of the main or side stages should be
* specified to indicate which position was focused as a part of exiting (both can be unset).
*/
- public void logExit(int exitReason, @SplitPosition int mainStagePosition, int mainStageUid,
+ public void logExit(@ExitReason int exitReason,
+ @SplitPosition int mainStagePosition, int mainStageUid,
@SplitPosition int sideStagePosition, int sideStageUid, boolean isLandscape) {
if (mLoggerSessionId == null) {
// Ignore changes until we've started logging the session
@@ -113,7 +164,7 @@ public class SplitscreenEventLogger {
FrameworkStatsLog.write(FrameworkStatsLog.SPLITSCREEN_UI_CHANGED,
FrameworkStatsLog.SPLITSCREEN_UICHANGED__ACTION__EXIT,
0 /* enterReason */,
- exitReason,
+ getLoggerExitReason(exitReason),
0f /* splitRatio */,
getMainStagePositionFromSplitPosition(mainStagePosition, isLandscape),
mainStageUid,
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 72d9880d0aa1..050d255bfd2d 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
@@ -17,6 +17,7 @@
package com.android.wm.shell.splitscreen;
import static android.app.ActivityOptions.KEY_LAUNCH_ROOT_TASK_TOKEN;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.TRANSIT_OPEN;
@@ -25,12 +26,6 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.transitTypeToString;
import static android.view.WindowManagerPolicyConstants.SPLIT_DIVIDER_LAYER;
-import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__APP_DOES_NOT_SUPPORT_MULTIWINDOW;
-import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__APP_FINISHED;
-import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__DEVICE_FOLDED;
-import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__DRAG_DIVIDER;
-import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME;
-import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED_SHOW_ON_TOP;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_UNDEFINED;
@@ -38,6 +33,13 @@ import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_FINISHED;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DEVICE_FOLDED;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_RETURN_HOME;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP;
+import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonToString;
import static com.android.wm.shell.splitscreen.SplitScreenTransitions.FLAG_IS_DIVIDER_BAR;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS_SNAP;
@@ -80,6 +82,7 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayImeController;
@@ -90,7 +93,10 @@ import com.android.wm.shell.common.split.SplitLayout;
import com.android.wm.shell.common.split.SplitLayout.SplitPosition;
import com.android.wm.shell.common.split.SplitWindowManager;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.recents.RecentTasksController;
+import com.android.wm.shell.splitscreen.SplitScreenController.ExitReason;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.util.StagedSplitBounds;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -144,6 +150,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private final DisplayInsetsController mDisplayInsetsController;
private final SplitScreenTransitions mSplitTransitions;
private final SplitscreenEventLogger mLogger;
+ private final Optional<RecentTasksController> mRecentTasks;
+ // Tracks whether we should update the recent tasks. Only allow this to happen in between enter
+ // and exit, since exit itself can trigger a number of changes that update the stages.
+ private boolean mShouldUpdateRecents;
private boolean mExitSplitScreenOnHide;
private boolean mKeyguardOccluded;
@@ -151,10 +161,12 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
/** Whether the device is supporting legacy split or not. */
private boolean mUseLegacySplit;
- @SplitScreen.StageType private int mDismissTop = NO_DISMISS;
+ @SplitScreen.StageType
+ private int mDismissTop = NO_DISMISS;
/** The target stage to dismiss to when unlock after folded. */
- @SplitScreen.StageType private int mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
+ @SplitScreen.StageType
+ private int mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
private final Runnable mOnTransitionAnimationComplete = () -> {
// If still playing, let it finish.
@@ -169,22 +181,24 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private final SplitWindowManager.ParentContainerCallbacks mParentContainerCallbacks =
new SplitWindowManager.ParentContainerCallbacks() {
- @Override
- public void attachToParentSurface(SurfaceControl.Builder b) {
- mRootTDAOrganizer.attachToDisplayArea(mDisplayId, b);
- }
+ @Override
+ public void attachToParentSurface(SurfaceControl.Builder b) {
+ mRootTDAOrganizer.attachToDisplayArea(mDisplayId, b);
+ }
- @Override
- public void onLeashReady(SurfaceControl leash) {
- mSyncQueue.runInSync(t -> applyDividerVisibility(t));
- }
- };
+ @Override
+ public void onLeashReady(SurfaceControl leash) {
+ mSyncQueue.runInSync(t -> applyDividerVisibility(t));
+ }
+ };
StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
DisplayImeController displayImeController,
DisplayInsetsController displayInsetsController, Transitions transitions,
TransactionPool transactionPool, SplitscreenEventLogger logger,
+ IconProvider iconProvider,
+ Optional<RecentTasksController> recentTasks,
Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) {
mContext = context;
mDisplayId = displayId;
@@ -192,15 +206,18 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mRootTDAOrganizer = rootTDAOrganizer;
mTaskOrganizer = taskOrganizer;
mLogger = logger;
+ mRecentTasks = recentTasks;
mMainUnfoldController = unfoldControllerProvider.get().orElse(null);
mSideUnfoldController = unfoldControllerProvider.get().orElse(null);
mMainStage = new MainStage(
+ mContext,
mTaskOrganizer,
mDisplayId,
mMainStageListener,
mSyncQueue,
mSurfaceSession,
+ iconProvider,
mMainUnfoldController);
mSideStage = new SideStage(
mContext,
@@ -209,10 +226,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSideStageListener,
mSyncQueue,
mSurfaceSession,
+ iconProvider,
mSideUnfoldController);
mDisplayImeController = displayImeController;
mDisplayInsetsController = displayInsetsController;
- mDisplayInsetsController.addInsetsChangedListener(mDisplayId, mSideStage);
mRootTDAOrganizer.registerListener(displayId, this);
final DeviceStateManager deviceStateManager =
mContext.getSystemService(DeviceStateManager.class);
@@ -230,6 +247,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
DisplayInsetsController displayInsetsController, SplitLayout splitLayout,
Transitions transitions, TransactionPool transactionPool,
SplitscreenEventLogger logger,
+ Optional<RecentTasksController> recentTasks,
Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) {
mContext = context;
mDisplayId = displayId;
@@ -247,6 +265,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mMainUnfoldController = unfoldControllerProvider.get().orElse(null);
mSideUnfoldController = unfoldControllerProvider.get().orElse(null);
mLogger = logger;
+ mRecentTasks = recentTasks;
transitions.addHandler(this);
}
@@ -262,11 +281,19 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
@SplitPosition int sideStagePosition) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
+ return moveToSideStage(task, sideStagePosition, wct);
+ }
+
+ boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
+ @SplitPosition int sideStagePosition, WindowContainerTransaction wct) {
+ final WindowContainerTransaction evictWct = new WindowContainerTransaction();
setSideStagePosition(sideStagePosition, wct);
- mMainStage.activate(getMainStageBounds(), wct, true /* reparent */);
- mSideStage.addTask(task, getSideStageBounds(), wct);
- mSyncQueue.queue(wct);
- mSyncQueue.runInSync(t -> updateSurfaceBounds(null /* layout */, t));
+ mSideStage.evictAllChildren(evictWct);
+ mSideStage.addTask(task, wct);
+ if (!evictWct.isEmpty()) {
+ wct.merge(evictWct, true /* transfer */);
+ }
+ mTaskOrganizer.applyTransaction(wct);
return true;
}
@@ -284,10 +311,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return result;
}
- void setSideStageOutline(boolean enable) {
- mSideStage.enableOutline(enable);
- }
-
/** Starts 2 tasks in one transition. */
void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId,
@Nullable Bundle sideOptions, @SplitPosition int sidePosition,
@@ -335,8 +358,13 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
augmentedNonApps[augmentedNonApps.length - 1] = getDividerBarLegacyTarget();
try {
- ActivityTaskManager.getService().setRunningRemoteTransitionDelegate(
- adapter.getCallingApplication());
+ try {
+ ActivityTaskManager.getService().setRunningRemoteTransitionDelegate(
+ adapter.getCallingApplication());
+ } catch (SecurityException e) {
+ Slog.e(TAG, "Unable to boost animation thread. This should only happen"
+ + " during unit tests");
+ }
adapter.getRunner().onAnimationStart(transit, apps, wallpapers, nonApps,
finishedCallback);
} catch (RemoteException e) {
@@ -361,6 +389,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
} else {
ActivityOptions mainActivityOptions = ActivityOptions.fromBundle(mainOptions);
mainActivityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter));
+ mainOptions = mainActivityOptions.toBundle();
}
sideOptions = sideOptions != null ? sideOptions : new Bundle();
@@ -509,7 +538,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (!showing && mMainStage.isActive()
&& mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
exitSplitScreen(mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
- SPLITSCREEN_UICHANGED__EXIT_REASON__DEVICE_FOLDED);
+ EXIT_REASON_DEVICE_FOLDED);
}
}
@@ -517,7 +546,9 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mExitSplitScreenOnHide = exitSplitScreenOnHide;
}
- void exitSplitScreen(int toTopTaskId, int exitReason) {
+ void exitSplitScreen(int toTopTaskId, @ExitReason int exitReason) {
+ if (!mMainStage.isActive()) return;
+
StageTaskListener childrenToTop = null;
if (mMainStage.containsTask(toTopTaskId)) {
childrenToTop = mMainStage;
@@ -532,23 +563,38 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
applyExitSplitScreen(childrenToTop, wct, exitReason);
}
- private void exitSplitScreen(StageTaskListener childrenToTop, int exitReason) {
+ private void exitSplitScreen(StageTaskListener childrenToTop, @ExitReason int exitReason) {
+ if (!mMainStage.isActive()) return;
+
final WindowContainerTransaction wct = new WindowContainerTransaction();
applyExitSplitScreen(childrenToTop, wct, exitReason);
}
private void applyExitSplitScreen(StageTaskListener childrenToTop,
- WindowContainerTransaction wct, int exitReason) {
+ WindowContainerTransaction wct, @ExitReason int exitReason) {
+ mRecentTasks.ifPresent(recentTasks -> {
+ // Notify recents if we are exiting in a way that breaks the pair, and disable further
+ // updates to splits in the recents until we enter split again
+ if (shouldBreakPairedTaskInRecents(exitReason) && mShouldUpdateRecents) {
+ recentTasks.removeSplitPair(mMainStage.getTopVisibleChildTaskId());
+ recentTasks.removeSplitPair(mSideStage.getTopVisibleChildTaskId());
+ }
+ });
+ mShouldUpdateRecents = false;
+
mSideStage.removeAllTasks(wct, childrenToTop == mSideStage);
mMainStage.deactivate(wct, childrenToTop == mMainStage);
mTaskOrganizer.applyTransaction(wct);
mSyncQueue.runInSync(t -> t
.setWindowCrop(mMainStage.mRootLeash, null)
.setWindowCrop(mSideStage.mRootLeash, null));
+
// Hide divider and reset its position.
setDividerVisibility(false);
mSplitLayout.resetDividerPosition();
mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
+ Slog.i(TAG, "applyExitSplitScreen, reason = " + exitReasonToString(exitReason));
+ // Log the exit
if (childrenToTop != null) {
logExitToStage(exitReason, childrenToTop == mMainStage);
} else {
@@ -557,6 +603,23 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
/**
+ * Returns whether the split pair in the recent tasks list should be broken.
+ */
+ private boolean shouldBreakPairedTaskInRecents(@ExitReason int exitReason) {
+ switch (exitReason) {
+ // One of the apps doesn't support MW
+ case EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW:
+ // User has explicitly dragged the divider to dismiss split
+ case EXIT_REASON_DRAG_DIVIDER:
+ // Either of the split apps have finished
+ case EXIT_REASON_APP_FINISHED:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
* Unlike exitSplitScreen, this takes a stagetype vs an actual stage-reference and populates
* an existing WindowContainerTransaction (rather than applying immediately). This is intended
* to be used when exiting split might be bundled with other window operations.
@@ -622,12 +685,42 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mLogger.logSideStageAppChange(getSideStagePosition(), mSideStage.getTopChildTaskUid(),
mSplitLayout.isLandscape());
}
+ updateRecentTasksSplitPair();
for (int i = mListeners.size() - 1; i >= 0; --i) {
mListeners.get(i).onTaskStageChanged(taskId, stage, visible);
}
}
+ private void updateRecentTasksSplitPair() {
+ if (!mShouldUpdateRecents) {
+ return;
+ }
+
+ mRecentTasks.ifPresent(recentTasks -> {
+ Rect topLeftBounds = mSplitLayout.getBounds1();
+ Rect bottomRightBounds = mSplitLayout.getBounds2();
+ int mainStageTopTaskId = mMainStage.getTopVisibleChildTaskId();
+ int sideStageTopTaskId = mSideStage.getTopVisibleChildTaskId();
+ boolean sideStageTopLeft = mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT;
+ int leftTopTaskId;
+ int rightBottomTaskId;
+ if (sideStageTopLeft) {
+ leftTopTaskId = sideStageTopTaskId;
+ rightBottomTaskId = mainStageTopTaskId;
+ } else {
+ leftTopTaskId = mainStageTopTaskId;
+ rightBottomTaskId = sideStageTopTaskId;
+ }
+ StagedSplitBounds splitBounds = new StagedSplitBounds(topLeftBounds, bottomRightBounds,
+ leftTopTaskId, rightBottomTaskId);
+ if (mainStageTopTaskId != INVALID_TASK_ID && sideStageTopTaskId != INVALID_TASK_ID) {
+ // Update the pair for the top tasks
+ recentTasks.addSplitPair(mainStageTopTaskId, sideStageTopTaskId, splitBounds);
+ }
+ });
+ }
+
private void sendSplitVisibilityChanged() {
for (int i = mListeners.size() - 1; i >= 0; --i) {
final SplitScreen.SplitScreenListener l = mListeners.get(i);
@@ -697,11 +790,13 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (bothStageInvisible) {
if (mExitSplitScreenOnHide
+ // Don't dismiss staged split when both stages are not visible due to sleeping
+ // display, like the cases keyguard showing or screen off.
+ || (!mMainStage.mRootTaskInfo.isSleeping
+ && !mSideStage.mRootTaskInfo.isSleeping)) {
// Don't dismiss staged split when both stages are not visible due to sleeping display,
// like the cases keyguard showing or screen off.
- || (!mMainStage.mRootTaskInfo.isSleeping && !mSideStage.mRootTaskInfo.isSleeping)) {
- exitSplitScreen(null /* childrenToTop */,
- SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME);
+ exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RETURN_HOME);
}
} else if (mKeyguardOccluded) {
// At least one of the stages is visible while keyguard occluded. Dismiss split because
@@ -709,7 +804,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// task contains show-when-locked activity remains on top after split dismissed.
final StageTaskListener toTop =
mainStageVisible ? mMainStage : (sideStageVisible ? mSideStage : null);
- exitSplitScreen(toTop, SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED_SHOW_ON_TOP);
+ exitSplitScreen(toTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
}
mSyncQueue.runInSync(t -> {
@@ -719,7 +814,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
t.setVisibility(mSideStage.mRootLeash, bothStageVisible)
.setVisibility(mMainStage.mRootLeash, bothStageVisible);
applyDividerVisibility(t);
- applyOutlineVisibility(t);
}
});
}
@@ -741,43 +835,35 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
}
- private void applyOutlineVisibility(SurfaceControl.Transaction t) {
- final SurfaceControl outlineLeash = mSideStage.getOutlineLeash();
- if (outlineLeash == null) {
- return;
- }
-
- if (mDividerVisible) {
- t.show(outlineLeash).setLayer(outlineLeash, SPLIT_DIVIDER_LAYER);
- } else {
- t.hide(outlineLeash);
- }
- }
-
private void onStageHasChildrenChanged(StageListenerImpl stageListener) {
final boolean hasChildren = stageListener.mHasChildren;
final boolean isSideStage = stageListener == mSideStageListener;
if (!hasChildren) {
if (isSideStage && mMainStageListener.mVisible) {
// Exit to main stage if side stage no longer has children.
- exitSplitScreen(mMainStage, SPLITSCREEN_UICHANGED__EXIT_REASON__APP_FINISHED);
+ exitSplitScreen(mMainStage, EXIT_REASON_APP_FINISHED);
} else if (!isSideStage && mSideStageListener.mVisible) {
// Exit to side stage if main stage no longer has children.
- exitSplitScreen(mSideStage, SPLITSCREEN_UICHANGED__EXIT_REASON__APP_FINISHED);
+ exitSplitScreen(mSideStage, EXIT_REASON_APP_FINISHED);
}
} else if (isSideStage) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
// Make sure the main stage is active.
mMainStage.activate(getMainStageBounds(), wct, true /* reparent */);
- mSideStage.setBounds(getSideStageBounds(), wct);
- mTaskOrganizer.applyTransaction(wct);
+ mSideStage.moveToTop(getSideStageBounds(), wct);
+ mSyncQueue.queue(wct);
+ mSyncQueue.runInSync(t -> updateSurfaceBounds(mSplitLayout, t));
}
- if (!mLogger.hasStartedSession() && mMainStageListener.mHasChildren
- && mSideStageListener.mHasChildren) {
- mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
- getMainStagePosition(), mMainStage.getTopChildTaskUid(),
- getSideStagePosition(), mSideStage.getTopChildTaskUid(),
- mSplitLayout.isLandscape());
+ if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) {
+ mShouldUpdateRecents = true;
+ updateRecentTasksSplitPair();
+
+ if (!mLogger.hasStartedSession()) {
+ mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
+ getMainStagePosition(), mMainStage.getTopChildTaskUid(),
+ getSideStagePosition(), mSideStage.getTopChildTaskUid(),
+ mSplitLayout.isLandscape());
+ }
}
}
@@ -797,8 +883,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
onSnappedToDismissTransition(mainStageToTop);
return;
}
- exitSplitScreen(mainStageToTop ? mMainStage : mSideStage,
- SPLITSCREEN_UICHANGED__EXIT_REASON__DRAG_DIVIDER);
+ exitSplitScreen(mainStageToTop ? mMainStage : mSideStage, EXIT_REASON_DRAG_DIVIDER);
}
@Override
@@ -817,8 +902,11 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@Override
public void onLayoutSizeChanging(SplitLayout layout) {
- mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t));
- mSideStage.setOutlineVisibility(false);
+ mSyncQueue.runInSync(t -> {
+ updateSurfaceBounds(layout, t);
+ mMainStage.onResizing(getMainStageBounds(), t);
+ mSideStage.onResizing(getSideStageBounds(), t);
+ });
}
@Override
@@ -827,8 +915,11 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
updateWindowBounds(layout, wct);
updateUnfoldBounds();
mSyncQueue.queue(wct);
- mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t));
- mSideStage.setOutlineVisibility(true);
+ mSyncQueue.runInSync(t -> {
+ updateSurfaceBounds(layout, t);
+ mMainStage.onResized(getMainStageBounds(), t);
+ mSideStage.onResized(getSideStageBounds(), t);
+ });
mLogger.logResize(mSplitLayout.getDividerPositionAsFraction());
}
@@ -893,7 +984,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (mSplitLayout == null) {
mSplitLayout = new SplitLayout(TAG + "SplitDivider", mContext,
mDisplayAreaInfo.configuration, this, mParentContainerCallbacks,
- mDisplayImeController, mTaskOrganizer);
+ mDisplayImeController, mTaskOrganizer, false /* applyDismissingParallax */);
mDisplayInsetsController.addInsetsChangedListener(mDisplayId, mSplitLayout);
if (mMainUnfoldController != null && mSideUnfoldController != null) {
@@ -1216,18 +1307,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
null /* taskInfo */, false /* allowEnterPip */, TYPE_DOCK_DIVIDER);
}
- RemoteAnimationTarget getOutlineLegacyTarget() {
- final Rect bounds = mSideStage.mRootTaskInfo.configuration.windowConfiguration.getBounds();
- // Leverage TYPE_DOCK_DIVIDER type when wrapping outline remote animation target in order to
- // distinguish as a split auxiliary target in Launcher.
- return new RemoteAnimationTarget(-1 /* taskId */, -1 /* mode */,
- mSideStage.getOutlineLeash(), false /* isTranslucent */, null /* clipRect */,
- null /* contentInsets */, Integer.MAX_VALUE /* prefixOrderIndex */,
- new android.graphics.Point(0, 0) /* position */, bounds, bounds,
- new WindowConfiguration(), true, null /* startLeash */, null /* startBounds */,
- null /* taskInfo */, false /* allowEnterPip */, TYPE_DOCK_DIVIDER);
- }
-
@Override
public void dump(@NonNull PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
@@ -1262,7 +1341,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
/**
* Logs the exit of splitscreen.
*/
- private void logExit(int exitReason) {
+ private void logExit(@ExitReason int exitReason) {
mLogger.logExit(exitReason,
SPLIT_POSITION_UNDEFINED, 0 /* mainStageUid */,
SPLIT_POSITION_UNDEFINED, 0 /* sideStageUid */,
@@ -1273,7 +1352,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
* Logs the exit of splitscreen to a specific stage. This must be called before the exit is
* executed.
*/
- private void logExitToStage(int exitReason, boolean toMainStage) {
+ private void logExitToStage(@ExitReason int exitReason, boolean toMainStage) {
mLogger.logExit(exitReason,
toMainStage ? getMainStagePosition() : SPLIT_POSITION_UNDEFINED,
toMainStage ? mMainStage.getTopChildTaskUid() : 0 /* mainStageUid */,
@@ -1322,7 +1401,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
public void onNoLongerSupportMultiWindow() {
if (mMainStage.isActive()) {
StageCoordinator.this.exitSplitScreen(null /* childrenToTop */,
- SPLITSCREEN_UICHANGED__EXIT_REASON__APP_DOES_NOT_SUPPORT_MULTIWINDOW);
+ EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 6f1a09dc88e6..190006ec0d9b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.splitscreen;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
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;
@@ -26,6 +27,7 @@ import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIO
import android.annotation.CallSuper;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.SparseArray;
@@ -35,9 +37,11 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
+import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.SurfaceUtils;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.common.split.SplitDecorManager;
import java.io.PrintWriter;
@@ -72,25 +76,31 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
void onNoLongerSupportMultiWindow();
}
+ private final Context mContext;
private final StageListenerCallbacks mCallbacks;
private final SurfaceSession mSurfaceSession;
- protected final SyncTransactionQueue mSyncQueue;
+ private final SyncTransactionQueue mSyncQueue;
+ private final IconProvider mIconProvider;
protected ActivityManager.RunningTaskInfo mRootTaskInfo;
protected SurfaceControl mRootLeash;
protected SurfaceControl mDimLayer;
protected SparseArray<ActivityManager.RunningTaskInfo> mChildrenTaskInfo = new SparseArray<>();
private final SparseArray<SurfaceControl> mChildrenLeashes = new SparseArray<>();
+ // TODO(b/204308910): Extracts SplitDecorManager related code to common package.
+ private SplitDecorManager mSplitDecorManager;
private final StageTaskUnfoldController mStageTaskUnfoldController;
- StageTaskListener(ShellTaskOrganizer taskOrganizer, int displayId,
+ StageTaskListener(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
- SurfaceSession surfaceSession,
+ SurfaceSession surfaceSession, IconProvider iconProvider,
@Nullable StageTaskUnfoldController stageTaskUnfoldController) {
+ mContext = context;
mCallbacks = callbacks;
mSyncQueue = syncQueue;
mSurfaceSession = surfaceSession;
+ mIconProvider = iconProvider;
mStageTaskUnfoldController = stageTaskUnfoldController;
taskOrganizer.createRootTask(displayId, WINDOWING_MODE_MULTI_WINDOW, this);
}
@@ -104,6 +114,19 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
}
/**
+ * Returns the top visible child task's id.
+ */
+ int getTopVisibleChildTaskId() {
+ for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
+ final ActivityManager.RunningTaskInfo info = mChildrenTaskInfo.valueAt(i);
+ if (info.isVisible) {
+ return info.taskId;
+ }
+ }
+ return INVALID_TASK_ID;
+ }
+
+ /**
* Returns the top activity uid for the top child task.
*/
int getTopChildTaskUid() {
@@ -142,13 +165,14 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
if (mRootTaskInfo == null && !taskInfo.hasParentTask()) {
mRootLeash = leash;
mRootTaskInfo = taskInfo;
+ mSplitDecorManager = new SplitDecorManager(
+ mRootTaskInfo.configuration,
+ mIconProvider,
+ mSurfaceSession);
mCallbacks.onRootTaskAppeared();
sendStatusChanged();
- mSyncQueue.runInSync(t -> {
- t.hide(mRootLeash);
- mDimLayer =
- SurfaceUtils.makeDimLayer(t, mRootLeash, "Dim layer", mSurfaceSession);
- });
+ mSyncQueue.runInSync(t -> mDimLayer =
+ SurfaceUtils.makeDimLayer(t, mRootLeash, "Dim layer", mSurfaceSession));
} else if (taskInfo.parentTaskId == mRootTaskInfo.taskId) {
final int taskId = taskInfo.taskId;
mChildrenLeashes.put(taskId, leash);
@@ -179,6 +203,17 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
return;
}
if (mRootTaskInfo.taskId == taskInfo.taskId) {
+ // Inflates split decor view only when the root task is visible.
+ if (mRootTaskInfo.isVisible != taskInfo.isVisible) {
+ mSyncQueue.runInSync(t -> {
+ if (taskInfo.isVisible) {
+ mSplitDecorManager.inflate(mContext, mRootLeash,
+ taskInfo.configuration.windowConfiguration.getBounds());
+ } else {
+ mSplitDecorManager.release(t);
+ }
+ });
+ }
mRootTaskInfo = taskInfo;
} else if (taskInfo.parentTaskId == mRootTaskInfo.taskId) {
mChildrenTaskInfo.put(taskInfo.taskId, taskInfo);
@@ -205,8 +240,11 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
final int taskId = taskInfo.taskId;
if (mRootTaskInfo.taskId == taskId) {
mCallbacks.onRootTaskVanished();
- mSyncQueue.runInSync(t -> t.remove(mDimLayer));
mRootTaskInfo = null;
+ mSyncQueue.runInSync(t -> {
+ t.remove(mDimLayer);
+ mSplitDecorManager.release(t);
+ });
} else if (mChildrenTaskInfo.contains(taskId)) {
mChildrenTaskInfo.remove(taskId);
mChildrenLeashes.remove(taskId);
@@ -237,6 +275,18 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
}
}
+ void onResizing(Rect newBounds, SurfaceControl.Transaction t) {
+ if (mSplitDecorManager != null && mRootTaskInfo != null) {
+ mSplitDecorManager.onResizing(mRootTaskInfo, newBounds, t);
+ }
+ }
+
+ void onResized(Rect newBounds, SurfaceControl.Transaction t) {
+ if (mSplitDecorManager != null) {
+ mSplitDecorManager.onResized(newBounds, t);
+ }
+ }
+
void setBounds(Rect bounds, WindowContainerTransaction wct) {
wct.setBounds(mRootTaskInfo.token, bounds);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java
index 574e379921b1..60a6cd78c4fc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java
@@ -882,7 +882,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (mSplitLayout == null) {
mSplitLayout = new SplitLayout(TAG + "SplitDivider", mContext,
mDisplayAreaInfo.configuration, this, mParentContainerCallbacks,
- mDisplayImeController, mTaskOrganizer);
+ mDisplayImeController, mTaskOrganizer, true /* applyDismissingParallax */);
mDisplayInsetsController.addInsetsChangedListener(mDisplayId, mSplitLayout);
if (mMainUnfoldController != null && mSideUnfoldController != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
index 4e477ca104dd..003d8a3f2fef 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
@@ -18,6 +18,8 @@ package com.android.wm.shell.startingsurface;
import static android.view.Choreographer.CALLBACK_COMMIT;
import static android.view.View.GONE;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_SPLASHSCREEN_EXIT_ANIM;
+
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
@@ -42,6 +44,7 @@ import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.window.SplashScreenView;
+import com.android.internal.jank.InteractionJankMonitor;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.TransactionPool;
@@ -311,17 +314,19 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener {
@Override
public void onAnimationStart(Animator animation) {
- // ignore
+ InteractionJankMonitor.getInstance().begin(mSplashScreenView, CUJ_SPLASHSCREEN_EXIT_ANIM);
}
@Override
public void onAnimationEnd(Animator animation) {
reset();
+ InteractionJankMonitor.getInstance().end(CUJ_SPLASHSCREEN_EXIT_ANIM);
}
@Override
public void onAnimationCancel(Animator animation) {
reset();
+ InteractionJankMonitor.getInstance().cancel(CUJ_SPLASHSCREEN_EXIT_ANIM);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
index 38122ffc032b..709e2219a64e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
@@ -19,6 +19,7 @@ package com.android.wm.shell.startingsurface;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.ColorInt;
import android.annotation.NonNull;
@@ -263,11 +264,12 @@ public class SplashscreenIconDrawableFactory {
* A lightweight AdaptiveIconDrawable which support foreground to be Animatable, and keep this
* drawable masked by config_icon_mask.
*/
- private static class AnimatableIconAnimateListener extends AdaptiveForegroundDrawable
+ public static class AnimatableIconAnimateListener extends AdaptiveForegroundDrawable
implements SplashScreenView.IconAnimateListener {
private Animatable mAnimatableIcon;
private Animator mIconAnimator;
private boolean mAnimationTriggered;
+ private AnimatorListenerAdapter mJankMonitoringListener;
AnimatableIconAnimateListener(@NonNull Drawable foregroundDrawable) {
super(foregroundDrawable);
@@ -275,6 +277,11 @@ public class SplashscreenIconDrawableFactory {
}
@Override
+ public void setAnimationJankMonitoring(AnimatorListenerAdapter listener) {
+ mJankMonitoringListener = listener;
+ }
+
+ @Override
public boolean prepareAnimate(long duration, Runnable startListener) {
mAnimatableIcon = (Animatable) mForegroundDrawable;
mIconAnimator = ValueAnimator.ofInt(0, 1);
@@ -286,6 +293,9 @@ public class SplashscreenIconDrawableFactory {
startListener.run();
}
try {
+ if (mJankMonitoringListener != null) {
+ mJankMonitoringListener.onAnimationStart(animation);
+ }
mAnimatableIcon.start();
} catch (Exception ex) {
Log.e(TAG, "Error while running the splash screen animated icon", ex);
@@ -296,11 +306,17 @@ public class SplashscreenIconDrawableFactory {
@Override
public void onAnimationEnd(Animator animation) {
mAnimatableIcon.stop();
+ if (mJankMonitoringListener != null) {
+ mJankMonitoringListener.onAnimationEnd(animation);
+ }
}
@Override
public void onAnimationCancel(Animator animation) {
mAnimatableIcon.stop();
+ if (mJankMonitoringListener != null) {
+ mJankMonitoringListener.onAnimationCancel(animation);
+ }
}
@Override
@@ -314,8 +330,9 @@ public class SplashscreenIconDrawableFactory {
@Override
public void stopAnimation() {
- if (mIconAnimator != null) {
+ if (mIconAnimator != null && mIconAnimator.isRunning()) {
mIconAnimator.end();
+ mJankMonitoringListener = null;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
index a86e07a5602d..e98a3e87c0b7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -46,6 +46,7 @@ import com.android.internal.util.function.TriConsumer;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SingleInstanceRemoteListener;
import com.android.wm.shell.common.TransactionPool;
/**
@@ -237,24 +238,19 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo
@BinderThread
private static class IStartingWindowImpl extends IStartingWindow.Stub {
private StartingWindowController mController;
- private IStartingWindowListener mListener;
+ private SingleInstanceRemoteListener<StartingWindowController,
+ IStartingWindowListener> mListener;
private final TriConsumer<Integer, Integer, Integer> mStartingWindowListener =
- this::notifyIStartingWindowListener;
- private final IBinder.DeathRecipient mListenerDeathRecipient =
- new IBinder.DeathRecipient() {
- @Override
- @BinderThread
- public void binderDied() {
- final StartingWindowController controller = mController;
- controller.getRemoteCallExecutor().execute(() -> {
- mListener = null;
- controller.setStartingWindowListener(null);
- });
- }
+ (taskId, supportedType, startingWindowBackgroundColor) -> {
+ mListener.call(l -> l.onTaskLaunching(taskId, supportedType,
+ startingWindowBackgroundColor));
};
public IStartingWindowImpl(StartingWindowController controller) {
mController = controller;
+ mListener = new SingleInstanceRemoteListener<>(controller,
+ c -> c.setStartingWindowListener(mStartingWindowListener),
+ c -> c.setStartingWindowListener(null));
}
/**
@@ -268,36 +264,12 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo
public void setStartingWindowListener(IStartingWindowListener listener) {
executeRemoteCallWithTaskPermission(mController, "setStartingWindowListener",
(controller) -> {
- if (mListener != null) {
- // Reset the old death recipient
- mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
- 0 /* flags */);
- }
if (listener != null) {
- try {
- listener.asBinder().linkToDeath(mListenerDeathRecipient,
- 0 /* flags */);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to link to death");
- return;
- }
+ mListener.register(listener);
+ } else {
+ mListener.unregister();
}
- mListener = listener;
- controller.setStartingWindowListener(mStartingWindowListener);
});
}
-
- private void notifyIStartingWindowListener(int taskId, int supportedType,
- int startingWindowBackgroundColor) {
- if (mListener == null) {
- return;
- }
-
- try {
- mListener.onTaskLaunching(taskId, supportedType, startingWindowBackgroundColor);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to notify task launching", e);
- }
- }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
index 3be896e4aca3..3e2a0e635a75 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
@@ -18,9 +18,11 @@ package com.android.wm.shell.transition;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityTaskManager;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
+import android.util.Slog;
import android.view.SurfaceControl;
import android.window.IRemoteTransition;
import android.window.IRemoteTransitionFinishedCallback;
@@ -89,6 +91,13 @@ public class OneShotRemoteHandler implements Transitions.TransitionHandler {
if (mRemote.asBinder() != null) {
mRemote.asBinder().linkToDeath(remoteDied, 0 /* flags */);
}
+ try {
+ ActivityTaskManager.getService().setRunningRemoteTransitionDelegate(
+ mRemote.getAppThread());
+ } catch (SecurityException e) {
+ Slog.e(Transitions.TAG, "Unable to boost animation thread. This should only happen"
+ + " during unit tests");
+ }
mRemote.getRemoteTransition().startAnimation(transition, info, startTransaction, cb);
} catch (RemoteException e) {
Log.e(Transitions.TAG, "Error running remote transition.", e);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
index c798ace18b5f..ece9f47e8788 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
@@ -18,6 +18,7 @@ package com.android.wm.shell.transition;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityTaskManager;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArrayMap;
@@ -130,6 +131,13 @@ public class RemoteTransitionHandler implements Transitions.TransitionHandler {
};
try {
handleDeath(remote.asBinder(), finishCallback);
+ try {
+ ActivityTaskManager.getService().setRunningRemoteTransitionDelegate(
+ remote.getAppThread());
+ } catch (SecurityException e) {
+ Log.e(Transitions.TAG, "Unable to boost animation thread. This should only happen"
+ + " during unit tests");
+ }
remote.getRemoteTransition().startAnimation(transition, info, startTransaction, cb);
} catch (RemoteException e) {
Log.e(Transitions.TAG, "Error running remote transition.", e);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java
index 802d25f66340..b34049d4ec42 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java
@@ -38,11 +38,11 @@ public interface ShellTransitions {
/**
* Registers a remote transition.
*/
- void registerRemote(@NonNull TransitionFilter filter,
- @NonNull RemoteTransition remoteTransition);
+ default void registerRemote(@NonNull TransitionFilter filter,
+ @NonNull RemoteTransition remoteTransition) {}
/**
* Unregisters a remote transition.
*/
- void unregisterRemote(@NonNull RemoteTransition remoteTransition);
+ default void unregisterRemote(@NonNull RemoteTransition remoteTransition) {}
}
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 c36983189a71..804e449decf8 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
@@ -171,24 +171,6 @@ public class Transitions implements RemoteCallable<Transitions> {
}
}
- /** Create an empty/non-registering transitions object for system-ui tests. */
- @VisibleForTesting
- public static ShellTransitions createEmptyForTesting() {
- return new ShellTransitions() {
- @Override
- public void registerRemote(@androidx.annotation.NonNull TransitionFilter filter,
- @androidx.annotation.NonNull RemoteTransition remoteTransition) {
- // Do nothing
- }
-
- @Override
- public void unregisterRemote(
- @androidx.annotation.NonNull RemoteTransition remoteTransition) {
- // Do nothing
- }
- };
- }
-
/** Register this transition handler with Core */
public void register(ShellTaskOrganizer taskOrganizer) {
if (mPlayerImpl == null) return;
diff --git a/packages/SystemUI/res/values/arrays_tv.xml b/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.aidl
index 9c7707791180..15797cdb9aba 100644
--- a/packages/SystemUI/res/values/arrays_tv.xml
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.aidl
@@ -1,13 +1,11 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/**
- * Copyright (c) 2017, 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.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -15,8 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
--->
-<resources>
- <string-array name="audio_recording_disclosure_exempt_apps" translatable="false">
- </string-array>
-</resources>
+
+package com.android.wm.shell.util;
+
+parcelable GroupedRecentTaskInfo; \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java
new file mode 100644
index 000000000000..603d05d78fc0
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java
@@ -0,0 +1,96 @@
+/*
+ * 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.util;
+
+import android.app.ActivityManager;
+import android.app.WindowConfiguration;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * Simple container for recent tasks. May contain either a single or pair of tasks.
+ */
+public class GroupedRecentTaskInfo implements Parcelable {
+ public @NonNull ActivityManager.RecentTaskInfo mTaskInfo1;
+ public @Nullable ActivityManager.RecentTaskInfo mTaskInfo2;
+ public @Nullable StagedSplitBounds mStagedSplitBounds;
+
+ public GroupedRecentTaskInfo(@NonNull ActivityManager.RecentTaskInfo task1) {
+ this(task1, null, null);
+ }
+
+ public GroupedRecentTaskInfo(@NonNull ActivityManager.RecentTaskInfo task1,
+ @Nullable ActivityManager.RecentTaskInfo task2,
+ @Nullable StagedSplitBounds stagedSplitBounds) {
+ mTaskInfo1 = task1;
+ mTaskInfo2 = task2;
+ mStagedSplitBounds = stagedSplitBounds;
+ }
+
+ GroupedRecentTaskInfo(Parcel parcel) {
+ mTaskInfo1 = parcel.readTypedObject(ActivityManager.RecentTaskInfo.CREATOR);
+ mTaskInfo2 = parcel.readTypedObject(ActivityManager.RecentTaskInfo.CREATOR);
+ mStagedSplitBounds = parcel.readTypedObject(StagedSplitBounds.CREATOR);
+ }
+
+ @Override
+ public String toString() {
+ String taskString = "Task1: " + getTaskInfo(mTaskInfo1)
+ + ", Task2: " + getTaskInfo(mTaskInfo2);
+ if (mStagedSplitBounds != null) {
+ taskString += ", SplitBounds: " + mStagedSplitBounds.toString();
+ }
+ return taskString;
+ }
+
+ private String getTaskInfo(ActivityManager.RecentTaskInfo taskInfo) {
+ if (taskInfo == null) {
+ return null;
+ }
+ return "id=" + taskInfo.taskId
+ + " baseIntent=" + (taskInfo.baseIntent != null
+ ? taskInfo.baseIntent.getComponent()
+ : "null")
+ + " winMode=" + WindowConfiguration.windowingModeToString(
+ taskInfo.getWindowingMode());
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeTypedObject(mTaskInfo1, flags);
+ parcel.writeTypedObject(mTaskInfo2, flags);
+ parcel.writeTypedObject(mStagedSplitBounds, flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final @android.annotation.NonNull Creator<GroupedRecentTaskInfo> CREATOR =
+ new Creator<GroupedRecentTaskInfo>() {
+ public GroupedRecentTaskInfo createFromParcel(Parcel source) {
+ return new GroupedRecentTaskInfo(source);
+ }
+ public GroupedRecentTaskInfo[] newArray(int size) {
+ return new GroupedRecentTaskInfo[size];
+ }
+ };
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/StagedSplitBounds.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/StagedSplitBounds.java
new file mode 100644
index 000000000000..aadf792c572f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/StagedSplitBounds.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.wm.shell.util;
+
+import android.graphics.Rect;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Container of various information needed to display split screen
+ * tasks/leashes/etc in Launcher
+ */
+public class StagedSplitBounds implements Parcelable {
+ public final Rect leftTopBounds;
+ public final Rect rightBottomBounds;
+ /** This rect represents the actual gap between the two apps */
+ public final Rect visualDividerBounds;
+ // This class is orientation-agnostic, so we compute both for later use
+ public final float topTaskPercent;
+ public final float leftTaskPercent;
+ /**
+ * If {@code true}, that means at the time of creation of this object, the
+ * split-screened apps were vertically stacked. This is useful in scenarios like
+ * rotation where the bounds won't change, but this variable can indicate what orientation
+ * the bounds were originally in
+ */
+ public final boolean appsStackedVertically;
+ public final int leftTopTaskId;
+ public final int rightBottomTaskId;
+
+ public StagedSplitBounds(Rect leftTopBounds, Rect rightBottomBounds,
+ int leftTopTaskId, int rightBottomTaskId) {
+ this.leftTopBounds = leftTopBounds;
+ this.rightBottomBounds = rightBottomBounds;
+ this.leftTopTaskId = leftTopTaskId;
+ this.rightBottomTaskId = rightBottomTaskId;
+
+ if (rightBottomBounds.top > leftTopBounds.top) {
+ // vertical apps, horizontal divider
+ this.visualDividerBounds = new Rect(leftTopBounds.left, leftTopBounds.bottom,
+ leftTopBounds.right, rightBottomBounds.top);
+ appsStackedVertically = true;
+ } else {
+ // horizontal apps, vertical divider
+ this.visualDividerBounds = new Rect(leftTopBounds.right, leftTopBounds.top,
+ rightBottomBounds.left, leftTopBounds.bottom);
+ appsStackedVertically = false;
+ }
+
+ leftTaskPercent = this.leftTopBounds.width() / (float) rightBottomBounds.right;
+ topTaskPercent = this.leftTopBounds.height() / (float) rightBottomBounds.bottom;
+ }
+
+ public StagedSplitBounds(Parcel parcel) {
+ leftTopBounds = parcel.readTypedObject(Rect.CREATOR);
+ rightBottomBounds = parcel.readTypedObject(Rect.CREATOR);
+ visualDividerBounds = parcel.readTypedObject(Rect.CREATOR);
+ topTaskPercent = parcel.readFloat();
+ leftTaskPercent = parcel.readFloat();
+ appsStackedVertically = parcel.readBoolean();
+ leftTopTaskId = parcel.readInt();
+ rightBottomTaskId = parcel.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeTypedObject(leftTopBounds, flags);
+ parcel.writeTypedObject(rightBottomBounds, flags);
+ parcel.writeTypedObject(visualDividerBounds, flags);
+ parcel.writeFloat(topTaskPercent);
+ parcel.writeFloat(leftTaskPercent);
+ parcel.writeBoolean(appsStackedVertically);
+ parcel.writeInt(leftTopTaskId);
+ parcel.writeInt(rightBottomTaskId);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "LeftTop: " + leftTopBounds + ", taskId: " + leftTopTaskId + "\n"
+ + "RightBottom: " + rightBottomBounds + ", taskId: " + rightBottomTaskId + "\n"
+ + "Divider: " + visualDividerBounds + "\n"
+ + "AppsVertical? " + appsStackedVertically;
+ }
+
+ public static final Creator<StagedSplitBounds> CREATOR = new Creator<StagedSplitBounds>() {
+ @Override
+ public StagedSplitBounds createFromParcel(Parcel in) {
+ return new StagedSplitBounds(in);
+ }
+
+ @Override
+ public StagedSplitBounds[] newArray(int size) {
+ return new StagedSplitBounds[size];
+ }
+ };
+}
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 c07f0eb11510..c4be785cff19 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
@@ -78,7 +78,7 @@ fun FlickerTestParameter.appPairsPrimaryBoundsIsVisibleAtEnd(
assertLayersEnd {
val dividerRegion = layer(APP_PAIR_SPLIT_DIVIDER_COMPONENT).visibleRegion.region
visibleRegion(primaryComponent)
- .coversExactly(getPrimaryRegion(dividerRegion, rotation))
+ .overlaps(getPrimaryRegion(dividerRegion, rotation))
}
}
@@ -89,7 +89,7 @@ fun FlickerTestParameter.dockedStackPrimaryBoundsIsVisibleAtEnd(
assertLayersEnd {
val dividerRegion = layer(DOCKED_STACK_DIVIDER_COMPONENT).visibleRegion.region
visibleRegion(primaryComponent)
- .coversExactly(getPrimaryRegion(dividerRegion, rotation))
+ .overlaps(getPrimaryRegion(dividerRegion, rotation))
}
}
@@ -100,7 +100,7 @@ fun FlickerTestParameter.appPairsSecondaryBoundsIsVisibleAtEnd(
assertLayersEnd {
val dividerRegion = layer(APP_PAIR_SPLIT_DIVIDER_COMPONENT).visibleRegion.region
visibleRegion(secondaryComponent)
- .coversExactly(getSecondaryRegion(dividerRegion, rotation))
+ .overlaps(getSecondaryRegion(dividerRegion, rotation))
}
}
@@ -111,7 +111,7 @@ fun FlickerTestParameter.dockedStackSecondaryBoundsIsVisibleAtEnd(
assertLayersEnd {
val dividerRegion = layer(DOCKED_STACK_DIVIDER_COMPONENT).visibleRegion.region
visibleRegion(secondaryComponent)
- .coversExactly(getSecondaryRegion(dividerRegion, rotation))
+ .overlaps(getSecondaryRegion(dividerRegion, rotation))
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index d5acbbcf7d2c..1fcbf14fb732 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -65,6 +65,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.Optional;
/**
* Tests for the shell task organizer.
@@ -131,7 +132,7 @@ public class ShellTaskOrganizerTests {
.when(mTaskOrganizerController).registerTaskOrganizer(any());
} catch (RemoteException e) {}
mOrganizer = spy(new ShellTaskOrganizer(mTaskOrganizerController, mTestExecutor, mContext,
- mSizeCompatUI));
+ mSizeCompatUI, Optional.empty()));
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java
index 5bdf831a81f4..6080f3ae78e8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java
@@ -26,6 +26,7 @@ import androidx.test.InstrumentationRegistry;
import org.junit.After;
import org.junit.Before;
+import org.mockito.MockitoAnnotations;
/**
* Base class that does shell test case setup.
@@ -36,6 +37,7 @@ public abstract class ShellTestCase {
@Before
public void shellSetup() {
+ MockitoAnnotations.initMocks(this);
final Context context =
InstrumentationRegistry.getInstrumentation().getTargetContext();
final DisplayManager dm = context.getSystemService(DisplayManager.class);
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 b4caeb5de4ec..73eebad040d8 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
@@ -68,7 +68,8 @@ public class SplitLayoutTests extends ShellTestCase {
mSplitLayoutHandler,
mCallbacks,
mDisplayImeController,
- mTaskOrganizer));
+ mTaskOrganizer,
+ false /* applyDismissingParallax */));
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/fullscreen/FullscreenTaskListenerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/fullscreen/FullscreenTaskListenerTest.java
index d6f7e54ae369..9cbdf1e2dbb6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/fullscreen/FullscreenTaskListenerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/fullscreen/FullscreenTaskListenerTest.java
@@ -35,6 +35,7 @@ import android.view.SurfaceControl;
import androidx.test.filters.SmallTest;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.recents.RecentTasksController;
import org.junit.Before;
import org.junit.Test;
@@ -52,6 +53,8 @@ public class FullscreenTaskListenerTest {
@Mock
private FullscreenUnfoldController mUnfoldController;
@Mock
+ private RecentTasksController mRecentTasksController;
+ @Mock
private SurfaceControl mSurfaceControl;
private Optional<FullscreenUnfoldController> mFullscreenUnfoldController;
@@ -62,7 +65,8 @@ public class FullscreenTaskListenerTest {
public void setup() {
MockitoAnnotations.initMocks(this);
mFullscreenUnfoldController = Optional.of(mUnfoldController);
- mListener = new FullscreenTaskListener(mSyncQueue, mFullscreenUnfoldController);
+ mListener = new FullscreenTaskListener(mSyncQueue, mFullscreenUnfoldController,
+ Optional.empty());
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 0270093da938..0172cf324eea 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -50,6 +50,7 @@ import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.pip.phone.PhonePipMenuController;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import org.junit.Before;
import org.junit.Test;
@@ -75,7 +76,8 @@ public class PipTaskOrganizerTest extends ShellTestCase {
@Mock private PipTransitionController mMockPipTransitionController;
@Mock private PipSurfaceTransactionHelper mMockPipSurfaceTransactionHelper;
@Mock private PipUiEventLogger mMockPipUiEventLogger;
- @Mock private Optional<LegacySplitScreenController> mMockOptionalSplitScreen;
+ @Mock private Optional<LegacySplitScreenController> mMockOptionalLegacySplitScreen;
+ @Mock private Optional<SplitScreenController> mMockOptionalSplitScreen;
@Mock private ShellTaskOrganizer mMockShellTaskOrganizer;
private TestShellExecutor mMainExecutor;
private PipBoundsState mPipBoundsState;
@@ -99,8 +101,9 @@ public class PipTaskOrganizerTest extends ShellTestCase {
mMockSyncTransactionQueue, mPipTransitionState, mPipBoundsState,
mPipBoundsAlgorithm, mMockPhonePipMenuController,
mMockPipAnimationController, mMockPipSurfaceTransactionHelper,
- mMockPipTransitionController, mMockOptionalSplitScreen, mMockDisplayController,
- mMockPipUiEventLogger, mMockShellTaskOrganizer, mMainExecutor));
+ mMockPipTransitionController, mMockOptionalLegacySplitScreen,
+ mMockOptionalSplitScreen, mMockDisplayController, mMockPipUiEventLogger,
+ mMockShellTaskOrganizer, mMainExecutor));
mMainExecutor.flushAll();
preparePipTaskOrg();
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 935f6695538d..c2f58b8b6266 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -191,7 +191,7 @@ public class PipControllerTest extends ShellTestCase {
mPipController.mDisplaysChangedListener.onDisplayConfigurationChanged(
displayId, new Configuration());
- verify(mMockPipMotionHelper).movePip(any(Rect.class));
+ verify(mMockPipMotionHelper).animateResizedBounds(any(Rect.class));
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
new file mode 100644
index 000000000000..19a5417aace6
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -0,0 +1,232 @@
+/*
+ * 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.recents;
+
+import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import static java.lang.Integer.MAX_VALUE;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.graphics.Rect;
+import android.view.SurfaceControl;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.TestShellExecutor;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.util.GroupedRecentTaskInfo;
+import com.android.wm.shell.util.StagedSplitBounds;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Optional;
+
+/**
+ * Tests for {@link RecentTasksController}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class RecentTasksControllerTest extends ShellTestCase {
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private TaskStackListenerImpl mTaskStackListener;
+
+ private ShellTaskOrganizer mShellTaskOrganizer;
+ private RecentTasksController mRecentTasksController;
+ private ShellExecutor mMainExecutor;
+
+ @Before
+ public void setUp() {
+ mMainExecutor = new TestShellExecutor();
+ mRecentTasksController = spy(new RecentTasksController(mContext, mTaskStackListener,
+ mMainExecutor));
+ mShellTaskOrganizer = new ShellTaskOrganizer(mMainExecutor, mContext,
+ null /* sizeCompatUI */, Optional.of(mRecentTasksController));
+ }
+
+ @Test
+ public void testGetRecentTasks() {
+ ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
+ ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
+ ActivityManager.RecentTaskInfo t3 = makeTaskInfo(3);
+ setRawList(t1, t2, t3);
+
+ ArrayList<GroupedRecentTaskInfo> recentTasks = mRecentTasksController.getRecentTasks(
+ MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0);
+ assertGroupedTasksListEquals(recentTasks,
+ t1.taskId, -1,
+ t2.taskId, -1,
+ t3.taskId, -1);
+ }
+
+ @Test
+ public void testGetRecentTasks_withPairs() {
+ ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
+ ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
+ ActivityManager.RecentTaskInfo t3 = makeTaskInfo(3);
+ ActivityManager.RecentTaskInfo t4 = makeTaskInfo(4);
+ ActivityManager.RecentTaskInfo t5 = makeTaskInfo(5);
+ ActivityManager.RecentTaskInfo t6 = makeTaskInfo(6);
+ setRawList(t1, t2, t3, t4, t5, t6);
+
+ // Mark a couple pairs [t2, t4], [t3, t5]
+ StagedSplitBounds pair1Bounds = new StagedSplitBounds(new Rect(), new Rect(), 2, 4);
+ StagedSplitBounds pair2Bounds = new StagedSplitBounds(new Rect(), new Rect(), 3, 5);
+
+ mRecentTasksController.addSplitPair(t2.taskId, t4.taskId, pair1Bounds);
+ mRecentTasksController.addSplitPair(t3.taskId, t5.taskId, pair2Bounds);
+
+ ArrayList<GroupedRecentTaskInfo> recentTasks = mRecentTasksController.getRecentTasks(
+ MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0);
+ assertGroupedTasksListEquals(recentTasks,
+ t1.taskId, -1,
+ t2.taskId, t4.taskId,
+ t3.taskId, t5.taskId,
+ t6.taskId, -1);
+ }
+
+ @Test
+ public void testRemovedTaskRemovesSplit() {
+ ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
+ ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
+ ActivityManager.RecentTaskInfo t3 = makeTaskInfo(3);
+ setRawList(t1, t2, t3);
+
+ // Add a pair
+ StagedSplitBounds pair1Bounds = new StagedSplitBounds(new Rect(), new Rect(), 2, 3);
+ mRecentTasksController.addSplitPair(t2.taskId, t3.taskId, pair1Bounds);
+ reset(mRecentTasksController);
+
+ // Remove one of the tasks and ensure the pair is removed
+ SurfaceControl mockLeash = mock(SurfaceControl.class);
+ ActivityManager.RunningTaskInfo rt2 = makeRunningTaskInfo(2);
+ mShellTaskOrganizer.onTaskAppeared(rt2, mockLeash);
+ mShellTaskOrganizer.onTaskVanished(rt2);
+
+ verify(mRecentTasksController).removeSplitPair(t2.taskId);
+ }
+
+ @Test
+ public void testTaskWindowingModeChangedNotifiesChange() {
+ ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
+ setRawList(t1);
+
+ // Remove one of the tasks and ensure the pair is removed
+ SurfaceControl mockLeash = mock(SurfaceControl.class);
+ ActivityManager.RunningTaskInfo rt2Fullscreen = makeRunningTaskInfo(2);
+ rt2Fullscreen.configuration.windowConfiguration.setWindowingMode(
+ WINDOWING_MODE_FULLSCREEN);
+ mShellTaskOrganizer.onTaskAppeared(rt2Fullscreen, mockLeash);
+
+ // Change the windowing mode and ensure the recent tasks change is notified
+ ActivityManager.RunningTaskInfo rt2MultiWIndow = makeRunningTaskInfo(2);
+ rt2MultiWIndow.configuration.windowConfiguration.setWindowingMode(
+ WINDOWING_MODE_MULTI_WINDOW);
+ mShellTaskOrganizer.onTaskInfoChanged(rt2MultiWIndow);
+
+ verify(mRecentTasksController).notifyRecentTasksChanged();
+ }
+
+ /**
+ * Helper to create a task with a given task id.
+ */
+ private ActivityManager.RecentTaskInfo makeTaskInfo(int taskId) {
+ ActivityManager.RecentTaskInfo info = new ActivityManager.RecentTaskInfo();
+ info.taskId = taskId;
+ return info;
+ }
+
+ /**
+ * Helper to create a running task with a given task id.
+ */
+ private ActivityManager.RunningTaskInfo makeRunningTaskInfo(int taskId) {
+ ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
+ info.taskId = taskId;
+ return info;
+ }
+
+ /**
+ * Helper to set the raw task list on the controller.
+ */
+ private ArrayList<ActivityManager.RecentTaskInfo> setRawList(
+ ActivityManager.RecentTaskInfo... tasks) {
+ ArrayList<ActivityManager.RecentTaskInfo> rawList = new ArrayList<>();
+ for (ActivityManager.RecentTaskInfo task : tasks) {
+ rawList.add(task);
+ }
+ doReturn(rawList).when(mRecentTasksController).getRawRecentTasks(anyInt(), anyInt(),
+ anyInt());
+ return rawList;
+ }
+
+ /**
+ * Asserts that the recent tasks matches the given task ids.
+ * @param expectedTaskIds list of task ids that map to the flattened task ids of the tasks in
+ * the grouped task list
+ */
+ private void assertGroupedTasksListEquals(ArrayList<GroupedRecentTaskInfo> recentTasks,
+ int... expectedTaskIds) {
+ int[] flattenedTaskIds = new int[recentTasks.size() * 2];
+ for (int i = 0; i < recentTasks.size(); i++) {
+ GroupedRecentTaskInfo pair = recentTasks.get(i);
+ int taskId1 = pair.mTaskInfo1.taskId;
+ flattenedTaskIds[2 * i] = taskId1;
+ flattenedTaskIds[2 * i + 1] = pair.mTaskInfo2 != null
+ ? pair.mTaskInfo2.taskId
+ : -1;
+
+ if (pair.mTaskInfo2 != null) {
+ assertNotNull(pair.mStagedSplitBounds);
+ int leftTopTaskId = pair.mStagedSplitBounds.leftTopTaskId;
+ int bottomRightTaskId = pair.mStagedSplitBounds.rightBottomTaskId;
+ // Unclear if pairs are ordered by split position, most likely not.
+ assertTrue(leftTopTaskId == taskId1 || leftTopTaskId == pair.mTaskInfo2.taskId);
+ assertTrue(bottomRightTaskId == taskId1
+ || bottomRightTaskId == pair.mTaskInfo2.taskId);
+ } else {
+ assertNull(pair.mStagedSplitBounds);
+ }
+ }
+ assertTrue("Expected: " + Arrays.toString(expectedTaskIds)
+ + " Received: " + Arrays.toString(flattenedTaskIds),
+ Arrays.equals(flattenedTaskIds, expectedTaskIds));
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/StagedSplitBoundsTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/StagedSplitBoundsTest.java
new file mode 100644
index 000000000000..ad73c56950bd
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/StagedSplitBoundsTest.java
@@ -0,0 +1,94 @@
+package com.android.wm.shell.recents;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.Rect;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.wm.shell.util.StagedSplitBounds;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class StagedSplitBoundsTest {
+ private static final int DEVICE_WIDTH = 100;
+ private static final int DEVICE_LENGTH = 200;
+ private static final int DIVIDER_SIZE = 20;
+ private static final int TASK_ID_1 = 4;
+ private static final int TASK_ID_2 = 9;
+
+ // Bounds in screen space
+ private final Rect mTopRect = new Rect();
+ private final Rect mBottomRect = new Rect();
+ private final Rect mLeftRect = new Rect();
+ private final Rect mRightRect = new Rect();
+
+ @Before
+ public void setup() {
+ mTopRect.set(0, 0, DEVICE_WIDTH, DEVICE_LENGTH / 2 - DIVIDER_SIZE / 2);
+ mBottomRect.set(0, DEVICE_LENGTH / 2 + DIVIDER_SIZE / 2,
+ DEVICE_WIDTH, DEVICE_LENGTH);
+ mLeftRect.set(0, 0, DEVICE_WIDTH / 2 - DIVIDER_SIZE / 2, DEVICE_LENGTH);
+ mRightRect.set(DEVICE_WIDTH / 2 + DIVIDER_SIZE / 2, 0,
+ DEVICE_WIDTH, DEVICE_LENGTH);
+ }
+
+ @Test
+ public void testVerticalStacked() {
+ StagedSplitBounds ssb = new StagedSplitBounds(mTopRect, mBottomRect,
+ TASK_ID_1, TASK_ID_2);
+ assertTrue(ssb.appsStackedVertically);
+ }
+
+ @Test
+ public void testHorizontalStacked() {
+ StagedSplitBounds ssb = new StagedSplitBounds(mLeftRect, mRightRect,
+ TASK_ID_1, TASK_ID_2);
+ assertFalse(ssb.appsStackedVertically);
+ }
+
+ @Test
+ public void testHorizontalDividerBounds() {
+ StagedSplitBounds ssb = new StagedSplitBounds(mTopRect, mBottomRect,
+ TASK_ID_1, TASK_ID_2);
+ Rect dividerBounds = ssb.visualDividerBounds;
+ assertEquals(0, dividerBounds.left);
+ assertEquals(DEVICE_LENGTH / 2 - DIVIDER_SIZE / 2, dividerBounds.top);
+ assertEquals(DEVICE_WIDTH, dividerBounds.right);
+ assertEquals(DEVICE_LENGTH / 2 + DIVIDER_SIZE / 2, dividerBounds.bottom);
+ }
+
+ @Test
+ public void testVerticalDividerBounds() {
+ StagedSplitBounds ssb = new StagedSplitBounds(mLeftRect, mRightRect,
+ TASK_ID_1, TASK_ID_2);
+ Rect dividerBounds = ssb.visualDividerBounds;
+ assertEquals(DEVICE_WIDTH / 2 - DIVIDER_SIZE / 2, dividerBounds.left);
+ assertEquals(0, dividerBounds.top);
+ assertEquals(DEVICE_WIDTH / 2 + DIVIDER_SIZE / 2, dividerBounds.right);
+ assertEquals(DEVICE_LENGTH, dividerBounds.bottom);
+ }
+
+ @Test
+ public void testEqualVerticalTaskPercent() {
+ StagedSplitBounds ssb = new StagedSplitBounds(mTopRect, mBottomRect,
+ TASK_ID_1, TASK_ID_2);
+ float topPercentSpaceTaken = (float) (DEVICE_LENGTH / 2 - DIVIDER_SIZE / 2) / DEVICE_LENGTH;
+ assertEquals(topPercentSpaceTaken, ssb.topTaskPercent, 0.01);
+ }
+
+ @Test
+ public void testEqualHorizontalTaskPercent() {
+ StagedSplitBounds ssb = new StagedSplitBounds(mLeftRect, mRightRect,
+ TASK_ID_1, TASK_ID_2);
+ float leftPercentSpaceTaken = (float) (DEVICE_WIDTH / 2 - DIVIDER_SIZE / 2) / DEVICE_WIDTH;
+ assertEquals(leftPercentSpaceTaken, ssb.leftTaskPercent, 0.01);
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java
index 10fd7d705967..3a14a336190d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java
@@ -24,7 +24,7 @@ import static org.mockito.Mockito.verify;
import android.content.res.Configuration;
import android.testing.AndroidTestingRunner;
import android.view.LayoutInflater;
-import android.widget.Button;
+import android.widget.LinearLayout;
import androidx.test.filters.SmallTest;
@@ -77,8 +77,8 @@ public class SizeCompatHintPopupTest extends ShellTestCase {
public void testOnClick() {
doNothing().when(mLayout).dismissHint();
- final Button button = mHint.findViewById(R.id.got_it);
- button.performClick();
+ final LinearLayout hintPopup = mHint.findViewById(R.id.size_compat_hint_popup);
+ hintPopup.performClick();
verify(mLayout).dismissHint();
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java
index 8839f58ea889..d12cf5c3518a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java
@@ -16,11 +16,14 @@
package com.android.wm.shell.sizecompatui;
+import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -28,6 +31,8 @@ import static org.mockito.Mockito.verify;
import android.content.Context;
import android.content.res.Configuration;
import android.testing.AndroidTestingRunner;
+import android.view.InsetsSource;
+import android.view.InsetsState;
import androidx.test.filters.SmallTest;
@@ -35,12 +40,16 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.DisplayInsetsController.OnInsetsChangedListener;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
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;
@@ -58,12 +67,16 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
private SizeCompatUIController mController;
private @Mock DisplayController mMockDisplayController;
+ private @Mock DisplayInsetsController mMockDisplayInsetsController;
private @Mock DisplayLayout mMockDisplayLayout;
private @Mock DisplayImeController mMockImeController;
private @Mock ShellTaskOrganizer.TaskListener mMockTaskListener;
private @Mock SyncTransactionQueue mMockSyncQueue;
private @Mock SizeCompatUILayout mMockLayout;
+ @Captor
+ ArgumentCaptor<OnInsetsChangedListener> mOnInsetsChangedListenerCaptor;
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -72,7 +85,7 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
doReturn(DISPLAY_ID).when(mMockLayout).getDisplayId();
doReturn(TASK_ID).when(mMockLayout).getTaskId();
mController = new SizeCompatUIController(mContext, mMockDisplayController,
- mMockImeController, mMockSyncQueue) {
+ mMockDisplayInsetsController, mMockImeController, mMockSyncQueue) {
@Override
SizeCompatUILayout createLayout(Context context, int displayId, int taskId,
Configuration taskConfig, ShellTaskOrganizer.TaskListener taskListener) {
@@ -114,7 +127,17 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
}
@Test
+ public void testOnDisplayAdded() {
+ mController.onDisplayAdded(DISPLAY_ID);
+ mController.onDisplayAdded(DISPLAY_ID + 1);
+
+ verify(mMockDisplayInsetsController).addInsetsChangedListener(eq(DISPLAY_ID), any());
+ verify(mMockDisplayInsetsController).addInsetsChangedListener(eq(DISPLAY_ID + 1), any());
+ }
+
+ @Test
public void testOnDisplayRemoved() {
+ mController.onDisplayAdded(DISPLAY_ID);
final Configuration taskConfig = new Configuration();
mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig,
mMockTaskListener);
@@ -122,9 +145,12 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
mController.onDisplayRemoved(DISPLAY_ID + 1);
verify(mMockLayout, never()).release();
+ verify(mMockDisplayInsetsController, never()).removeInsetsChangedListener(eq(DISPLAY_ID),
+ any());
mController.onDisplayRemoved(DISPLAY_ID);
+ verify(mMockDisplayInsetsController).removeInsetsChangedListener(eq(DISPLAY_ID), any());
verify(mMockLayout).release();
}
@@ -145,6 +171,29 @@ public class SizeCompatUIControllerTest extends ShellTestCase {
}
@Test
+ public void testInsetsChanged() {
+ mController.onDisplayAdded(DISPLAY_ID);
+ final Configuration taskConfig = new Configuration();
+ mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig,
+ mMockTaskListener);
+ InsetsState insetsState = new InsetsState();
+ InsetsSource insetsSource = new InsetsSource(ITYPE_EXTRA_NAVIGATION_BAR);
+ insetsSource.setFrame(0, 0, 1000, 1000);
+ insetsState.addSource(insetsSource);
+
+ verify(mMockDisplayInsetsController).addInsetsChangedListener(eq(DISPLAY_ID),
+ mOnInsetsChangedListenerCaptor.capture());
+ mOnInsetsChangedListenerCaptor.getValue().insetsChanged(insetsState);
+
+ verify(mMockLayout).updateDisplayLayout(mMockDisplayLayout);
+
+ // No update if the insets state is the same.
+ clearInvocations(mMockLayout);
+ mOnInsetsChangedListenerCaptor.getValue().insetsChanged(new InsetsState(insetsState));
+ verify(mMockLayout, never()).updateDisplayLayout(mMockDisplayLayout);
+ }
+
+ @Test
public void testChangeButtonVisibilityOnImeShowHide() {
final Configuration taskConfig = new Configuration();
mController.onSizeCompatInfoChanged(DISPLAY_ID, TASK_ID, taskConfig,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java
index ee4c81547bbd..2ba603c8eda8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java
@@ -16,6 +16,8 @@
package com.android.wm.shell.sizecompatui;
+import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static org.junit.Assert.assertFalse;
@@ -33,6 +35,8 @@ import android.content.res.Configuration;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
import android.view.DisplayInfo;
+import android.view.InsetsSource;
+import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.View;
@@ -77,7 +81,7 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
mTaskConfig = new Configuration();
mLayout = new SizeCompatUILayout(mSyncTransactionQueue, mCallback, mContext,
- new Configuration(), TASK_ID, mTaskListener, mDisplayLayout,
+ new Configuration(), TASK_ID, mTaskListener, new DisplayLayout(),
false /* hasShownHint */);
spyOn(mLayout);
@@ -176,7 +180,7 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
displayInfo.logicalWidth = 1000;
displayInfo.logicalHeight = 2000;
final DisplayLayout displayLayout1 = new DisplayLayout(displayInfo,
- mContext.getResources(), false, false);
+ mContext.getResources(), /* hasNavigationBar= */ false, /* hasStatusBar= */ false);
mLayout.updateDisplayLayout(displayLayout1);
verify(mLayout).updateButtonSurfacePosition();
@@ -185,13 +189,37 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
// No update if the display bounds is the same.
clearInvocations(mLayout);
final DisplayLayout displayLayout2 = new DisplayLayout(displayInfo,
- mContext.getResources(), false, false);
+ mContext.getResources(), /* hasNavigationBar= */ false, /* hasStatusBar= */ false);
mLayout.updateDisplayLayout(displayLayout2);
verify(mLayout, never()).updateButtonSurfacePosition();
verify(mLayout, never()).updateHintSurfacePosition();
}
@Test
+ public void testUpdateDisplayLayoutInsets() {
+ final DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.logicalWidth = 1000;
+ displayInfo.logicalHeight = 2000;
+ final DisplayLayout displayLayout = new DisplayLayout(displayInfo,
+ mContext.getResources(), /* hasNavigationBar= */ true, /* hasStatusBar= */ false);
+
+ mLayout.updateDisplayLayout(displayLayout);
+ verify(mLayout).updateButtonSurfacePosition();
+ verify(mLayout).updateHintSurfacePosition();
+
+ // Update if the insets change on the existing display layout
+ clearInvocations(mLayout);
+ InsetsState insetsState = new InsetsState();
+ InsetsSource insetsSource = new InsetsSource(ITYPE_EXTRA_NAVIGATION_BAR);
+ insetsSource.setFrame(0, 0, 1000, 1000);
+ insetsState.addSource(insetsSource);
+ displayLayout.setInsets(mContext.getResources(), insetsState);
+ mLayout.updateDisplayLayout(displayLayout);
+ verify(mLayout).updateButtonSurfacePosition();
+ verify(mLayout).updateHintSurfacePosition();
+ }
+
+ @Test
public void testUpdateImeVisibility() {
// Create button if it is not created.
mLayout.mButton = null;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java
index 2bcc45e2587d..c9720671f49c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java
@@ -25,10 +25,13 @@ import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.window.WindowContainerTransaction;
+import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
import com.android.wm.shell.common.SyncTransactionQueue;
@@ -41,22 +44,24 @@ import org.mockito.MockitoAnnotations;
/** Tests for {@link MainStage} */
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class MainStageTests {
+public class MainStageTests extends ShellTestCase {
@Mock private ShellTaskOrganizer mTaskOrganizer;
@Mock private StageTaskListener.StageListenerCallbacks mCallbacks;
@Mock private SyncTransactionQueue mSyncQueue;
@Mock private ActivityManager.RunningTaskInfo mRootTaskInfo;
@Mock private SurfaceControl mRootLeash;
+ @Mock private IconProvider mIconProvider;
private WindowContainerTransaction mWct = new WindowContainerTransaction();
private SurfaceSession mSurfaceSession = new SurfaceSession();
private MainStage mMainStage;
@Before
+ @UiThreadTest
public void setup() {
MockitoAnnotations.initMocks(this);
mRootTaskInfo = new TestRunningTaskInfoBuilder().build();
- mMainStage = new MainStage(mTaskOrganizer, DEFAULT_DISPLAY, mCallbacks, mSyncQueue,
- mSurfaceSession, null);
+ mMainStage = new MainStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mCallbacks,
+ mSyncQueue, mSurfaceSession, mIconProvider, null);
mMainStage.onTaskAppeared(mRootTaskInfo, mRootLeash);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java
index 838aa811bb87..a31aa58bdc26 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java
@@ -33,6 +33,7 @@ import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
@@ -54,6 +55,7 @@ public class SideStageTests extends ShellTestCase {
@Mock private SyncTransactionQueue mSyncQueue;
@Mock private ActivityManager.RunningTaskInfo mRootTask;
@Mock private SurfaceControl mRootLeash;
+ @Mock private IconProvider mIconProvider;
@Spy private WindowContainerTransaction mWct;
private SurfaceSession mSurfaceSession = new SurfaceSession();
private SideStage mSideStage;
@@ -64,7 +66,7 @@ public class SideStageTests extends ShellTestCase {
MockitoAnnotations.initMocks(this);
mRootTask = new TestRunningTaskInfoBuilder().build();
mSideStage = new SideStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mCallbacks,
- mSyncQueue, mSurfaceSession, null);
+ mSyncQueue, mSurfaceSession, mIconProvider, null);
mSideStage.onTaskAppeared(mRootTask, mRootLeash);
}
@@ -72,7 +74,7 @@ public class SideStageTests extends ShellTestCase {
public void testAddTask() {
final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
- mSideStage.addTask(task, mRootTask.configuration.windowConfiguration.getBounds(), mWct);
+ mSideStage.addTask(task, mWct);
verify(mWct).reparent(eq(task.token), eq(mRootTask.token), eq(true));
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
index f90af239db01..aab1e3a99c98 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
@@ -36,6 +36,7 @@ import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitLayout;
+import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.transition.Transitions;
import java.util.Optional;
@@ -72,10 +73,11 @@ public class SplitTestUtils {
DisplayInsetsController insetsController, SplitLayout splitLayout,
Transitions transitions, TransactionPool transactionPool,
SplitscreenEventLogger logger,
+ Optional<RecentTasksController> recentTasks,
Provider<Optional<StageTaskUnfoldController>> unfoldController) {
super(context, displayId, syncQueue, rootTDAOrganizer, taskOrganizer, mainStage,
sideStage, imeController, insetsController, splitLayout, transitions,
- transactionPool, logger, unfoldController);
+ transactionPool, logger, recentTasks, unfoldController);
// Prepare default TaskDisplayArea for testing.
mDisplayAreaInfo = new DisplayAreaInfo(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index 05496b059030..1eae625233a0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -55,6 +55,7 @@ import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
@@ -65,6 +66,7 @@ import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitLayout;
+import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.transition.Transitions;
import org.junit.Before;
@@ -89,6 +91,7 @@ public class SplitTransitionTests extends ShellTestCase {
@Mock private Transitions mTransitions;
@Mock private SurfaceSession mSurfaceSession;
@Mock private SplitscreenEventLogger mLogger;
+ @Mock private IconProvider mIconProvider;
private SplitLayout mSplitLayout;
private MainStage mMainStage;
private SideStage mSideStage;
@@ -107,17 +110,18 @@ public class SplitTransitionTests extends ShellTestCase {
doReturn(mockExecutor).when(mTransitions).getAnimExecutor();
doReturn(mock(SurfaceControl.Transaction.class)).when(mTransactionPool).acquire();
mSplitLayout = SplitTestUtils.createMockSplitLayout();
- mMainStage = new MainStage(mTaskOrganizer, DEFAULT_DISPLAY, mock(
- StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession, null);
+ mMainStage = new MainStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
+ StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession,
+ mIconProvider, null);
mMainStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
mSideStage = new SideStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
- StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession, null);
+ StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession,
+ mIconProvider, null);
mSideStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage,
mDisplayImeController, mDisplayInsetsController, mSplitLayout, mTransitions,
- mTransactionPool,
- mLogger, Optional::empty);
+ mTransactionPool, mLogger, Optional.empty(), Optional::empty);
mSplitScreenTransitions = mStageCoordinator.getSplitTransitions();
doAnswer((Answer<IBinder>) invocation -> mock(IBinder.class))
.when(mTransitions).startTransition(anyInt(), any(), any());
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index cd29220bb96a..ad65c046be65 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -22,6 +22,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_RETURN_HOME;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
@@ -48,6 +49,7 @@ import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitLayout;
+import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.transition.Transitions;
import org.junit.Before;
@@ -113,10 +115,7 @@ public class StageCoordinatorTests extends ShellTestCase {
mStageCoordinator.moveToSideStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT);
- verify(mMainStage).activate(any(Rect.class), any(WindowContainerTransaction.class),
- eq(true /* includingTopTask */));
- verify(mSideStage).addTask(eq(task), any(Rect.class),
- any(WindowContainerTransaction.class));
+ verify(mSideStage).addTask(eq(task), any(WindowContainerTransaction.class));
}
@Test
@@ -164,19 +163,19 @@ public class StageCoordinatorTests extends ShellTestCase {
@Test
public void testExitSplitScreen() {
- mStageCoordinator.exitSplitScreen(INVALID_TASK_ID,
- SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME);
+ when(mMainStage.isActive()).thenReturn(true);
+ mStageCoordinator.exitSplitScreen(INVALID_TASK_ID, EXIT_REASON_RETURN_HOME);
verify(mSideStage).removeAllTasks(any(WindowContainerTransaction.class), eq(false));
verify(mMainStage).deactivate(any(WindowContainerTransaction.class), eq(false));
}
@Test
public void testExitSplitScreenToMainStage() {
+ when(mMainStage.isActive()).thenReturn(true);
final int testTaskId = 12345;
when(mMainStage.containsTask(eq(testTaskId))).thenReturn(true);
when(mSideStage.containsTask(eq(testTaskId))).thenReturn(false);
- mStageCoordinator.exitSplitScreen(testTaskId,
- SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME);
+ mStageCoordinator.exitSplitScreen(testTaskId, EXIT_REASON_RETURN_HOME);
verify(mMainStage).reorderChild(eq(testTaskId), eq(true),
any(WindowContainerTransaction.class));
verify(mSideStage).removeAllTasks(any(WindowContainerTransaction.class), eq(false));
@@ -185,11 +184,11 @@ public class StageCoordinatorTests extends ShellTestCase {
@Test
public void testExitSplitScreenToSideStage() {
+ when(mMainStage.isActive()).thenReturn(true);
final int testTaskId = 12345;
when(mMainStage.containsTask(eq(testTaskId))).thenReturn(false);
when(mSideStage.containsTask(eq(testTaskId))).thenReturn(true);
- mStageCoordinator.exitSplitScreen(testTaskId,
- SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME);
+ mStageCoordinator.exitSplitScreen(testTaskId, EXIT_REASON_RETURN_HOME);
verify(mSideStage).reorderChild(eq(testTaskId), eq(true),
any(WindowContainerTransaction.class));
verify(mSideStage).removeAllTasks(any(WindowContainerTransaction.class), eq(true));
@@ -200,7 +199,8 @@ public class StageCoordinatorTests extends ShellTestCase {
return new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage,
mDisplayImeController, mDisplayInsetsController, splitLayout,
- mTransitions, mTransactionPool, mLogger, new UnfoldControllerProvider());
+ mTransitions, mTransactionPool, mLogger, Optional.empty(),
+ new UnfoldControllerProvider());
}
private class UnfoldControllerProvider implements
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
index 3ed72e2c079e..53d5076f5835 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
@@ -35,10 +35,13 @@ import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.window.WindowContainerTransaction;
+import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
import com.android.wm.shell.common.SyncTransactionQueue;
@@ -57,7 +60,7 @@ import org.mockito.MockitoAnnotations;
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
-public final class StageTaskListenerTests {
+public final class StageTaskListenerTests extends ShellTestCase {
private static final boolean ENABLE_SHELL_TRANSITIONS =
SystemProperties.getBoolean("persist.debug.shell_transit", false);
@@ -68,6 +71,8 @@ public final class StageTaskListenerTests {
@Mock
private SyncTransactionQueue mSyncQueue;
@Mock
+ private IconProvider mIconProvider;
+ @Mock
private StageTaskUnfoldController mStageTaskUnfoldController;
@Captor
private ArgumentCaptor<SyncTransactionQueue.TransactionRunnable> mRunnableCaptor;
@@ -77,14 +82,17 @@ public final class StageTaskListenerTests {
private StageTaskListener mStageTaskListener;
@Before
+ @UiThreadTest
public void setup() {
MockitoAnnotations.initMocks(this);
mStageTaskListener = new StageTaskListener(
+ mContext,
mTaskOrganizer,
DEFAULT_DISPLAY,
mCallbacks,
mSyncQueue,
mSurfaceSession,
+ mIconProvider,
mStageTaskUnfoldController);
mRootTask = new TestRunningTaskInfoBuilder().build();
mRootTask.parentTaskId = INVALID_TASK_ID;
diff --git a/libs/hwui/pipeline/skia/FunctorDrawable.h b/libs/hwui/pipeline/skia/FunctorDrawable.h
index 9bbd0a92600b..29ef2b82919d 100644
--- a/libs/hwui/pipeline/skia/FunctorDrawable.h
+++ b/libs/hwui/pipeline/skia/FunctorDrawable.h
@@ -34,6 +34,8 @@ namespace skiapipeline {
*/
class FunctorDrawable : public SkDrawable {
public:
+ constexpr static const char* const TYPE_NAME = "FunctorDrawable";
+
FunctorDrawable(int functor, SkCanvas* canvas)
: mBounds(canvas->getLocalClipBounds())
, mWebViewHandle(WebViewFunctorManager::instance().handleFor(functor)) {}
@@ -48,6 +50,8 @@ public:
mWebViewHandle->onRemovedFromTree();
}
+ const char* getTypeName() const override { return TYPE_NAME; }
+
protected:
virtual SkRect onGetBounds() override { return mBounds; }
diff --git a/libs/hwui/pipeline/skia/TransformCanvas.cpp b/libs/hwui/pipeline/skia/TransformCanvas.cpp
index 6777c00c4655..41e36874b862 100644
--- a/libs/hwui/pipeline/skia/TransformCanvas.cpp
+++ b/libs/hwui/pipeline/skia/TransformCanvas.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
#include "TransformCanvas.h"
+
+#include "FunctorDrawable.h"
#include "HolePunch.h"
#include "SkData.h"
#include "SkDrawable.h"
@@ -35,7 +37,17 @@ void TransformCanvas::onDrawAnnotation(const SkRect& rect, const char* key, SkDa
}
void TransformCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
- drawable->draw(this, matrix);
+ // TransformCanvas filters all drawing commands while maintaining the current
+ // clip stack and transformation. We need to draw most SkDrawables, since their
+ // draw calls may call methods that affect the clip stack and transformation. (Any
+ // actual draw commands will then be filtered out.) But FunctorDrawables are used
+ // as leaf nodes which issue self-contained OpenGL/Vulkan commands. These won't
+ // affect the clip stack + transformation, and in some cases cause problems (e.g. if
+ // the surface only has an alpha channel). See b/203960959
+ const auto* drawableName = drawable->getTypeName();
+ if (drawableName == nullptr || strcmp(drawableName, FunctorDrawable::TYPE_NAME) != 0) {
+ drawable->draw(this, matrix);
+ }
}
bool TransformCanvas::onFilter(SkPaint& paint) const {
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 028ae2b3487c..0847be34d90f 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -693,7 +693,7 @@ public final class MediaFormat {
* <p>This key is only used during decoding.
*/
public static final String KEY_MAX_OUTPUT_CHANNEL_COUNT =
- "max-output-channel_count";
+ "max-output-channel-count";
/**
* A key describing the number of frames to trim from the start of the decoded audio stream.
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index b4cafd8548f4..a5168ccd977c 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -78,6 +78,7 @@ public class CompanionDeviceActivity extends Activity {
getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
sInstance = this;
+ getService().mActivity = this;
String deviceProfile = getRequest().getDeviceProfile();
String profilePrivacyDisclaimer = emptyIfNull(getRequest()
@@ -141,8 +142,6 @@ public class CompanionDeviceActivity extends Activity {
profileSummary.setVisibility(View.GONE);
}
- getService().mActivity = this;
-
mCancelButton = findViewById(R.id.button_cancel);
mCancelButton.setOnClickListener(v -> cancel());
}
@@ -194,6 +193,7 @@ public class CompanionDeviceActivity extends Activity {
@Override
protected void onDestroy() {
super.onDestroy();
+ getService().mActivity = null;
if (sInstance == this) {
sInstance = null;
}
@@ -254,8 +254,14 @@ public class CompanionDeviceActivity extends Activity {
Log.i(LOG_TAG, "onDeviceConfirmed(selectedDevice = " + selectedDevice + ")");
getService().onDeviceSelected(
getCallingPackage(), getDeviceMacAddress(selectedDevice.device));
+ }
+
+ void setResultAndFinish() {
+ Log.i(LOG_TAG, "setResultAndFinish(selectedDevice = "
+ + getService().mSelectedDevice.device + ")");
setResult(RESULT_OK,
- new Intent().putExtra(CompanionDeviceManager.EXTRA_DEVICE, selectedDevice.device));
+ new Intent().putExtra(
+ CompanionDeviceManager.EXTRA_DEVICE, getService().mSelectedDevice.device));
finish();
}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index c24782e8b310..2a72c501d7d0 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -117,6 +117,11 @@ public class CompanionDeviceDiscoveryService extends Service {
CompanionDeviceDiscoveryService::startDiscovery,
CompanionDeviceDiscoveryService.this, request));
}
+
+ @Override
+ public void onAssociationCreated() {
+ Handler.getMain().post(CompanionDeviceDiscoveryService.this::onAssociationCreated);
+ }
};
private ScanCallback mBLEScanCallback;
@@ -222,6 +227,11 @@ public class CompanionDeviceDiscoveryService extends Service {
SCAN_TIMEOUT);
}
+ @MainThread
+ private void onAssociationCreated() {
+ mActivity.setResultAndFinish();
+ }
+
private boolean shouldScan(List<? extends DeviceFilter> mediumSpecificFilters) {
return !isEmpty(mediumSpecificFilters) || isEmpty(mFilters);
}
@@ -248,12 +258,8 @@ public class CompanionDeviceDiscoveryService extends Service {
if (!mIsScanning) return;
mIsScanning = false;
- CompanionDeviceActivity activity = mActivity;
- if (activity != null) {
- if (activity.mDeviceListView != null) {
- activity.mDeviceListView.removeFooterView(activity.mLoadingIndicator);
- }
- mActivity = null;
+ if (mActivity != null && mActivity.mDeviceListView != null) {
+ mActivity.mDeviceListView.removeFooterView(mActivity.mLoadingIndicator);
}
mBluetoothAdapter.cancelDiscovery();
@@ -327,6 +333,7 @@ public class CompanionDeviceDiscoveryService extends Service {
void onCancel() {
if (DEBUG) Log.i(LOG_TAG, "onCancel()");
+ mActivity = null;
mServiceCallback.cancel(true);
}
diff --git a/packages/PackageInstaller/res/values-as/strings.xml b/packages/PackageInstaller/res/values-as/strings.xml
index c050d39c236e..522410167eef 100644
--- a/packages/PackageInstaller/res/values-as/strings.xml
+++ b/packages/PackageInstaller/res/values-as/strings.xml
@@ -56,7 +56,7 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"আপুনি এই এপটো আনইনষ্টল কৰিব বিচাৰেনে?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"আপুনি "<b>"সকলো"</b>" ব্যৱহাৰকাৰীৰ বাবে এই এপটো আনইনষ্টল কৰিব বিচাৰেনে? এপ্লিকেশ্বন আৰু ইয়াৰ ডেটা ডিভাইচটোত থকা "<b>"সকলো"</b>" ব্যৱহাৰকাৰীৰ পৰা আঁতৰোৱা হ\'ব৷"</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"আপুনি ব্যৱহাৰকাৰীৰ <xliff:g id="USERNAME">%1$s</xliff:g> বাবে এই এপটো আনইনষ্টল কৰিব বিচাৰেনে?"</string>
- <string name="uninstall_update_text" msgid="863648314632448705">"এই এপটোৰ ফেক্টৰী সংস্কৰণ ব্যৱহাৰ কৰিব বিচাৰেনে? সকলো ডেটা মচা হ\'ব।"</string>
+ <string name="uninstall_update_text" msgid="863648314632448705">"এই এপ্‌টোৰ ফেক্টৰী সংস্কৰণ ব্যৱহাৰ কৰিব বিচাৰেনে? আটাইবোৰ ডেটা মচা হ\'ব।"</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"এই এপটোৰ ফেক্টৰী সংস্কৰণ ব্যৱহাৰ কৰিব বিচাৰেনে? সকলো ডেটা মচা হ\'ব। কর্মস্থানৰ প্ৰফাইল থকা ব্যৱহাৰকাৰীৰ লগতে ডিভাইচটোৰ সকলো ব্যৱহাৰকাৰীৰ ওপৰত ইয়াৰ প্ৰভাৱ পৰিব।"</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"এপৰ ডেটাৰ <xliff:g id="SIZE">%1$s</xliff:g> ৰাখক"</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"আনইনষ্টল কৰি থকা হৈছে"</string>
diff --git a/packages/PrintSpooler/res/values-as/strings.xml b/packages/PrintSpooler/res/values-as/strings.xml
index a93fceb87959..020eac770134 100644
--- a/packages/PrintSpooler/res/values-as/strings.xml
+++ b/packages/PrintSpooler/res/values-as/strings.xml
@@ -28,7 +28,7 @@
<string name="label_orientation" msgid="2853142581990496477">"দিশ"</string>
<string name="label_pages" msgid="7768589729282182230">"পৃষ্ঠাসমূহ"</string>
<string name="destination_default_text" msgid="5422708056807065710">"প্ৰিণ্টাৰ বাছনি কৰক"</string>
- <string name="template_all_pages" msgid="3322235982020148762">"সকলো <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
+ <string name="template_all_pages" msgid="3322235982020148762">"আটাইবোৰ <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
<string name="template_page_range" msgid="428638530038286328">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g>ৰ পৰিসৰ"</string>
<string name="pages_range_example" msgid="8558694453556945172">"যেনে: ১—৫, ৮, ১১—১৩"</string>
<string name="print_preview" msgid="8010217796057763343">"প্ৰিণ্টৰ পূৰ্বদৰ্শন"</string>
@@ -36,7 +36,7 @@
<string name="printing_app_crashed" msgid="854477616686566398">"প্ৰিণ্টিং এপ্ ক্ৰেশ্ব হৈছে"</string>
<string name="generating_print_job" msgid="3119608742651698916">"প্ৰিণ্টিং প্ৰস্তুত কৰি আছে"</string>
<string name="save_as_pdf" msgid="5718454119847596853">"PDF ৰূপে ছেভ কৰক"</string>
- <string name="all_printers" msgid="5018829726861876202">"সকলো প্ৰিণ্টাৰ…"</string>
+ <string name="all_printers" msgid="5018829726861876202">"আটাইবোৰ প্ৰিণ্টাৰ…"</string>
<string name="print_dialog" msgid="32628687461331979">"প্ৰিণ্ট সংবাদ"</string>
<string name="current_page_template" msgid="5145005201131935302">"<xliff:g id="CURRENT_PAGE">%1$d</xliff:g> /<xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
<string name="page_description_template" msgid="6831239682256197161">"পৃষ্ঠা <xliff:g id="PAGE_COUNT">%2$d</xliff:g>ৰ <xliff:g id="CURRENT_PAGE">%1$d</xliff:g>"</string>
@@ -48,7 +48,7 @@
<string name="print_options_expanded" msgid="6944679157471691859">"প্ৰিণ্ট বিকল্পসমূহ বিস্তাৰ কৰা হ’ল"</string>
<string name="print_options_collapsed" msgid="7455930445670414332">"প্ৰিণ্ট বিকল্পসমূহ সংকুচিত কৰা হ’ল"</string>
<string name="search" msgid="5421724265322228497">"সন্ধান কৰক"</string>
- <string name="all_printers_label" msgid="3178848870161526399">"সকলো প্ৰিণ্টাৰ"</string>
+ <string name="all_printers_label" msgid="3178848870161526399">"আটাইবোৰ প্ৰিণ্টাৰ"</string>
<string name="add_print_service_label" msgid="5356702546188981940">"সেৱা যোগ কৰক"</string>
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"সন্ধান বাকচটো দেখুওৱা হ’ল"</string>
<string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"সন্ধান বাকচটো ঢাক খাই আছে"</string>
@@ -74,7 +74,7 @@
<string name="enabled_services_title" msgid="7036986099096582296">"সক্ষম কৰা সেৱাসমূহ"</string>
<string name="recommended_services_title" msgid="3799434882937956924">"অনুমোদিত সেৱাসমূহ"</string>
<string name="disabled_services_title" msgid="7313253167968363211">"অক্ষম কৰা সেৱাসমূহ"</string>
- <string name="all_services_title" msgid="5578662754874906455">"সকলো সেৱা"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"আটাইবোৰ সেৱা"</string>
<plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138">
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g>টা প্ৰিণ্টাৰ বিচাৰিবলৈ ইনষ্টল কৰক</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g>টা প্ৰিণ্টাৰ বিচাৰিবলৈ ইনষ্টল কৰক</item>
diff --git a/packages/SettingsLib/ActivityEmbedding/Android.bp b/packages/SettingsLib/ActivityEmbedding/Android.bp
new file mode 100644
index 000000000000..fc82b79399ef
--- /dev/null
+++ b/packages/SettingsLib/ActivityEmbedding/Android.bp
@@ -0,0 +1,21 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_library {
+ name: "SettingsLibActivityEmbedding",
+
+ srcs: ["src/**/*.java"],
+
+ static_libs: [
+ "androidx.annotation_annotation",
+ "SettingsLibUtils",
+ ],
+ sdk_version: "system_current",
+ min_sdk_version: "21",
+}
diff --git a/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_disabled.xml b/packages/SettingsLib/ActivityEmbedding/AndroidManifest.xml
index 088e82bb4260..2e6c405f9529 100644
--- a/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_disabled.xml
+++ b/packages/SettingsLib/ActivityEmbedding/AndroidManifest.xml
@@ -13,14 +13,11 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
- -->
+-->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="?android:attr/colorControlHighlight">
- <item>
- <shape android:shape="rectangle">
- <solid android:color="@color/settingslib_state_off_color"/>
- <corners android:radius="@dimen/settingslib_switch_bar_radius"/>
- </shape>
- </item>
-</ripple>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.settingslib.activityembedding">
+
+ <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java b/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java
new file mode 100644
index 000000000000..36c2bda8b03a
--- /dev/null
+++ b/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java
@@ -0,0 +1,51 @@
+/*
+ * 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.settingslib.activityembedding;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+
+import com.android.settingslib.utils.BuildCompatUtils;
+
+/**
+ * An util class collecting all common methods for the embedding activity features.
+ */
+public class ActivityEmbeddingUtils {
+ private static final String ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY =
+ "android.settings.SETTINGS_EMBED_DEEP_LINK_ACTIVITY";
+ private static final String PACKAGE_NAME_SETTINGS = "com.android.settings";
+
+ /**
+ * Whether to support embedding activity feature.
+ */
+ public static boolean isEmbeddingActivityEnabled(Context context) {
+ if (BuildCompatUtils.isAtLeastS()) {
+ final Intent intent = new Intent(ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY);
+ intent.setPackage(PACKAGE_NAME_SETTINGS);
+ final ResolveInfo resolveInfo =
+ context.getPackageManager().resolveActivity(intent, 0 /* flags */);
+ return resolveInfo != null
+ && resolveInfo.activityInfo != null
+ && resolveInfo.activityInfo.enabled;
+ }
+ return false;
+ }
+
+ private ActivityEmbeddingUtils() {
+ }
+}
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index a65bf41210a1..7560c41b2e29 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -73,6 +73,7 @@ java_defaults {
"SettingsLibCollapsingToolbarBaseActivity",
"SettingsLibTwoTargetPreference",
"SettingsLibSettingsTransition",
+ "SettingsLibActivityEmbedding",
],
}
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 39aacfdfd658..057349fd25ba 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"نمایش گزینه‌ها برای گواهینامه نمایش بی‌سیم"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"‏افزایش سطح گزارش‌گیری Wi‑Fi، نمایش به ازای SSID RSSI در انتخاب‌کننده Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"تخلیه باتری راکاهش می‌دهد و عملکرد شبکه را بهبود می‌بخشد"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"‏اگر این حالت فعال باشد، هر بار این دستگاه به شبکه‌ای متصل شود که تصادفی‌سازی MAC در آن فعال است، ممکن است نشانی MAC آن تغییر کند."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"اگر این حالت فعال باشد، هر بار این دستگاه به شبکه‌ای متصل شود که تصادفی‌سازی «واپایش دسترسی رسانه» در آن فعال است، ممکن است «نشانی واد» آن تغییر کند."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"محدودشده"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"محدودنشده"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"اندازه‌های حافظه موقت ثبت‌کننده"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 9f2d8a2d346e..286d99418135 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -524,7 +524,7 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"יש לשאול בכל פעם"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"עד הכיבוי"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"הרגע"</string>
- <string name="media_transfer_this_device_name" msgid="2716555073132169240">"רמקול של הטלפון"</string>
+ <string name="media_transfer_this_device_name" msgid="2716555073132169240">"הרמקול של הטלפון"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"הטלפון הזה"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"יש בעיה בחיבור. עליך לכבות את המכשיר ולהפעיל אותו מחדש"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"התקן אודיו חוטי"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 5ed5f39e0ebd..f982eeea84e8 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -454,7 +454,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> lagi hingga penuh"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> lagi hingga penuh"</string>
- <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pengecasan terhad buat sementara waktu"</string>
+ <string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pengecasan terhad sementara"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tidak diketahui"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Mengecas"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mengecas dgn cepat"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 2f571069b788..9f4e544a2be4 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -169,7 +169,7 @@
<string name="tts_play_example_summary" msgid="634044730710636383">"အသံပေါင်းစပ်ခြင်းအတွက် တိုတောင်းသောသရုပ်ပြမှုကို ပြခြင်း"</string>
<string name="tts_install_data_title" msgid="1829942496472751703">"အသံဒေတာများကို ထည့်သွင်းခြင်း"</string>
<string name="tts_install_data_summary" msgid="3608874324992243851">"စကားသံပေါင်းစပ်မှုအတွက်လိုအပ်သောအသံဒေတာအား ထည့်သွင်းမည်"</string>
- <string name="tts_engine_security_warning" msgid="3372432853837988146">"ဤစကားသံပေါင်းစပ်အင်ဂျင်အားအသုံးပြုရာရာတွင် သင့်ကိုယ်ရေးအချက်အလက်များဖြစ်သော စကားဝှက်များနှင့် ကရက်ဒစ်ကဒ်နံပါတ်စသည်တို့အပါအဝင် သင်ပြောဆိုသောစာသားများအားလုံးကို ရယူသွားမည်ဖြစ်သည်။ <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>အင်ဂျင်မှ လာပါသည်။ ဤစကားသံပေါင်းစပ်အင်ဂျင်ကို အသုံးပြုမည်လား?"</string>
+ <string name="tts_engine_security_warning" msgid="3372432853837988146">"ဤစကားသံပေါင်းစပ်စနစ်အားအသုံးပြုရာရာတွင် သင့်ကိုယ်ရေးအချက်အလက်များဖြစ်သော စကားဝှက်များနှင့် ကရက်ဒစ်ကတ်နံပါတ်စသည်တို့အပါအဝင် သင်ပြောဆိုသောစာသားများအားလုံးကို ရယူသွားမည်ဖြစ်သည်။ ဤစနစ်သည် <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> မှ လာပါသည်။ ဤစကားသံပေါင်းစပ်စနစ်ကို အသုံးပြုမလား။"</string>
<string name="tts_engine_network_required" msgid="8722087649733906851">"ဤဘာသာစကားသည် စာသားမှ အသံထွက်ရန် အလုပ်လုပ်သော ကွန်ရက်ချိတ်ဆက်မှု လိုအပ်သည်။"</string>
<string name="tts_default_sample_string" msgid="6388016028292967973">"ဤသည်မှာ အသံတုလုပ်ခြင်း ၏ နမူနာတစ်ခုဖြစ်သည်။"</string>
<string name="tts_status_title" msgid="8190784181389278640">"လက်ရှိဘာသာစကားအခြေအနေ"</string>
@@ -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/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index ff799e09e428..7d2b4d912cef 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -524,7 +524,7 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Всегда спрашивать"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"Пока вы не отключите"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Только что"</string>
- <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Встроенный динамик"</string>
+ <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Встроен. динамик"</string>
<string name="media_transfer_this_phone" msgid="7194341457812151531">"Этот смартфон"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Ошибка подключения. Выключите и снова включите устройство."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Проводное аудиоустройство"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index a67ea6a06381..cb4cbf8b2ce2 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -552,7 +552,7 @@
<string name="user_setup_dialog_message" msgid="269931619868102841">"Đảm bảo người dùng có mặt để tự thiết lập không gian của mình trên thiết bị"</string>
<string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"Thiết lập tiểu sử ngay bây giờ?"</string>
<string name="user_setup_button_setup_now" msgid="1708269547187760639">"Thiết lập ngay"</string>
- <string name="user_setup_button_setup_later" msgid="8712980133555493516">"Không phải bây giờ"</string>
+ <string name="user_setup_button_setup_later" msgid="8712980133555493516">"Để sau"</string>
<string name="user_add_user_type_title" msgid="551279664052914497">"Thêm"</string>
<string name="user_new_user_name" msgid="60979820612818840">"Người dùng mới"</string>
<string name="user_new_profile_name" msgid="2405500423304678841">"Tiểu sử mới"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/SignalIcon.java b/packages/SettingsLib/src/com/android/settingslib/SignalIcon.java
index 794b0eb66519..280e40726c03 100644
--- a/packages/SettingsLib/src/com/android/settingslib/SignalIcon.java
+++ b/packages/SettingsLib/src/com/android/settingslib/SignalIcon.java
@@ -15,13 +15,8 @@
*/
package com.android.settingslib;
-import com.android.settingslib.mobile.TelephonyIcons;
-
-import java.text.SimpleDateFormat;
-import java.util.Objects;
-
/**
- * Icons and states for SysUI and Settings.
+ * Icons for SysUI and Settings.
*/
public class SignalIcon {
@@ -71,92 +66,6 @@ public class SignalIcon {
}
/**
- * Holds states for SysUI.
- */
- public static class State {
- // No locale as it's only used for logging purposes
- private static SimpleDateFormat sSDF = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
- public boolean connected;
- public boolean enabled;
- public boolean activityIn;
- public boolean activityOut;
- public int level;
- public IconGroup iconGroup;
- public int inetCondition;
- public int rssi; // Only for logging.
-
- // Not used for comparison, just used for logging.
- public long time;
-
- /**
- * Generates a copy of the source state.
- */
- public void copyFrom(State state) {
- connected = state.connected;
- enabled = state.enabled;
- level = state.level;
- iconGroup = state.iconGroup;
- inetCondition = state.inetCondition;
- activityIn = state.activityIn;
- activityOut = state.activityOut;
- rssi = state.rssi;
- time = state.time;
- }
-
- @Override
- public String toString() {
- if (time != 0) {
- StringBuilder builder = new StringBuilder();
- toString(builder);
- return builder.toString();
- } else {
- return "Empty " + getClass().getSimpleName();
- }
- }
-
- protected void toString(StringBuilder builder) {
- builder.append("connected=").append(connected).append(',')
- .append("enabled=").append(enabled).append(',')
- .append("level=").append(level).append(',')
- .append("inetCondition=").append(inetCondition).append(',')
- .append("iconGroup=").append(iconGroup).append(',')
- .append("activityIn=").append(activityIn).append(',')
- .append("activityOut=").append(activityOut).append(',')
- .append("rssi=").append(rssi).append(',')
- .append("lastModified=").append(sSDF.format(time));
- }
-
- @Override
- public boolean equals(Object o) {
- if (!o.getClass().equals(getClass())) {
- return false;
- }
- State other = (State) o;
- return other.connected == connected
- && other.enabled == enabled
- && other.level == level
- && other.inetCondition == inetCondition
- && other.iconGroup == iconGroup
- && other.activityIn == activityIn
- && other.activityOut == activityOut
- && other.rssi == rssi;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(
- connected,
- enabled,
- level,
- inetCondition,
- iconGroup,
- activityIn,
- activityOut,
- rssi);
- }
- }
-
- /**
* Holds icons for a given MobileState.
*/
public static class MobileIconGroup extends IconGroup {
@@ -189,110 +98,4 @@ public class SignalIcon {
this.dataType = dataType;
}
}
-
- /**
- * Holds mobile states for SysUI.
- */
- public static class MobileState extends State {
- public String networkName;
- public String networkNameData;
- public boolean dataSim;
- public boolean dataConnected;
- public boolean isEmergency;
- public boolean airplaneMode;
- public boolean carrierNetworkChangeMode;
- public boolean isDefault;
- public boolean userSetup;
- public boolean roaming;
- public boolean defaultDataOff; // Tracks the on/off state of the defaultDataSubscription
-
- @Override
- public void copyFrom(State s) {
- super.copyFrom(s);
- MobileState state = (MobileState) s;
- dataSim = state.dataSim;
- networkName = state.networkName;
- networkNameData = state.networkNameData;
- dataConnected = state.dataConnected;
- isDefault = state.isDefault;
- isEmergency = state.isEmergency;
- airplaneMode = state.airplaneMode;
- carrierNetworkChangeMode = state.carrierNetworkChangeMode;
- userSetup = state.userSetup;
- roaming = state.roaming;
- defaultDataOff = state.defaultDataOff;
- }
-
- /** @return true if this state is disabled or not default data */
- public boolean isDataDisabledOrNotDefault() {
- return (iconGroup == TelephonyIcons.DATA_DISABLED
- || (iconGroup == TelephonyIcons.NOT_DEFAULT_DATA)) && userSetup;
- }
-
- /** @return if this state is considered to have inbound activity */
- public boolean hasActivityIn() {
- return dataConnected && !carrierNetworkChangeMode && activityIn;
- }
-
- /** @return if this state is considered to have outbound activity */
- public boolean hasActivityOut() {
- return dataConnected && !carrierNetworkChangeMode && activityOut;
- }
-
- /** @return true if this state should show a RAT icon in quick settings */
- public boolean showQuickSettingsRatIcon() {
- return dataConnected || isDataDisabledOrNotDefault();
- }
-
- @Override
- protected void toString(StringBuilder builder) {
- super.toString(builder);
- builder.append(',');
- builder.append("dataSim=").append(dataSim).append(',');
- builder.append("networkName=").append(networkName).append(',');
- builder.append("networkNameData=").append(networkNameData).append(',');
- builder.append("dataConnected=").append(dataConnected).append(',');
- builder.append("roaming=").append(roaming).append(',');
- builder.append("isDefault=").append(isDefault).append(',');
- builder.append("isEmergency=").append(isEmergency).append(',');
- builder.append("airplaneMode=").append(airplaneMode).append(',');
- builder.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode)
- .append(',');
- builder.append("userSetup=").append(userSetup).append(',');
- builder.append("defaultDataOff=").append(defaultDataOff).append(',');
- builder.append("showQuickSettingsRatIcon=").append(showQuickSettingsRatIcon());
- }
-
- @Override
- public boolean equals(Object o) {
- return super.equals(o)
- && Objects.equals(((MobileState) o).networkName, networkName)
- && Objects.equals(((MobileState) o).networkNameData, networkNameData)
- && ((MobileState) o).dataSim == dataSim
- && ((MobileState) o).dataConnected == dataConnected
- && ((MobileState) o).isEmergency == isEmergency
- && ((MobileState) o).airplaneMode == airplaneMode
- && ((MobileState) o).carrierNetworkChangeMode == carrierNetworkChangeMode
- && ((MobileState) o).userSetup == userSetup
- && ((MobileState) o).isDefault == isDefault
- && ((MobileState) o).roaming == roaming
- && ((MobileState) o).defaultDataOff == defaultDataOff;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(super.hashCode(),
- networkName,
- networkNameData,
- dataSim,
- dataConnected,
- isEmergency,
- airplaneMode,
- carrierNetworkChangeMode,
- userSetup,
- isDefault,
- roaming,
- defaultDataOff);
- }
- }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index a1fba4a018e2..dc109cac37b2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -16,7 +16,8 @@
package com.android.settingslib.bluetooth;
-import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_ALL;
+import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_AUDIO;
+import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL;
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
@@ -29,6 +30,7 @@ import android.content.Context;
import android.util.Log;
import com.android.settingslib.R;
+import com.android.settingslib.Utils;
import java.util.ArrayList;
import java.util.List;
@@ -162,9 +164,12 @@ public class HearingAidProfile implements LocalBluetoothProfile {
if (mBluetoothAdapter == null) {
return false;
}
+ int profiles = Utils.isAudioModeOngoingCall(mContext)
+ ? ACTIVE_DEVICE_PHONE_CALL
+ : ACTIVE_DEVICE_AUDIO;
return device == null
- ? mBluetoothAdapter.removeActiveDevice(ACTIVE_DEVICE_ALL)
- : mBluetoothAdapter.setActiveDevice(device, ACTIVE_DEVICE_ALL);
+ ? mBluetoothAdapter.removeActiveDevice(profiles)
+ : mBluetoothAdapter.setActiveDevice(device, profiles);
}
public List<BluetoothDevice> getActiveDevices() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
index 6cb60d1aaf0e..7390b6aaaaed 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
@@ -97,6 +97,9 @@ public class MetricsFeatureProvider {
/**
* Logs a simple action without page id or attribution
+ *
+ * @param category the target page
+ * @param taggedData the data for {@link EventLogWriter}
*/
public void action(Context context, int category, Pair<Integer, Object>... taggedData) {
for (LogWriter writer : mLoggerWriters) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
index 274696bfec0e..468aa05052ad 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
@@ -183,6 +183,20 @@ public class UserIconDrawable extends Drawable implements Drawable.Callback {
return setBadge(badge);
}
+ /**
+ * Sets the managed badge to this user icon if the device has a device owner.
+ */
+ public UserIconDrawable setBadgeIfManagedDevice(Context context) {
+ Drawable badge = null;
+ boolean deviceOwnerExists = context.getSystemService(DevicePolicyManager.class)
+ .getDeviceOwnerComponentOnAnyUser() != null;
+ if (deviceOwnerExists) {
+ badge = getDrawableForDisplayDensity(
+ context, com.android.internal.R.drawable.ic_corp_badge_case);
+ }
+ return setBadge(badge);
+ }
+
public void setBadgeRadius(float radius) {
mBadgeRadius = radius;
onBoundsChange(getBounds());
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 3c43f4a637ba..a383c1e2b680 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -70,6 +70,7 @@ public class InfoMediaManager extends MediaManager {
MediaRouter2Manager mRouterManager;
@VisibleForTesting
String mPackageName;
+ private final boolean mVolumeAdjustmentForRemoteGroupSessions;
private MediaDevice mCurrentConnectedDevice;
private LocalBluetoothManager mBluetoothManager;
@@ -83,6 +84,9 @@ public class InfoMediaManager extends MediaManager {
if (!TextUtils.isEmpty(packageName)) {
mPackageName = packageName;
}
+
+ mVolumeAdjustmentForRemoteGroupSessions = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions);
}
@Override
@@ -387,7 +391,9 @@ public class InfoMediaManager extends MediaManager {
@TargetApi(Build.VERSION_CODES.R)
boolean shouldEnableVolumeSeekBar(RoutingSessionInfo sessionInfo) {
- return false;
+ return sessionInfo.isSystemSession() // System sessions are not remote
+ || mVolumeAdjustmentForRemoteGroupSessions
+ || sessionInfo.getSelectedRoutes().size() <= 1;
}
private void refreshDevices() {
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index c6cca5adaeb0..bca5071380de 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -52,12 +52,18 @@ java_library {
filegroup {
name: "ReleaseJavaFiles",
- srcs: ["src/com/android/systemui/flags/FeatureFlagManager.java"],
+ srcs: [
+ "src-release/**/*.kt",
+ "src-release/**/*.java",
+ ],
}
filegroup {
name: "DebugJavaFiles",
- srcs: ["src-debug/com/android/systemui/flags/FeatureFlagManager.java"],
+ srcs: [
+ "src-debug/**/*.kt",
+ "src-debug/**/*.java",
+ ],
}
android_library {
@@ -66,6 +72,7 @@ android_library {
"src/**/*.kt",
"src/**/*.java",
"src/**/I*.aidl",
+ ":ReleaseJavaFiles",
],
product_variables: {
debuggable: {
@@ -159,6 +166,7 @@ android_library {
"src/**/*.kt",
"src/**/*.java",
"src/**/I*.aidl",
+ ":ReleaseJavaFiles",
],
static_libs: [
"SystemUIAnimationLib",
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 58e3d398553c..462aa57eee5e 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -356,10 +356,6 @@
android:exported="false"
android:finishOnTaskLaunch="true" />
- <activity android:name=".screenrecord.ScreenRecordDialog"
- android:theme="@style/ScreenRecord"
- android:showForAllUsers="true"
- android:excludeFromRecents="true" />
<service android:name=".screenrecord.RecordingService" />
<receiver android:name=".SysuiRestartReceiver"
@@ -585,21 +581,6 @@
</intent-filter>
</activity>
- <activity android:name=".egg.MLandActivity"
- android:theme="@android:style/Theme.Material.NoActionBar"
- android:exported="true"
- android:icon="@drawable/icon"
- android:label="@string/mland"
- android:launchMode="singleInstance"
- android:screenOrientation="locked"
- android:process=":sweetsweetdesserts"
- android:excludeFromRecents="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
-
<!-- People Space UI Screen -->
<activity android:name=".people.PeopleSpaceActivity"
android:label="@string/people_tile_title"
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index e509777633e7..1fe509ac538f 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -116,13 +116,18 @@
],
"auto-end-to-end-postsubmit": [
{
- "name": "AndroidAutoUiTests",
+ "name": "AndroidAutomotiveHomeTests",
"options" : [
{
- "include-filter": "android.test.functional.auto.apps.HomeHelperTest"
- },
+ "include-filter": "android.platform.tests.HomeTest"
+ }
+ ]
+ },
+ {
+ "name": "AndroidAutomotiveNotificationsTests",
+ "options" : [
{
- "include-filter": "android.test.functional.auto.apps.NotificationHelperTest"
+ "include-filter": "android.platform.tests.NotificationTest"
}
]
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
index c2b36089d0a7..413612ff9a76 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -16,26 +16,34 @@
package com.android.systemui.animation
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
import android.app.Dialog
import android.content.Context
import android.graphics.Color
+import android.graphics.Rect
import android.os.Looper
import android.util.Log
+import android.util.MathUtils
+import android.view.GhostView
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
-import android.view.ViewTreeObserver
+import android.view.ViewTreeObserver.OnPreDrawListener
+import android.view.WindowInsets
import android.view.WindowManager
+import android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
+import android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+import android.view.WindowManagerPolicyConstants
import android.widget.FrameLayout
+import kotlin.math.roundToInt
private const val TAG = "DialogLaunchAnimator"
/**
* A class that allows dialogs to be started in a seamless way from a view that is transforming
* nicely into the starting dialog.
- *
- * Important: Don't forget to call [DialogLaunchAnimator.onDozeAmountChanged] when the doze amount
- * changes to gracefully handle dialogs fading out when the device is dozing.
*/
class DialogLaunchAnimator(
private val context: Context,
@@ -46,11 +54,16 @@ class DialogLaunchAnimator(
private val TAG_LAUNCH_ANIMATION_RUNNING = R.id.launch_animation_running
}
+ /**
+ * The set of dialogs that were animated using this animator and that are still opened (not
+ * dismissed, but can be hidden).
+ */
// TODO(b/201264644): Remove this set.
- private val currentAnimations = hashSetOf<DialogLaunchAnimation>()
+ private val openedDialogs = hashSetOf<AnimatedDialog>()
/**
- * Show [dialog] by expanding it from [view].
+ * Show [dialog] by expanding it from [view]. If [animateBackgroundBoundsChange] is true, then
+ * the background of the dialog will be animated when the dialog bounds change.
*
* Caveats: When calling this function, the dialog content view will actually be stolen and
* attached to a different dialog (and thus a different window) which means that the actual
@@ -58,34 +71,57 @@ class DialogLaunchAnimator(
* must call dismiss(), hide() and show() on the [Dialog] returned by this function to actually
* dismiss, hide or show the dialog.
*/
- fun showFromView(dialog: Dialog, view: View): Dialog {
+ @JvmOverloads
+ fun showFromView(
+ dialog: Dialog,
+ view: View,
+ animateBackgroundBoundsChange: Boolean = false
+ ): Dialog {
if (Looper.myLooper() != Looper.getMainLooper()) {
throw IllegalStateException(
"showFromView must be called from the main thread and dialog must be created in " +
"the main thread")
}
+ // If the parent of the view we are launching from is the background of some other animated
+ // dialog, then this means the caller intent is to launch a dialog from another dialog. In
+ // this case, we also animate the parent (which is the dialog background).
+ val dialogContentParent = openedDialogs
+ .firstOrNull { it.dialogContentParent == view.parent }
+ ?.dialogContentParent
+ val animateFrom = dialogContentParent ?: view
+
// Make sure we don't run the launch animation from the same view twice at the same time.
- if (view.getTag(TAG_LAUNCH_ANIMATION_RUNNING) != null) {
+ if (animateFrom.getTag(TAG_LAUNCH_ANIMATION_RUNNING) != null) {
Log.e(TAG, "Not running dialog launch animation as there is already one running")
dialog.show()
return dialog
}
- view.setTag(TAG_LAUNCH_ANIMATION_RUNNING, true)
+ animateFrom.setTag(TAG_LAUNCH_ANIMATION_RUNNING, true)
- val launchAnimation = DialogLaunchAnimation(
- context, launchAnimator, hostDialogProvider, view,
- onDialogDismissed = { currentAnimations.remove(it) }, originalDialog = dialog)
+ val launchAnimation = AnimatedDialog(
+ context, launchAnimator, hostDialogProvider, animateFrom,
+ onDialogDismissed = { openedDialogs.remove(it) }, originalDialog = dialog,
+ animateBackgroundBoundsChange)
val hostDialog = launchAnimation.hostDialog
- currentAnimations.add(launchAnimation)
+ openedDialogs.add(launchAnimation)
// If the dialog is dismissed/hidden/shown, then we should actually dismiss/hide/show the
// host dialog.
if (dialog is ListenableDialog) {
dialog.addListener(object : DialogListener {
- override fun onDismiss() {
+ override fun onDismiss(reason: DialogListener.DismissReason) {
dialog.removeListener(this)
+
+ // We disable the exit animation if we are dismissing the dialog because the
+ // device is being locked, otherwise the animation looks bad if AOD is enabled.
+ // If AOD is disabled the screen will directly becomes black and we won't see
+ // the animation anyways.
+ if (reason == DialogListener.DismissReason.DEVICE_LOCKED) {
+ launchAnimation.exitAnimationDisabled = true
+ }
+
hostDialog.dismiss()
}
@@ -105,6 +141,10 @@ class DialogLaunchAnimator(
launchAnimation.ignoreNextCallToHide = true
dialog.hide()
}
+
+ override fun onSizeChanged() {
+ launchAnimation.onOriginalDialogSizeChanged()
+ }
})
}
@@ -112,13 +152,6 @@ class DialogLaunchAnimator(
return hostDialog
}
- /** Notify the current doze amount, to ensure that dialogs fade out when dozing. */
- // TODO(b/193634619): Replace this by some mandatory constructor parameter to make sure that we
- // don't forget to call this when the doze amount changes.
- fun onDozeAmountChanged(amount: Float) {
- currentAnimations.forEach { it.onDozeAmountChanged(amount) }
- }
-
/**
* Ensure that all dialogs currently shown won't animate into their touch surface when
* dismissed.
@@ -130,7 +163,7 @@ class DialogLaunchAnimator(
* TODO(b/193634619): Remove this function and animate dialog into opening activity instead.
*/
fun disableAllCurrentDialogsExitAnimations() {
- currentAnimations.forEach { it.exitAnimationDisabled = true }
+ openedDialogs.forEach { it.exitAnimationDisabled = true }
}
}
@@ -142,6 +175,7 @@ interface HostDialogProvider {
* 2. call [dismissOverride] instead of doing any dismissing logic. The actual dismissing
* logic should instead be done inside the lambda passed to [dismissOverride], which will
* be called after the exit animation.
+ * 3. Be full screen, i.e. have a window matching its parent size.
*
* See SystemUIHostDialogProvider for an example of implementation.
*/
@@ -163,17 +197,28 @@ interface ListenableDialog {
}
interface DialogListener {
+ /** The reason why a dialog was dismissed. */
+ enum class DismissReason {
+ UNKNOWN,
+
+ /** The device was locked, which dismissed this dialog. */
+ DEVICE_LOCKED,
+ }
+
/** Called when this dialog dismiss() is called. */
- fun onDismiss()
+ fun onDismiss(reason: DismissReason)
/** Called when this dialog hide() is called. */
fun onHide()
/** Called when this dialog show() is called. */
fun onShow()
+
+ /** Called when this dialog size might have changed, e.g. because of configuration changes. */
+ fun onSizeChanged()
}
-private class DialogLaunchAnimation(
+private class AnimatedDialog(
private val context: Context,
private val launchAnimator: LaunchAnimator,
hostDialogProvider: HostDialogProvider,
@@ -182,13 +227,16 @@ private class DialogLaunchAnimation(
private val touchSurface: View,
/**
- * A callback that will be called with this [DialogLaunchAnimation] after the dialog was
+ * A callback that will be called with this [AnimatedDialog] after the dialog was
* dismissed and the exit animation is done.
*/
- private val onDialogDismissed: (DialogLaunchAnimation) -> Unit,
+ private val onDialogDismissed: (AnimatedDialog) -> Unit,
/** The original dialog whose content will be shown and animate in/out in [hostDialog]. */
- private val originalDialog: Dialog
+ private val originalDialog: Dialog,
+
+ /** Whether we should animate the dialog background when its bounds change. */
+ private val animateBackgroundBoundsChange: Boolean
) {
/**
* The fullscreen dialog to which we will add the content view [originalDialogView] of
@@ -201,10 +249,11 @@ private class DialogLaunchAnimation(
private val hostDialogRoot = FrameLayout(context)
/**
- * The content view of [originalDialog], which will be stolen from that dialog and added to
- * [hostDialogRoot].
+ * The parent of the original dialog content view, that serves as a fake window that will have
+ * the same size as the original dialog window and to which we will set the original dialog
+ * window background.
*/
- private var originalDialogView: View? = null
+ val dialogContentParent = FrameLayout(context)
/**
* The background color of [originalDialogView], taking into consideration the [originalDialog]
@@ -221,10 +270,17 @@ private class DialogLaunchAnimation(
private var isDismissing = false
private var dismissRequested = false
- private var drawHostDialog = false
var ignoreNextCallToHide = false
var exitAnimationDisabled = false
+ private var isTouchSurfaceGhostDrawn = false
+ private var isOriginalDialogViewLaidOut = false
+ private var backgroundLayoutListener = if (animateBackgroundBoundsChange) {
+ AnimatedBoundsLayoutListener()
+ } else {
+ null
+ }
+
fun start() {
// Show the host (fullscreen) dialog, to which we will add the stolen dialog view.
hostDialog.show()
@@ -247,24 +303,77 @@ private class DialogLaunchAnimation(
val window = hostDialog.window
?: throw IllegalStateException("There is no window associated to the host dialog")
window.setBackgroundDrawableResource(android.R.color.transparent)
- window.setLayout(
- WindowManager.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.MATCH_PARENT
- )
- // Prevent the host dialog from drawing until the animation starts.
- hostDialogRoot.viewTreeObserver.addOnPreDrawListener(
- object : ViewTreeObserver.OnPreDrawListener {
- override fun onPreDraw(): Boolean {
- if (drawHostDialog) {
- hostDialogRoot.viewTreeObserver.removeOnPreDrawListener(this)
- return true
- }
+ // If we are using gesture navigation, then we can overlay the navigation/task bars with
+ // the host dialog.
+ val navigationMode = context.resources.getInteger(
+ com.android.internal.R.integer.config_navBarInteractionMode)
+ if (navigationMode == WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL) {
+ window.attributes.fitInsetsTypes = window.attributes.fitInsetsTypes and
+ WindowInsets.Type.navigationBars().inv()
+ window.addFlags(FLAG_LAYOUT_IN_SCREEN or FLAG_LAYOUT_INSET_DECOR)
+ window.setDecorFitsSystemWindows(false)
+ }
- return false
- }
+ // Disable the dim. We will enable it once we start the animation.
+ window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
+
+ // Add a temporary touch surface ghost as soon as the window is ready to draw. This
+ // temporary ghost will be drawn together with the touch surface, but in the host dialog
+ // window. Once it is drawn, we will make the touch surface invisible, and then start the
+ // animation. We do all this synchronization to avoid flicker that would occur if we made
+ // the touch surface invisible too early (before its ghost is drawn), leading to one or more
+ // frames with a hole instead of the touch surface (or its ghost).
+ hostDialogRoot.viewTreeObserver.addOnPreDrawListener(object : OnPreDrawListener {
+ override fun onPreDraw(): Boolean {
+ hostDialogRoot.viewTreeObserver.removeOnPreDrawListener(this)
+ addTemporaryTouchSurfaceGhost()
+ return true
}
- )
+ })
+ hostDialogRoot.invalidate()
+ }
+
+ private fun addTemporaryTouchSurfaceGhost() {
+ // Create a ghost of the touch surface (which will make the touch surface invisible) and add
+ // it to the host dialog. We will wait for this ghost to be drawn before starting the
+ // animation.
+ val ghost = GhostView.addGhost(touchSurface, hostDialogRoot)
+
+ // The ghost of the touch surface was just created, so the touch surface was made invisible.
+ // We make it visible again until the ghost is actually drawn.
+ touchSurface.visibility = View.VISIBLE
+
+ // Wait for the ghost to be drawn before continuing.
+ ghost.viewTreeObserver.addOnPreDrawListener(object : OnPreDrawListener {
+ override fun onPreDraw(): Boolean {
+ ghost.viewTreeObserver.removeOnPreDrawListener(this)
+ onTouchSurfaceGhostDrawn()
+ return true
+ }
+ })
+ ghost.invalidate()
+ }
+
+ private fun onTouchSurfaceGhostDrawn() {
+ // Make the touch surface invisible and make sure that it stays invisible as long as the
+ // dialog is shown or animating.
+ touchSurface.visibility = View.INVISIBLE
+ if (touchSurface is LaunchableView) {
+ touchSurface.setShouldBlockVisibilityChanges(true)
+ }
+
+ // Add a pre draw listener to (maybe) start the animation once the touch surface is
+ // actually invisible.
+ touchSurface.viewTreeObserver.addOnPreDrawListener(object : OnPreDrawListener {
+ override fun onPreDraw(): Boolean {
+ touchSurface.viewTreeObserver.removeOnPreDrawListener(this)
+ isTouchSurfaceGhostDrawn = true
+ maybeStartLaunchAnimation()
+ return true
+ }
+ })
+ touchSurface.invalidate()
}
/** Get the content view of [originalDialog] and pass it to [then]. */
@@ -276,7 +385,7 @@ private class DialogLaunchAnimation(
?: throw IllegalStateException("Dialog does not have any android.R.id.content view")
androidContent.viewTreeObserver.addOnPreDrawListener(
- object : ViewTreeObserver.OnPreDrawListener {
+ object : OnPreDrawListener {
override fun onPreDraw(): Boolean {
if (androidContent.childCount == 1) {
androidContent.viewTreeObserver.removeOnPreDrawListener(this)
@@ -299,9 +408,6 @@ private class DialogLaunchAnimation(
}
private fun showDialogFromView(dialogView: View) {
- // Save the dialog view for later as we will need it for the close animation.
- this.originalDialogView = dialogView
-
// Close the dialog when clicking outside of it.
hostDialogRoot.setOnClickListener { hostDialog.dismiss() }
dialogView.isClickable = true
@@ -319,29 +425,46 @@ private class DialogLaunchAnimation(
throw IllegalStateException("Dialogs with no backgrounds on window are not supported")
}
- dialogView.setBackgroundResource(backgroundRes)
+ // Add a parent view to the original dialog view to which we will set the original dialog
+ // window background. This View serves as a fake window with background, so that we are sure
+ // that we don't override the dialog view paddings with the window background that usually
+ // has insets.
+ dialogContentParent.setBackgroundResource(backgroundRes)
+ hostDialogRoot.addView(
+ dialogContentParent,
+
+ // We give it the size of its original dialog window.
+ FrameLayout.LayoutParams(
+ originalDialog.window.attributes.width,
+ originalDialog.window.attributes.height,
+ Gravity.CENTER
+ )
+ )
+
+ // Make the dialog view parent invisible for now, to make sure it's not drawn yet.
+ dialogContentParent.visibility = View.INVISIBLE
+
+ val background = dialogContentParent.background!!
originalDialogBackgroundColor =
- GhostedViewLaunchAnimatorController.findGradientDrawable(dialogView.background!!)
+ GhostedViewLaunchAnimatorController.findGradientDrawable(background)
?.color
?.defaultColor ?: Color.BLACK
- // Add the dialog view to the host (fullscreen) dialog and make it invisible to make sure
- // it's not drawn yet.
+ // Add the dialog view to its parent (that has the original window background).
(dialogView.parent as? ViewGroup)?.removeView(dialogView)
- hostDialogRoot.addView(
+ dialogContentParent.addView(
dialogView,
- // We give it the size of its original dialog window.
+ // It should match its parent size, which is sized the same as the original dialog
+ // window.
FrameLayout.LayoutParams(
- originalDialog.window.attributes.width,
- originalDialog.window.attributes.height,
- Gravity.CENTER
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT
)
)
- dialogView.visibility = View.INVISIBLE
// Start the animation when the dialog is laid out in the center of the host dialog.
- dialogView.addOnLayoutChangeListener(object : View.OnLayoutChangeListener {
+ dialogContentParent.addOnLayoutChangeListener(object : View.OnLayoutChangeListener {
override fun onLayoutChange(
view: View,
left: Int,
@@ -353,33 +476,68 @@ private class DialogLaunchAnimation(
oldRight: Int,
oldBottom: Int
) {
- dialogView.removeOnLayoutChangeListener(this)
- startAnimation(
- isLaunching = true,
- onLaunchAnimationStart = { drawHostDialog = true },
- onLaunchAnimationEnd = {
- touchSurface.setTag(R.id.launch_animation_running, null)
-
- // We hide the touch surface when the dialog is showing. We will make this
- // view visible again when dismissing the dialog.
- // TODO(b/193634619): Provide an easy way for views to check if they should
- // be hidden because of a dialog launch so that they don't override this
- // visibility when updating/refreshing itself.
- touchSurface.visibility = View.INVISIBLE
-
- isLaunching = false
-
- // dismiss was called during the animation, dismiss again now to actually
- // dismiss.
- if (dismissRequested) {
- hostDialog.dismiss()
- }
- }
- )
+ dialogContentParent.removeOnLayoutChangeListener(this)
+
+ isOriginalDialogViewLaidOut = true
+ maybeStartLaunchAnimation()
}
})
}
+ fun onOriginalDialogSizeChanged() {
+ // The dialog is the single child of the root.
+ if (hostDialogRoot.childCount != 1) {
+ return
+ }
+
+ val dialogView = hostDialogRoot.getChildAt(0)
+ val layoutParams = dialogView.layoutParams as? FrameLayout.LayoutParams ?: return
+ layoutParams.width = originalDialog.window.attributes.width
+ layoutParams.height = originalDialog.window.attributes.height
+ dialogView.layoutParams = layoutParams
+ }
+
+ private fun maybeStartLaunchAnimation() {
+ if (!isTouchSurfaceGhostDrawn || !isOriginalDialogViewLaidOut) {
+ return
+ }
+
+ // Show the background dim.
+ hostDialog.window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
+
+ startAnimation(
+ isLaunching = true,
+ onLaunchAnimationStart = {
+ // Remove the temporary ghost. Another ghost (that ghosts only the touch surface
+ // content, and not its background) will be added right after this and will be
+ // animated.
+ GhostView.removeGhost(touchSurface)
+ },
+ onLaunchAnimationEnd = {
+ touchSurface.setTag(R.id.launch_animation_running, null)
+
+ // We hide the touch surface when the dialog is showing. We will make this
+ // view visible again when dismissing the dialog.
+ touchSurface.visibility = View.INVISIBLE
+
+ isLaunching = false
+
+ // dismiss was called during the animation, dismiss again now to actually
+ // dismiss.
+ if (dismissRequested) {
+ hostDialog.dismiss()
+ }
+
+ // If necessary, we animate the dialog background when its bounds change. We do it
+ // at the end of the launch animation, because the lauch animation already correctly
+ // handles bounds changes.
+ if (backgroundLayoutListener != null) {
+ dialogContentParent.addOnLayoutChangeListener(backgroundLayoutListener)
+ }
+ }
+ )
+ }
+
private fun onHostDialogDismissed(actualDismiss: () -> Unit) {
if (Looper.myLooper() != Looper.getMainLooper()) {
context.mainExecutor.execute { onHostDialogDismissed(actualDismiss) }
@@ -417,13 +575,18 @@ private class DialogLaunchAnimation(
if (!shouldAnimateDialogIntoView()) {
Log.i(TAG, "Skipping animation of dialog into the touch surface")
+ // Make sure we allow the touch surface to change its visibility again.
+ if (touchSurface is LaunchableView) {
+ touchSurface.setShouldBlockVisibilityChanges(false)
+ }
+
// If the view is invisible it's probably because of us, so we make it visible again.
if (touchSurface.visibility == View.INVISIBLE) {
touchSurface.visibility = View.VISIBLE
}
dismissDialogs(false /* instantDismiss */)
- onDialogDismissed(this@DialogLaunchAnimation)
+ onDialogDismissed(this@AnimatedDialog)
return
}
@@ -434,10 +597,37 @@ private class DialogLaunchAnimation(
hostDialog.window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
},
onLaunchAnimationEnd = {
+ // Make sure we allow the touch surface to change its visibility again.
+ if (touchSurface is LaunchableView) {
+ touchSurface.setShouldBlockVisibilityChanges(false)
+ }
+
touchSurface.visibility = View.VISIBLE
- originalDialogView!!.visibility = View.INVISIBLE
- dismissDialogs(true /* instantDismiss */)
- onDialogDismissed(this@DialogLaunchAnimation)
+ dialogContentParent.visibility = View.INVISIBLE
+
+ if (backgroundLayoutListener != null) {
+ dialogContentParent.removeOnLayoutChangeListener(backgroundLayoutListener)
+ }
+
+ // The animated ghost was just removed. We create a temporary ghost that will be
+ // removed only once we draw the touch surface, to avoid flickering that would
+ // happen when removing the ghost too early (before the touch surface is drawn).
+ GhostView.addGhost(touchSurface, hostDialogRoot)
+
+ touchSurface.viewTreeObserver.addOnPreDrawListener(object : OnPreDrawListener {
+ override fun onPreDraw(): Boolean {
+ touchSurface.viewTreeObserver.removeOnPreDrawListener(this)
+
+ // Now that the touch surface was drawn, we can remove the temporary ghost
+ // and instantly dismiss the dialog.
+ GhostView.removeGhost(touchSurface)
+ dismissDialogs(true /* instantDismiss */)
+ onDialogDismissed(this@AnimatedDialog)
+
+ return true
+ }
+ })
+ touchSurface.invalidate()
}
)
}
@@ -447,12 +637,10 @@ private class DialogLaunchAnimation(
onLaunchAnimationStart: () -> Unit = {},
onLaunchAnimationEnd: () -> Unit = {}
) {
- val dialogView = this.originalDialogView!!
-
// Create 2 ghost controllers to animate both the dialog and the touch surface in the host
// dialog.
- val startView = if (isLaunching) touchSurface else dialogView
- val endView = if (isLaunching) dialogView else touchSurface
+ val startView = if (isLaunching) touchSurface else dialogContentParent
+ val endView = if (isLaunching) dialogContentParent else touchSurface
val startViewController = GhostedViewLaunchAnimatorController(startView)
val endViewController = GhostedViewLaunchAnimatorController(endView)
startViewController.launchContainer = hostDialogRoot
@@ -472,10 +660,13 @@ private class DialogLaunchAnimation(
}
override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
+ // During launch, onLaunchAnimationStart will be used to remove the temporary touch
+ // surface ghost so it is important to call this before calling
+ // onLaunchAnimationStart on the controller (which will create its own ghost).
+ onLaunchAnimationStart()
+
startViewController.onLaunchAnimationStart(isExpandingFullyAbove)
endViewController.onLaunchAnimationStart(isExpandingFullyAbove)
-
- onLaunchAnimationStart()
}
override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
@@ -529,13 +720,80 @@ private class DialogLaunchAnimation(
return (touchSurface.parent as? View)?.isShown ?: true
}
- internal fun onDozeAmountChanged(amount: Float) {
- val alpha = Interpolators.ALPHA_OUT.getInterpolation(1 - amount)
- val decorView = this.hostDialog.window?.decorView ?: return
- if (decorView.hasOverlappingRendering() && alpha > 0.0f &&
- alpha < 1.0f && decorView.layerType != View.LAYER_TYPE_HARDWARE) {
- decorView.setLayerType(View.LAYER_TYPE_HARDWARE, null)
+ /** A layout listener to animate the change of bounds of the dialog background. */
+ class AnimatedBoundsLayoutListener : View.OnLayoutChangeListener {
+ companion object {
+ private const val ANIMATION_DURATION = 500L
+ }
+
+ private var lastBounds: Rect? = null
+ private var currentAnimator: ValueAnimator? = null
+
+ override fun onLayoutChange(
+ view: View,
+ left: Int,
+ top: Int,
+ right: Int,
+ bottom: Int,
+ oldLeft: Int,
+ oldTop: Int,
+ oldRight: Int,
+ oldBottom: Int
+ ) {
+ // Don't animate if bounds didn't actually change.
+ if (left == oldLeft && top == oldTop && right == oldRight && bottom == oldBottom) {
+ // Make sure that we that the last bounds set by the animator were not overridden.
+ lastBounds?.let { bounds ->
+ view.left = bounds.left
+ view.top = bounds.top
+ view.right = bounds.right
+ view.bottom = bounds.bottom
+ }
+ return
+ }
+
+ if (lastBounds == null) {
+ lastBounds = Rect(oldLeft, oldTop, oldRight, oldBottom)
+ }
+
+ val bounds = lastBounds!!
+ val startLeft = bounds.left
+ val startTop = bounds.top
+ val startRight = bounds.right
+ val startBottom = bounds.bottom
+
+ currentAnimator?.cancel()
+ currentAnimator = null
+
+ val animator = ValueAnimator.ofFloat(0f, 1f).apply {
+ duration = ANIMATION_DURATION
+ interpolator = Interpolators.STANDARD
+
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ currentAnimator = null
+ }
+ })
+
+ addUpdateListener { animatedValue ->
+ val progress = animatedValue.animatedFraction
+
+ // Compute new bounds.
+ bounds.left = MathUtils.lerp(startLeft, left, progress).roundToInt()
+ bounds.top = MathUtils.lerp(startTop, top, progress).roundToInt()
+ bounds.right = MathUtils.lerp(startRight, right, progress).roundToInt()
+ bounds.bottom = MathUtils.lerp(startBottom, bottom, progress).roundToInt()
+
+ // Set the new bounds.
+ view.left = bounds.left
+ view.top = bounds.top
+ view.right = bounds.right
+ view.bottom = bounds.bottom
+ }
+ }
+
+ currentAnimator = animator
+ animator.start()
}
- decorView.alpha = alpha
}
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt
new file mode 100644
index 000000000000..80a3eb839940
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.animation
+
+/** A view that can expand/launch into an app or a dialog. */
+interface LaunchableView {
+ /**
+ * Set whether this view should block/prevent all visibility changes. This ensures that this
+ * view remains invisible during the launch animation given that it is ghosted and already drawn
+ * somewhere else.
+ *
+ * Note that when this is set to true, both the [normal][android.view.View.setVisibility] and
+ * [transition][android.view.View.setTransitionVisibility] visibility changes must be blocked.
+ */
+ fun setShouldBlockVisibilityChanges(block: Boolean)
+} \ No newline at end of file
diff --git a/packages/SystemUI/docs/plugins.md b/packages/SystemUI/docs/plugins.md
index 689200577aad..378cba5155ab 100644
--- a/packages/SystemUI/docs/plugins.md
+++ b/packages/SystemUI/docs/plugins.md
@@ -1,3 +1,4 @@
+
# SystemUI Plugins
Plugins provide an easy way to rapidly prototype SystemUI features.  Plugins are APKs that will be installable only on Build.IS_DEBUGGABLE (dogfood) builds, that can change the behavior of SystemUI at runtime.  This is done by creating a basic set of interfaces that the plugins can expect to be in SysUI, then the portion of code controlled by the interface can be iterated on faster than currently.
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
index 1844288796cc..0b3eccfd3a91 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
@@ -85,9 +85,10 @@ public class ColorScheme(@ColorInt seed: Int, val darkTheme: Boolean) {
val camSeed = Cam.fromInt(seedArgb)
val hue = camSeed.hue
val chroma = camSeed.chroma.coerceAtLeast(ACCENT1_CHROMA)
+ val tertiaryHue = wrapDegrees((hue + ACCENT3_HUE_SHIFT).toInt())
accent1 = Shades.of(hue, chroma).toList()
accent2 = Shades.of(hue, ACCENT2_CHROMA).toList()
- accent3 = Shades.of(hue + ACCENT3_HUE_SHIFT, ACCENT3_CHROMA).toList()
+ accent3 = Shades.of(tertiaryHue.toFloat(), ACCENT3_CHROMA).toList()
neutral1 = Shades.of(hue, NEUTRAL1_CHROMA).toList()
neutral2 = Shades.of(hue, NEUTRAL2_CHROMA).toList()
}
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
index 989010e8730c..a16f5cd5d930 100644
--- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
@@ -123,18 +123,18 @@ public interface BcSmartspaceDataPlugin extends Plugin {
/** Interface for launching Intents, which can differ on the lockscreen */
interface IntentStarter {
- default void startFromAction(SmartspaceAction action, View v) {
+ default void startFromAction(SmartspaceAction action, View v, boolean showOnLockscreen) {
if (action.getIntent() != null) {
- startIntent(v, action.getIntent());
+ startIntent(v, action.getIntent(), showOnLockscreen);
} else if (action.getPendingIntent() != null) {
- startPendingIntent(action.getPendingIntent());
+ startPendingIntent(action.getPendingIntent(), showOnLockscreen);
}
}
/** Start the intent */
- void startIntent(View v, Intent i);
+ void startIntent(View v, Intent i, boolean showOnLockscreen);
/** Start the PendingIntent */
- void startPendingIntent(PendingIntent pi);
+ void startPendingIntent(PendingIntent pi, boolean showOnLockscreen);
}
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/flags/Flag.kt b/packages/SystemUI/plugin/src/com/android/systemui/flags/Flag.kt
deleted file mode 100644
index 68834bc2aa23..000000000000
--- a/packages/SystemUI/plugin/src/com/android/systemui/flags/Flag.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.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/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index 757dc2ec807d..b83ea4acd26f 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -55,13 +55,14 @@ public interface QS extends FragmentBase {
/**
* Asks QS to update its presentation, according to {@code NotificationPanelViewController}.
- *
* @param qsExpansionFraction How much each UI element in QS should be expanded (QQS to QS.)
* @param panelExpansionFraction Whats the expansion of the whole shade.
* @param headerTranslation How much we should vertically translate QS.
+ * @param squishinessFraction Fraction that affects tile height. 0 when collapsed,
+ * 1 when expanded.
*/
void setQsExpansion(float qsExpansionFraction, float panelExpansionFraction,
- float headerTranslation);
+ float headerTranslation, float squishinessFraction);
void setHeaderListening(boolean listening);
void notifyCustomizeChanged();
void setContainerController(QSContainerController controller);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
index 883f4de1149c..94fdbae83253 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
@@ -183,12 +183,6 @@ public interface NotificationMenuRowPlugin extends Plugin {
public boolean canBeDismissed();
/**
- * Informs the menu whether dismiss gestures are left-to-right or right-to-left.
- */
- default void setDismissRtl(boolean dismissRtl) {
- }
-
- /**
* Determines whether the menu should remain open given its current state, or snap closed.
* @return true if the menu should remain open, false otherwise.
*/
diff --git a/packages/SystemUI/res-keyguard/drawable/bubble_manage_user_education_bg.xml b/packages/SystemUI/res-keyguard/drawable/bubble_manage_user_education_bg.xml
deleted file mode 100644
index 64db25b65a0b..000000000000
--- a/packages/SystemUI/res-keyguard/drawable/bubble_manage_user_education_bg.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="?android:attr/colorAccent"/>
- <corners
- android:radius="?android:attr/dialogCornerRadius" />
-</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/drawable/circle_white.xml b/packages/SystemUI/res-keyguard/drawable/circle_white.xml
deleted file mode 100644
index d1b20979c29e..000000000000
--- a/packages/SystemUI/res-keyguard/drawable/circle_white.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="oval">
- <solid android:color="#33FFFFFF" />
-</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/drawable/face_auth_wallpaper.png b/packages/SystemUI/res-keyguard/drawable/face_auth_wallpaper.png
deleted file mode 100644
index b907f4eaf362..000000000000
--- a/packages/SystemUI/res-keyguard/drawable/face_auth_wallpaper.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/drawable/ic_done_black_24dp.xml b/packages/SystemUI/res-keyguard/drawable/ic_done_black_24dp.xml
deleted file mode 100644
index 5026f07de912..000000000000
--- a/packages/SystemUI/res-keyguard/drawable/ic_done_black_24dp.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
- ~ Copyright (C) 2017 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M9,16.2l-3.5,-3.5a0.984,0.984 0,0 0,-1.4 0,0.984 0.984,0 0,0 0,1.4l4.19,4.19c0.39,0.39 1.02,0.39 1.41,0L20.3,7.7a0.984,0.984 0,0 0,0 -1.4,0.984 0.984,0 0,0 -1.4,0L9,16.2z"/>
-</vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/ripple_drawable_pin.xml b/packages/SystemUI/res-keyguard/drawable/ripple_drawable_pin.xml
deleted file mode 100644
index 51c442abf2fd..000000000000
--- a/packages/SystemUI/res-keyguard/drawable/ripple_drawable_pin.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="?android:attr/colorControlHighlight"
- android:radius="40dp"/>
diff --git a/packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml b/packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml
index 7f0f68f4fc06..c58e2e3266d0 100644
--- a/packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml
+++ b/packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml
@@ -37,7 +37,7 @@
android:id="@+id/locked_fp"
android:state_middle="true"
android:state_single="false"
- android:drawable="@drawable/ic_fingerprint" />
+ android:drawable="@drawable/ic_kg_fingerprint" />
<item
android:id="@+id/unlocked"
diff --git a/packages/SystemUI/res-keyguard/values-land/integers.xml b/packages/SystemUI/res-keyguard/values-land/integers.xml
deleted file mode 100644
index 0739c3a1cf5a..000000000000
--- a/packages/SystemUI/res-keyguard/values-land/integers.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<resources>
- <!-- Gravity to make KeyguardSelectorView work in multiple orientations
- 0x13 == "left|center_vertical" -->
- <integer name="kg_selector_gravity">0x13</integer>
-</resources>
diff --git a/packages/SystemUI/res-keyguard/values-port/bools.xml b/packages/SystemUI/res-keyguard/values-port/bools.xml
deleted file mode 100644
index fdb8ebcff970..000000000000
--- a/packages/SystemUI/res-keyguard/values-port/bools.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<resources>
- <bool name="kg_sim_puk_account_full_screen">true</bool>
-</resources>
diff --git a/packages/SystemUI/res-keyguard/values-port/integers.xml b/packages/SystemUI/res-keyguard/values-port/integers.xml
deleted file mode 100644
index ef7e4da0cc26..000000000000
--- a/packages/SystemUI/res-keyguard/values-port/integers.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<resources>
- <!-- Gravity to make KeyguardSelectorView work in multiple orientations
- 0x31 == "top|center_horizontal" -->
- <integer name="kg_selector_gravity">0x31</integer>
-</resources> \ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/values-sw600dp-land/dimens.xml b/packages/SystemUI/res-keyguard/values-sw600dp-land/dimens.xml
index d816b3a461cd..17765b51c325 100644
--- a/packages/SystemUI/res-keyguard/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw600dp-land/dimens.xml
@@ -23,6 +23,6 @@
<dimen name="widget_big_font_size">88dp</dimen>
<dimen name="qs_header_system_icons_area_height">0dp</dimen>
- <dimen name="qs_panel_padding_top">0dp</dimen>
+ <dimen name="qs_panel_padding_top">@dimen/qqs_layout_margin_top</dimen>
</resources> \ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/values-sw600dp/bools.xml b/packages/SystemUI/res-keyguard/values-sw600dp/bools.xml
deleted file mode 100644
index 654821ade8dc..000000000000
--- a/packages/SystemUI/res-keyguard/values-sw600dp/bools.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<resources>
- <bool name="kg_sim_puk_account_full_screen">false</bool>
-</resources>
diff --git a/packages/SystemUI/res-keyguard/values/alias.xml b/packages/SystemUI/res-keyguard/values/alias.xml
index 6d49b1f511ee..1e1d29a34970 100644
--- a/packages/SystemUI/res-keyguard/values/alias.xml
+++ b/packages/SystemUI/res-keyguard/values/alias.xml
@@ -28,9 +28,6 @@
<!-- Alias used to reference framework configuration for screen rotation. -->
<item type="bool" name="config_enableLockScreenRotation">@*android:bool/config_enableLockScreenRotation</item>
- <!-- Alias used to reference framework activity duration. -->
- <item type="integer" name="config_activityDefaultDur">@*android:integer/config_activityDefaultDur</item>
-
<!-- Alias used to reference one of two possible layouts in keyguard. -->
<item type="layout" name="keyguard_eca">@layout/keyguard_emergency_carrier_area</item>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values/colors.xml b/packages/SystemUI/res-keyguard/values/colors.xml
index 74ee7ffad3f6..7a849ebd481d 100644
--- a/packages/SystemUI/res-keyguard/values/colors.xml
+++ b/packages/SystemUI/res-keyguard/values/colors.xml
@@ -19,6 +19,4 @@
<color name="bubbleHourHandColor">#C97343</color>
<!-- Default color for minute hand of Bubble clock. -->
<color name="bubbleMinuteHandColor">#F5C983</color>
- <!-- Accent color for Typographic clock. -->
- <color name="typeClockAccentColor">#F5C983</color>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index e854b027e074..89dd741e2898 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -31,7 +31,6 @@
<!-- Max Height of the sliding KeyguardSecurityContainer
(includes 2x keyguard_security_view_top_margin) -->
- <dimen name="keyguard_security_max_height">450dp</dimen>
<!-- pin/password field max height -->
<dimen name="keyguard_password_height">80dp</dimen>
@@ -57,7 +56,6 @@
<!-- Clock without header -->
<dimen name="widget_big_font_size">54dp</dimen>
<dimen name="bottom_text_spacing_digital">0dp</dimen>
- <dimen name="title_clock_padding">4dp</dimen>
<!-- Clock with header -->
<dimen name="widget_small_font_size">@dimen/widget_title_font_size</dimen>
<dimen name="widget_vertical_padding">5dp</dimen>
@@ -68,10 +66,8 @@
<dimen name="widget_icon_size">18dp</dimen>
<dimen name="widget_icon_padding">8dp</dimen>
<!-- Notification shelf padding when dark -->
- <dimen name="widget_bottom_separator_padding">-6dp</dimen>
<!-- The y translation to apply at the start in appear animations. -->
- <dimen name="appear_y_translation_start">32dp</dimen>
<!-- The size of the dots in the PIN unlock method. -->
<dimen name="password_dot_size">9dp</dimen>
@@ -82,7 +78,6 @@
<dimen name="password_char_padding">8dp</dimen>
<!-- The vertical margin between the date and the owner info. -->
- <dimen name="date_owner_info_margin">4dp</dimen>
<!-- The translation for disappearing security views after having solved them. -->
<dimen name="disappear_y_translation">-32dp</dimen>
diff --git a/packages/SystemUI/res-keyguard/values/donottranslate.xml b/packages/SystemUI/res-keyguard/values/donottranslate.xml
index 052d329ee63c..e677797dc4a7 100644
--- a/packages/SystemUI/res-keyguard/values/donottranslate.xml
+++ b/packages/SystemUI/res-keyguard/values/donottranslate.xml
@@ -16,7 +16,6 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Skeleton string format for displaying the date. -->
- <string name="abbrev_wday_month_day_no_year">EEEEMMMMd</string>
<!-- Skeleton string format for displaying the date when an alarm is set. -->
<string name="abbrev_wday_month_day_no_year_alarm">EEEMMMd</string>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 20ff424068b7..4fc38a813e8a 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -18,32 +18,6 @@
*/
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- App label in the manifest -->
- <string name="app_name">Keyguard</string>
- <!-- Instructions telling the user to enter their SIM PIN to unlock the keyguard.
- Displayed in one line in a large font. -->
- <string name="keyguard_password_enter_pin_code">Type PIN code</string>
-
- <!-- Instructions telling the user to enter their SIM PUK to unlock the keyguard.
- Displayed in one line in a large font. -->
- <string name="keyguard_password_enter_puk_code">Type SIM PUK and new PIN code</string>
-
- <!-- Prompt to enter SIM PUK in Edit Text Box in unlock screen -->
- <string name="keyguard_password_enter_puk_prompt">SIM PUK code</string>
- <!-- Prompt to enter New SIM PIN in Edit Text Box in unlock screen -->
- <string name="keyguard_password_enter_pin_prompt">New SIM PIN code</string>
-
- <!-- Displayed as hint in passwordEntry EditText on PasswordUnlockScreen [CHAR LIMIT=30]-->
- <string name="keyguard_password_entry_touch_hint"><font size="17">Touch to type password</font></string>
-
- <!-- Instructions telling the user to enter their text password to unlock the keyguard.
- Displayed in one line in a large font. -->
- <string name="keyguard_password_enter_password_code">Type password to unlock</string>
-
- <!-- Instructions telling the user to enter their PIN password to unlock the keyguard.
- Displayed in one line in a large font. -->
- <string name="keyguard_password_enter_pin_password_code">Type PIN to unlock</string>
-
<!-- Instructions telling the user to enter their PIN password to unlock the keyguard [CHAR LIMIT=30] -->
<string name="keyguard_enter_your_pin">Enter your PIN</string>
@@ -53,10 +27,6 @@
<!-- Instructions telling the user to enter their text password to unlock the keyguard [CHAR LIMIT=30] -->
<string name="keyguard_enter_your_password">Enter your password</string>
- <!-- Instructions telling the user that they entered the wrong pin while trying
- to unlock the keyguard. Displayed in one line in a large font. -->
- <string name="keyguard_password_wrong_pin_code">Incorrect PIN code.</string>
-
<!-- Shown in the lock screen when there is SIM card IO error. -->
<string name="keyguard_sim_error_message_short">Invalid Card.</string>
@@ -82,10 +52,6 @@
<!-- When the lock screen is showing and the phone plugged in, and the defend mode is triggered, say that charging is temporarily limited. -->
<string name="keyguard_plugged_in_charging_limited"><xliff:g id="percentage">%s</xliff:g> • Charging temporarily limited</string>
- <!-- When the lock screen is showing and the battery is low, warn user to plug
- in the phone soon. -->
- <string name="keyguard_low_battery">Connect your charger.</string>
-
<!-- On the keyguard screen, when pattern lock is disabled, only tell them to press menu to unlock. This is shown in small font at the bottom. -->
<string name="keyguard_instructions_when_pattern_disabled">Press Menu to unlock.</string>
@@ -132,9 +98,6 @@
<!-- Accessibility description of the SIM PUK password view. [CHAR_LIMIT=none] -->
<string name="keyguard_accessibility_sim_puk_area">SIM PUK area</string>
- <!-- Accessibility description for the text view that indicates when the next alarm is set (not shown on screen). [CHAR_LIMIT=none] -->
- <string name="keyguard_accessibility_next_alarm">Next alarm set for <xliff:g id="alarm" example="Fri 8:30 AM">%1$s</xliff:g></string>
-
<!-- KeyguardPinView - accessibility support --><skip />
<!-- Description of the Delete button in a KeyboardView. [CHAR LIMIT=NONE] -->
<string name="keyboardview_keycode_delete">Delete</string>
@@ -147,8 +110,6 @@
<!-- Description of the Enter button in a KeyboardView. [CHAR LIMIT=NONE] -->
<string name="keyboardview_keycode_enter">Enter</string>
- <!-- Message shown in pattern unlock after some number of unsuccessful attempts -->
- <string name="kg_forgot_pattern_button_text">Forgot Pattern</string>
<!-- Message shown when user enters wrong pattern -->
<string name="kg_wrong_pattern">Wrong pattern</string>
<!-- Message shown when user enters wrong password -->
@@ -160,18 +121,12 @@
<item quantity="one">Try again in 1 second.</item>
<item quantity="other">Try again in <xliff:g id="number">%d</xliff:g> seconds.</item>
</plurals>
- <!-- Instructions for using the pattern unlock screen -->
- <string name="kg_pattern_instructions">Draw your pattern</string>
<!-- Instructions for using the SIM PIN unlock screen -->
<string name="kg_sim_pin_instructions">Enter SIM PIN.</string>
<!-- Instructions for using the SIM PIN unlock screen when there's more than one SIM -->
<string name="kg_sim_pin_instructions_multi">Enter SIM PIN for \"<xliff:g id="carrier" example="CARD 1">%1$s</xliff:g>\".</string>
<!-- Instructions for disabling eSIM carrier to unlock the phone with embedded SIM. This message follows the original SIM PIN/PUK message of device without embedded SIM. -->
<string name="kg_sim_lock_esim_instructions"><xliff:g id="previous_msg" example="Enter SIM PIN.">%1$s</xliff:g> Disable eSIM to use device without mobile service.</string>
- <!-- Instructions for using the PIN unlock screen -->
- <string name="kg_pin_instructions">Enter PIN</string>
- <!-- Instructions for using the password unlock screen -->
- <string name="kg_password_instructions">Enter Password</string>
<!-- Hint shown in the PUK screen that asks the user to enter the PUK code given to them by their provider -->
<string name="kg_puk_enter_puk_hint">SIM is now disabled. Enter PUK code to continue. Contact carrier for details.</string>
<!-- Hint shown when there are multiple SIMs in the device to ask the user to enter the PUK code given to them by their provider -->
@@ -186,10 +141,6 @@
<string name="kg_invalid_sim_pin_hint">Type a PIN that is 4 to 8 numbers.</string>
<!-- Message shown when the user enters an invalid PUK code in the PUK screen -->
<string name="kg_invalid_sim_puk_hint">PUK code should be 8 numbers or more.</string>
- <!-- Message shown when the user enters an invalid PUK code -->
- <string name="kg_invalid_puk">Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM.</string>
- <!-- Message shown when the user exceeds the maximum number of pattern attempts -->
- <string name="kg_login_too_many_attempts">Too many pattern attempts</string>
<!-- Message shown in dialog when max number of attempts are reached for PIN screen of keyguard -->
<string name="kg_too_many_failed_pin_attempts_dialog_message">
You have incorrectly typed your PIN <xliff:g id="number">%1$d</xliff:g> times.
@@ -230,13 +181,6 @@
<!-- Instructions telling the user that the operation to unlock the keyguard
with PUK failed. Displayed in one line in a large font. -->
<string name="kg_password_puk_failed">SIM PUK operation failed!</string>
- <!-- Notification telling the user that the PIN1 they entered is valid -->
- <string name="kg_pin_accepted">Code Accepted!</string>
-
- <!-- On the keyguard screen, it shows the carrier the phone is connected to.
- This is displayed if the phone is not connected to a carrier.-->
- <string name="keyguard_carrier_default">No service.</string>
-
<!-- Content description of the switch input method button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">Switch input method</string>
@@ -261,15 +205,6 @@
<!-- An explanation text that the password needs to be entered since the user hasn't used strong authentication since quite some time. [CHAR LIMIT=80] -->
<string name="kg_prompt_reason_timeout_password">Password required for additional security</string>
- <!-- An explanation text that the pattern needs to be solved since profiles have just been switched. [CHAR LIMIT=80] -->
- <string name="kg_prompt_reason_switch_profiles_pattern">Pattern required when you switch profiles</string>
-
- <!-- An explanation text that the pin needs to be entered since profiles have just been switched. [CHAR LIMIT=80] -->
- <string name="kg_prompt_reason_switch_profiles_pin">PIN required when you switch profiles</string>
-
- <!-- An explanation text that the password needs to be entered since profiles have just been switched. [CHAR LIMIT=80] -->
- <string name="kg_prompt_reason_switch_profiles_password">Password required when you switch profiles</string>
-
<!-- An explanation text that the credential needs to be entered because a device admin has
locked the device. [CHAR LIMIT=80] -->
<string name="kg_prompt_reason_device_admin">Device locked by admin</string>
@@ -278,24 +213,6 @@
the force lock button. [CHAR LIMIT=80] -->
<string name="kg_prompt_reason_user_request">Device was locked manually</string>
- <!-- An explanation text that the pattern needs to be solved since it hasn't been solved in a while. [CHAR LIMIT=80]-->
- <plurals name="kg_prompt_reason_time_pattern">
- <item quantity="one">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hour. Confirm pattern.</item>
- <item quantity="other">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hours. Confirm pattern.</item>
- </plurals>
-
- <!-- An explanation text that the pin needs to be entered since it hasn't been entered in a while. [CHAR LIMIT=80]-->
- <plurals name="kg_prompt_reason_time_pin">
- <item quantity="one">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hour. Confirm PIN.</item>
- <item quantity="other">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hours. Confirm PIN.</item>
- </plurals>
-
- <!-- An explanation text that the password needs to be entered since it hasn't been entered in a while. [CHAR LIMIT=80]-->
- <plurals name="kg_prompt_reason_time_password">
- <item quantity="one">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hour. Confirm password.</item>
- <item quantity="other">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hours. Confirm password.</item>
- </plurals>
-
<!-- Fingerprint hint message when finger was not recognized.-->
<string name="kg_fingerprint_not_recognized">Not recognized</string>
@@ -324,5 +241,4 @@ number">%d</xliff:g> remaining attempts before SIM becomes permanently unusable.
<string name="clock_title_bubble">Bubble</string>
<!-- Name of the "Analog" clock face [CHAR LIMIT=15]-->
<string name="clock_title_analog">Analog</string>
-
</resources>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 6e89fb0169ab..b0bdc72f986a 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -75,9 +75,6 @@
</style>
<!-- Built-in clock widget stuff -->
- <style name="widget_label">
- <item name="android:textSize">@dimen/widget_label_font_size</item>
- </style>
<style name="widget_big">
<item name="android:textSize">@dimen/widget_big_font_size</item>
<item name="android:paddingBottom">@dimen/bottom_text_spacing_digital</item>
@@ -87,15 +84,7 @@
<item name="android:shadowColor">@color/keyguard_shadow_color</item>
<item name="android:shadowRadius">?attr/shadowRadius</item>
</style>
- <style name="widget_title_bold">
- <item name="android:textStyle">bold</item>
- <item name="android:textSize">@dimen/widget_title_font_size</item>
- <item name="android:paddingBottom">@dimen/widget_vertical_padding_clock</item>
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:ellipsize">none</item>
- <item name="android:shadowColor">@color/keyguard_shadow_color</item>
- <item name="android:shadowRadius">?attr/shadowRadius</item>
- </style>
+
<style name="widget_small_bold">
<item name="android:textStyle">bold</item>
<item name="android:textSize">@dimen/widget_small_font_size</item>
diff --git a/packages/SystemUI/res/anim/bottomsheet_in.xml b/packages/SystemUI/res/anim/bottomsheet_in.xml
deleted file mode 100644
index 0d5efeb2be1e..000000000000
--- a/packages/SystemUI/res/anim/bottomsheet_in.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@*android:anim/accelerate_decelerate_interpolator"
- android:zAdjustment="top">
-
- <translate android:fromYDelta="100%"
- android:toYDelta="0"
- android:startOffset="@android:integer/config_shortAnimTime"
- android:duration="@*android:integer/config_mediumAnimTime"/>
-</set>
diff --git a/packages/SystemUI/res/anim/bottomsheet_out.xml b/packages/SystemUI/res/anim/bottomsheet_out.xml
deleted file mode 100644
index 01f8d2d6b2a3..000000000000
--- a/packages/SystemUI/res/anim/bottomsheet_out.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@*android:anim/accelerate_interpolator"
- android:zAdjustment="top">
-
- <translate xmlns:android="http://schemas.android.com/apk/res/android"
- android:fromYDelta="0"
- android:toYDelta="100%"
- android:duration="@*android:integer/config_shortAnimTime" />
-</set>
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_focus_gain_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_focus_gain_animation.xml
deleted file mode 100644
index 257bf35c8e76..000000000000
--- a/packages/SystemUI/res/anim/tv_pip_controls_focus_gain_animation.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
- android:propertyName="alpha"
- android:valueTo="1"
- android:interpolator="@android:interpolator/fast_out_slow_in"
- android:duration="100" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_focus_loss_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_focus_loss_animation.xml
deleted file mode 100644
index e032008b3750..000000000000
--- a/packages/SystemUI/res/anim/tv_pip_controls_focus_loss_animation.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
- android:propertyName="alpha"
- android:valueTo="0"
- android:interpolator="@android:interpolator/fast_out_slow_in"
- android:duration="100" />
diff --git a/packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml b/packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml
deleted file mode 100644
index 257bf35c8e76..000000000000
--- a/packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
- android:propertyName="alpha"
- android:valueTo="1"
- android:interpolator="@android:interpolator/fast_out_slow_in"
- android:duration="100" />
diff --git a/packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml b/packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml
deleted file mode 100644
index e032008b3750..000000000000
--- a/packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
- android:propertyName="alpha"
- android:valueTo="0"
- android:interpolator="@android:interpolator/fast_out_slow_in"
- android:duration="100" />
diff --git a/packages/SystemUI/res/color/docked_divider_background.xml b/packages/SystemUI/res/color/docked_divider_background.xml
deleted file mode 100644
index 2ab8ecdec936..000000000000
--- a/packages/SystemUI/res/color/docked_divider_background.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="@android:color/system_neutral1_500" android:lStar="35" />
-</selector>
diff --git a/packages/SystemUI/res/color/notification_guts_buttons.xml b/packages/SystemUI/res/color/notification_guts_buttons.xml
deleted file mode 100644
index 412e0be65cf7..000000000000
--- a/packages/SystemUI/res/color/notification_guts_buttons.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_checked="true"
- android:color="?android:attr/colorAccent" />
- <item android:color="@color/notification_primary_text_color"
- android:alpha=".54" />
-</selector> \ No newline at end of file
diff --git a/packages/SystemUI/res/color/pin_delete_color.xml b/packages/SystemUI/res/color/pin_delete_color.xml
deleted file mode 100644
index c1b4cf87e923..000000000000
--- a/packages/SystemUI/res/color/pin_delete_color.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2017 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:alpha="0.61" android:color="?android:attr/textColor" />
-</selector> \ No newline at end of file
diff --git a/packages/SystemUI/res/color/pin_divider_color.xml b/packages/SystemUI/res/color/pin_divider_color.xml
deleted file mode 100644
index e05772fab8b2..000000000000
--- a/packages/SystemUI/res/color/pin_divider_color.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2017 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:alpha="0.45" android:color="?android:attr/textColorSecondary" />
-</selector> \ No newline at end of file
diff --git a/packages/SystemUI/res/color/qs_user_detail_name.xml b/packages/SystemUI/res/color/qs_user_detail_name.xml
deleted file mode 100644
index e262209a82c3..000000000000
--- a/packages/SystemUI/res/color/qs_user_detail_name.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- ~ Copyright (C) 2014 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
- -->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_activated="true" android:color="?android:attr/colorAccent" />
- <item android:state_enabled="false" android:color="@color/qs_tile_disabled_color" />
- <item android:color="#66ffffff" /> <!-- 40% white -->
-</selector> \ No newline at end of file
diff --git a/packages/SystemUI/res/color/screenrecord_switch_thumb_color.xml b/packages/SystemUI/res/color/screenrecord_switch_thumb_color.xml
deleted file mode 100644
index 22b7a1e50dd6..000000000000
--- a/packages/SystemUI/res/color/screenrecord_switch_thumb_color.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <!-- Disabled status of thumb -->
- <item android:state_enabled="false"
- android:color="@android:color/system_neutral2_100" />
- <!-- Toggle off status of thumb -->
- <item android:state_checked="false"
- android:color="@android:color/system_neutral2_100" />
- <!-- Enabled or toggle on status of thumb -->
- <item android:color="@android:color/system_accent1_100" />
-</selector> \ No newline at end of file
diff --git a/packages/SystemUI/res/color/screenrecord_switch_track_color.xml b/packages/SystemUI/res/color/screenrecord_switch_track_color.xml
deleted file mode 100644
index bb55b07a6731..000000000000
--- a/packages/SystemUI/res/color/screenrecord_switch_track_color.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <!-- Disabled status of thumb -->
- <item android:state_enabled="false"
- android:color="@android:color/system_neutral2_600"
- android:alpha="?android:attr/disabledAlpha" />
- <!-- Toggle off status of thumb -->
- <item android:state_checked="false"
- android:color="@android:color/system_neutral2_600" />
- <!-- Enabled or toggle on status of thumb -->
- <item android:color="@android:color/system_accent1_600" />
-</selector> \ No newline at end of file
diff --git a/packages/SystemUI/res/color/settingslib_state_off.xml b/packages/SystemUI/res/color/settingslib_state_off.xml
deleted file mode 100644
index e8218259087d..000000000000
--- a/packages/SystemUI/res/color/settingslib_state_off.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
- <item android:color="?androidprv:attr/colorAccentSecondaryVariant"/>
-</selector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable-hdpi/pip_dismiss_scrim.9.png b/packages/SystemUI/res/drawable-hdpi/pip_dismiss_scrim.9.png
deleted file mode 100644
index 32f1ed79c993..000000000000
--- a/packages/SystemUI/res/drawable-hdpi/pip_dismiss_scrim.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/screenshot_panel.9.png b/packages/SystemUI/res/drawable-hdpi/screenshot_panel.9.png
deleted file mode 100644
index da56dcc99374..000000000000
--- a/packages/SystemUI/res/drawable-hdpi/screenshot_panel.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/search_bg_transparent.9.png b/packages/SystemUI/res/drawable-hdpi/search_bg_transparent.9.png
deleted file mode 100644
index 85db9c82cf20..000000000000
--- a/packages/SystemUI/res/drawable-hdpi/search_bg_transparent.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mcc310-mnc004/ic_5g_plus_mobiledata.xml b/packages/SystemUI/res/drawable-mcc310-mnc004/ic_5g_plus_mobiledata.xml
deleted file mode 100644
index 998db3b44b19..000000000000
--- a/packages/SystemUI/res/drawable-mcc310-mnc004/ic_5g_plus_mobiledata.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<!--
- Copyright (C) 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="22"
- android:viewportHeight="17"
- android:width="22dp"
- android:height="17dp">
- <group>
- <group>
- <path android:fillColor="#FF000000"
- android:pathData="M19.98,3.54v2.81c0,0.47 -0.15,0.84 -0.44,1.11s-0.69,0.41 -1.2,0.41c-0.5,0 -0.89,-0.13 -1.19,-0.4s-0.44,-0.63 -0.45,-1.09V3.54h0.88v2.82c0,0.28 0.07,0.48 0.2,0.61c0.13,0.13 0.32,0.19 0.56,0.19c0.49,0 0.75,-0.26 0.75,-0.78V3.54H19.98z"/>
- <path android:fillColor="#FF000000"
- android:pathData="M19.42,12.25l0.57,-3.04h0.88l-0.95,4.27h-0.88l-0.69,-2.85l-0.69,2.85h-0.88l-0.95,-4.27h0.88l0.58,3.03l0.7,-3.03h0.74L19.42,12.25z"/>
- </group>
- <group>
- <path android:fillColor="#FF000000"
- android:pathData="M0.94,8.49l0.43,-4.96H5.7v1.17H2.39L2.15,7.41c0.41,-0.29 0.85,-0.43 1.33,-0.43c0.77,0 1.38,0.3 1.83,0.9c0.44,0.6 0.66,1.41 0.66,2.43c0,1.03 -0.24,1.84 -0.72,2.43c-0.48,0.59 -1.14,0.88 -1.98,0.88c-0.75,0 -1.36,-0.24 -1.83,-0.73c-0.47,-0.49 -0.74,-1.16 -0.81,-2.02h1.13c0.07,0.57 0.23,1 0.49,1.29c0.26,0.29 0.59,0.43 1.01,0.43c0.47,0 0.84,-0.2 1.1,-0.61c0.26,-0.41 0.4,-0.96 0.4,-1.65c0,-0.65 -0.14,-1.18 -0.43,-1.59C4.05,8.32 3.67,8.11 3.19,8.11c-0.4,0 -0.72,0.1 -0.96,0.31L1.9,8.75L0.94,8.49z"/>
- </group>
- <path android:fillColor="#FF000000"
- android:pathData="M13.86,12.24l-0.22,0.27c-0.63,0.73 -1.55,1.1 -2.76,1.1c-1.08,0 -1.92,-0.36 -2.53,-1.07c-0.61,-0.71 -0.93,-1.72 -0.94,-3.02V7.56c0,-1.39 0.28,-2.44 0.84,-3.13c0.56,-0.7 1.39,-1.04 2.51,-1.04c0.95,0 1.69,0.26 2.22,0.79c0.54,0.53 0.83,1.28 0.89,2.26h-1.25c-0.05,-0.62 -0.22,-1.1 -0.52,-1.45c-0.29,-0.35 -0.74,-0.52 -1.34,-0.52c-0.72,0 -1.24,0.23 -1.57,0.7C8.85,5.63 8.68,6.37 8.66,7.4v2.03c0,1 0.19,1.77 0.57,2.31c0.38,0.54 0.93,0.8 1.65,0.8c0.67,0 1.19,-0.16 1.54,-0.49l0.18,-0.17V9.59h-1.82V8.52h3.07V12.24z"/>
- </group>
-</vector>
-
diff --git a/packages/SystemUI/res/drawable-mcc311-mnc480/ic_5g_plus_mobiledata.xml b/packages/SystemUI/res/drawable-mcc311-mnc480/ic_5g_plus_mobiledata.xml
deleted file mode 100644
index 998db3b44b19..000000000000
--- a/packages/SystemUI/res/drawable-mcc311-mnc480/ic_5g_plus_mobiledata.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<!--
- Copyright (C) 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="22"
- android:viewportHeight="17"
- android:width="22dp"
- android:height="17dp">
- <group>
- <group>
- <path android:fillColor="#FF000000"
- android:pathData="M19.98,3.54v2.81c0,0.47 -0.15,0.84 -0.44,1.11s-0.69,0.41 -1.2,0.41c-0.5,0 -0.89,-0.13 -1.19,-0.4s-0.44,-0.63 -0.45,-1.09V3.54h0.88v2.82c0,0.28 0.07,0.48 0.2,0.61c0.13,0.13 0.32,0.19 0.56,0.19c0.49,0 0.75,-0.26 0.75,-0.78V3.54H19.98z"/>
- <path android:fillColor="#FF000000"
- android:pathData="M19.42,12.25l0.57,-3.04h0.88l-0.95,4.27h-0.88l-0.69,-2.85l-0.69,2.85h-0.88l-0.95,-4.27h0.88l0.58,3.03l0.7,-3.03h0.74L19.42,12.25z"/>
- </group>
- <group>
- <path android:fillColor="#FF000000"
- android:pathData="M0.94,8.49l0.43,-4.96H5.7v1.17H2.39L2.15,7.41c0.41,-0.29 0.85,-0.43 1.33,-0.43c0.77,0 1.38,0.3 1.83,0.9c0.44,0.6 0.66,1.41 0.66,2.43c0,1.03 -0.24,1.84 -0.72,2.43c-0.48,0.59 -1.14,0.88 -1.98,0.88c-0.75,0 -1.36,-0.24 -1.83,-0.73c-0.47,-0.49 -0.74,-1.16 -0.81,-2.02h1.13c0.07,0.57 0.23,1 0.49,1.29c0.26,0.29 0.59,0.43 1.01,0.43c0.47,0 0.84,-0.2 1.1,-0.61c0.26,-0.41 0.4,-0.96 0.4,-1.65c0,-0.65 -0.14,-1.18 -0.43,-1.59C4.05,8.32 3.67,8.11 3.19,8.11c-0.4,0 -0.72,0.1 -0.96,0.31L1.9,8.75L0.94,8.49z"/>
- </group>
- <path android:fillColor="#FF000000"
- android:pathData="M13.86,12.24l-0.22,0.27c-0.63,0.73 -1.55,1.1 -2.76,1.1c-1.08,0 -1.92,-0.36 -2.53,-1.07c-0.61,-0.71 -0.93,-1.72 -0.94,-3.02V7.56c0,-1.39 0.28,-2.44 0.84,-3.13c0.56,-0.7 1.39,-1.04 2.51,-1.04c0.95,0 1.69,0.26 2.22,0.79c0.54,0.53 0.83,1.28 0.89,2.26h-1.25c-0.05,-0.62 -0.22,-1.1 -0.52,-1.45c-0.29,-0.35 -0.74,-0.52 -1.34,-0.52c-0.72,0 -1.24,0.23 -1.57,0.7C8.85,5.63 8.68,6.37 8.66,7.4v2.03c0,1 0.19,1.77 0.57,2.31c0.38,0.54 0.93,0.8 1.65,0.8c0.67,0 1.19,-0.16 1.54,-0.49l0.18,-0.17V9.59h-1.82V8.52h3.07V12.24z"/>
- </group>
-</vector>
-
diff --git a/packages/SystemUI/res/drawable-mdpi/one_handed_tutorial.png b/packages/SystemUI/res/drawable-mdpi/one_handed_tutorial.png
deleted file mode 100644
index 6983c3b880c9..000000000000
--- a/packages/SystemUI/res/drawable-mdpi/one_handed_tutorial.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/pip_dismiss_scrim.9.png b/packages/SystemUI/res/drawable-mdpi/pip_dismiss_scrim.9.png
deleted file mode 100644
index 33826a664951..000000000000
--- a/packages/SystemUI/res/drawable-mdpi/pip_dismiss_scrim.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/screenshot_panel.9.png b/packages/SystemUI/res/drawable-mdpi/screenshot_panel.9.png
deleted file mode 100644
index 295e91f47a3e..000000000000
--- a/packages/SystemUI/res/drawable-mdpi/screenshot_panel.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/search_bg_transparent.9.png b/packages/SystemUI/res/drawable-mdpi/search_bg_transparent.9.png
deleted file mode 100644
index c4941a637d41..000000000000
--- a/packages/SystemUI/res/drawable-mdpi/search_bg_transparent.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/android_11_dial.xml b/packages/SystemUI/res/drawable-nodpi/android_11_dial.xml
deleted file mode 100644
index 73fd37f1bdd6..000000000000
--- a/packages/SystemUI/res/drawable-nodpi/android_11_dial.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:aapt="http://schemas.android.com/aapt"
- android:width="108dp"
- android:height="108dp"
- android:viewportWidth="108"
- android:viewportHeight="108">
- <path
- android:pathData="M77.773,51.064h-1.583c-0.217,0 -0.393,-0.176 -0.393,-0.393v-1.46c0,-0.217 0.176,-0.393 0.393,-0.393h3.466c0.217,0 0.393,0.176 0.393,0.393v9.921c0,0.217 -0.176,0.393 -0.393,0.393h-1.49c-0.217,0 -0.393,-0.176 -0.393,-0.393V51.064z"
- android:fillColor="#F86734"/>
- <path
- android:pathData="M83.598,51.064h-1.583c-0.217,0 -0.393,-0.176 -0.393,-0.393v-1.46c0,-0.217 0.176,-0.393 0.393,-0.393h3.466c0.217,0 0.393,0.176 0.393,0.393v9.921c0,0.217 -0.176,0.393 -0.393,0.393h-1.49c-0.217,0 -0.393,-0.176 -0.393,-0.393V51.064z"
- android:fillColor="#F86734"/>
- <path
- android:pathData="M70.044,75.974m-0.644,0a0.644,0.644 0,1 1,1.288 0a0.644,0.644 0,1 1,-1.288 0"
- android:fillColor="#d7effe"/>
- <path
- android:pathData="M56.896,80.985m-0.718,0a0.718,0.718 0,1 1,1.436 0a0.718,0.718 0,1 1,-1.436 0"
- android:fillColor="#d7effe"/>
- <path
- android:pathData="M43.408,78.881m-0.795,0a0.795,0.795 0,1 1,1.59 0a0.795,0.795 0,1 1,-1.59 0"
- android:fillColor="#d7effe"/>
- <path
- android:pathData="M32.419,70.115m-0.874,0a0.874,0.874 0,1 1,1.748 0a0.874,0.874 0,1 1,-1.748 0"
- android:fillColor="#d7effe"/>
- <path
- android:pathData="M27.306,56.992m-0.954,0a0.954,0.954 0,1 1,1.908 0a0.954,0.954 0,1 1,-1.908 0"
- android:fillColor="#d7effe"/>
- <path
- android:pathData="M29.313,43.489m-1.036,0a1.036,1.036 0,1 1,2.072 0a1.036,1.036 0,1 1,-2.072 0"
- android:fillColor="#d7effe"/>
- <path
- android:pathData="M37.988,32.445m-1.118,0a1.118,1.118 0,1 1,2.236 0a1.118,1.118 0,1 1,-2.236 0"
- android:fillColor="#d7effe"/>
- <path
- android:pathData="M51.137,27.064m-1.201,0a1.201,1.201 0,1 1,2.402 0a1.201,1.201 0,1 1,-2.402 0"
- android:fillColor="#d7effe"/>
- <path
- android:pathData="M64.553,28.868m-1.284,0a1.284,1.284 0,1 1,2.568 0a1.284,1.284 0,1 1,-2.568 0"
- android:fillColor="#d7effe"/>
- <path
- android:pathData="M75.522,37.652m-1.368,0a1.368,1.368 0,1 1,2.736 0a1.368,1.368 0,1 1,-2.736 0"
- android:fillColor="#d7effe"/>
- <path
- android:pathData="M87.942,115.052l-47.557,-47.557l26.869,-26.87l47.557,47.558z">
- <aapt:attr name="android:fillColor">
- <gradient
- android:startY="56.087"
- android:startX="55.8464"
- android:endY="100.0297"
- android:endX="99.7891"
- android:type="linear">
- <item android:offset="0" android:color="#3F000000"/>
- <item android:offset="1" android:color="#00000000"/>
- </gradient>
- </aapt:attr>
- </path>
- <path
- android:pathData="M53.928,54.17m-18.999,0a18.999,18.999 0,1 1,37.998 0a18.999,18.999 0,1 1,-37.998 0"
- android:fillColor="#3ddc84"/>
- <path
- android:pathData="M66.353,54.17m-3.185,0a3.185,3.185 0,1 1,6.37 0a3.185,3.185 0,1 1,-6.37 0"
- android:fillColor="#FFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable-nodpi/work_challenge_background.png b/packages/SystemUI/res/drawable-nodpi/work_challenge_background.png
deleted file mode 100644
index 311f30bc1e6b..000000000000
--- a/packages/SystemUI/res/drawable-nodpi/work_challenge_background.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/one_handed_tutorial.png b/packages/SystemUI/res/drawable-xhdpi/one_handed_tutorial.png
deleted file mode 100644
index 3ff692f0c6fc..000000000000
--- a/packages/SystemUI/res/drawable-xhdpi/one_handed_tutorial.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/pip_dismiss_scrim.9.png b/packages/SystemUI/res/drawable-xhdpi/pip_dismiss_scrim.9.png
deleted file mode 100644
index c1157f4316cf..000000000000
--- a/packages/SystemUI/res/drawable-xhdpi/pip_dismiss_scrim.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote.png b/packages/SystemUI/res/drawable-xhdpi/remote.png
deleted file mode 100644
index c0ccfe694412..000000000000
--- a/packages/SystemUI/res/drawable-xhdpi/remote.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/search_bg_transparent.9.png b/packages/SystemUI/res/drawable-xhdpi/search_bg_transparent.9.png
deleted file mode 100644
index 4618f40f95ce..000000000000
--- a/packages/SystemUI/res/drawable-xhdpi/search_bg_transparent.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/one_handed_tutorial.png b/packages/SystemUI/res/drawable-xxhdpi/one_handed_tutorial.png
deleted file mode 100644
index 75723fb2ea5a..000000000000
--- a/packages/SystemUI/res/drawable-xxhdpi/one_handed_tutorial.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/pip_dismiss_scrim.9.png b/packages/SystemUI/res/drawable-xxhdpi/pip_dismiss_scrim.9.png
deleted file mode 100644
index 8d58a7e01b42..000000000000
--- a/packages/SystemUI/res/drawable-xxhdpi/pip_dismiss_scrim.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/search_bg_transparent.9.png b/packages/SystemUI/res/drawable-xxhdpi/search_bg_transparent.9.png
deleted file mode 100644
index c0bf31d02f30..000000000000
--- a/packages/SystemUI/res/drawable-xxhdpi/search_bg_transparent.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/one_handed_tutorial.png b/packages/SystemUI/res/drawable-xxxhdpi/one_handed_tutorial.png
deleted file mode 100644
index 173abedae48a..000000000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/one_handed_tutorial.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/pip_dismiss_scrim.9.png b/packages/SystemUI/res/drawable-xxxhdpi/pip_dismiss_scrim.9.png
deleted file mode 100644
index 6c04d1aaccea..000000000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/pip_dismiss_scrim.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/circle_blue_40dp.xml b/packages/SystemUI/res/drawable/circle_blue_40dp.xml
deleted file mode 100644
index 00d2c52deb9b..000000000000
--- a/packages/SystemUI/res/drawable/circle_blue_40dp.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="oval">
- <size android:height="40dp"
- android:width="40dp" />
- <solid android:color="#4285f4" />
- <stroke android:color="#f1f3f4" android:width="1dp" />
-</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/circle_white_40dp.xml b/packages/SystemUI/res/drawable/circle_white_40dp.xml
deleted file mode 100644
index bcb1640a73fb..000000000000
--- a/packages/SystemUI/res/drawable/circle_white_40dp.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="oval">
- <size android:height="40dp"
- android:width="40dp" />
- <solid android:color="#ffffff" />
- <stroke android:color="#f1f3f4" android:width="1dp" />
-</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml b/packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml
deleted file mode 100644
index 6a0695e817c7..000000000000
--- a/packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<transition xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@color/transparent" />
- <item android:drawable="@drawable/floating_dismiss_gradient" />
-</transition> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_add_to_home.xml b/packages/SystemUI/res/drawable/ic_add_to_home.xml
deleted file mode 100644
index 2b40c627be1d..000000000000
--- a/packages/SystemUI/res/drawable/ic_add_to_home.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
- Copyright (C) 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?attr/colorControlNormal">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18,1.01L8,1c-1.1,0 -2,0.9 -2,2v3h2V5h10v14H8v-1H6v3c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3c0,-1.1 -0.9,-1.99 -2,-1.99zM10,15h2V8H5v2h3.59L3,15.59 4.41,17 10,11.41V15z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_arrow_downward.xml b/packages/SystemUI/res/drawable/ic_arrow_downward.xml
deleted file mode 100644
index ddd075dd17cc..000000000000
--- a/packages/SystemUI/res/drawable/ic_arrow_downward.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?attr/colorControlNormal">
- <path
- android:pathData="M20,12l-1.41,-1.41L13,16.17V4h-2v12.17l-5.58,-5.59L4,12l8,8 8,-8z"
- android:fillColor="@android:color/white"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_camera.xml b/packages/SystemUI/res/drawable/ic_camera.xml
deleted file mode 100644
index b330875864d3..000000000000
--- a/packages/SystemUI/res/drawable/ic_camera.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="17dp"
- android:height="17dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFF"
- android:pathData="M20,5h-3.17L15,3H9L7.17,5H4C2.9,5 2,5.9 2,7v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V7C22,5.9 21.1,5 20,5zM20,19H4V7h16V19zM12,9c-2.21,0 -4,1.79 -4,4c0,2.21 1.79,4 4,4s4,-1.79 4,-4C16,10.79 14.21,9 12,9z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_cancel_24.xml b/packages/SystemUI/res/drawable/ic_cancel_24.xml
deleted file mode 100644
index 8ab28ddb680d..000000000000
--- a/packages/SystemUI/res/drawable/ic_cancel_24.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?attr/colorControlNormal">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM17,15.59L15.59,17 12,13.41 8.41,17 7,15.59 10.59,12 7,8.41 8.41,7 12,10.59 15.59,7 17,8.41 13.41,12 17,15.59z"/>
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_chevron_up.xml b/packages/SystemUI/res/drawable/ic_chevron_up.xml
deleted file mode 100644
index 835d0adbef58..000000000000
--- a/packages/SystemUI/res/drawable/ic_chevron_up.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_clear.xml b/packages/SystemUI/res/drawable/ic_clear.xml
deleted file mode 100644
index 5ee50d845457..000000000000
--- a/packages/SystemUI/res/drawable/ic_clear.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12 19,6.41z"
- android:fillColor="#FF000000"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_demote_conversation.xml b/packages/SystemUI/res/drawable/ic_demote_conversation.xml
deleted file mode 100644
index 5a881605f800..000000000000
--- a/packages/SystemUI/res/drawable/ic_demote_conversation.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
- Copyright (C) 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M20,2L4.83,2l2,2L20,4v12h-1.17l1.87,1.87c0.75,-0.29 1.3,-1.02 1.3,-1.87L22,4c0,-1.1 -0.9,-2 -2,-2zM6,12h2v2L6,14zM18,11L18,9h-6.17l2,2zM18,6h-8v1.17l0.83,0.83L18,8zM0.69,3.51l1.32,1.32L2,22l4,-4h9.17l5.31,5.31 1.41,-1.41L2.1,2.1 0.69,3.51zM6,16h-0.83l-0.59,0.59 -0.58,0.58L4,6.83l2,2L6,11h2.17l5,5L6,16z"/>
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_drag_handle.xml b/packages/SystemUI/res/drawable/ic_drag_handle.xml
deleted file mode 100644
index 9b319f1b6544..000000000000
--- a/packages/SystemUI/res/drawable/ic_drag_handle.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M20.0,9.0L4.0,9.0l0.0,2.0l16.0,0.0L20.0,9.0zM4.0,15.0l16.0,0.0l0.0,-2.0L4.0,13.0l0.0,2.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml b/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml
deleted file mode 100644
index 314a25a6d5b2..000000000000
--- a/packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_important.xml b/packages/SystemUI/res/drawable/ic_important.xml
deleted file mode 100644
index d7439e167dd4..000000000000
--- a/packages/SystemUI/res/drawable/ic_important.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?attr/colorControlNormal">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M4,18.99h11c0.67,0 1.27,-0.32 1.63,-0.83L21,12l-4.37,-6.16C16.27,5.33 15.67,5 15,5H4l5,7 -5,6.99z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_fingerprint.xml b/packages/SystemUI/res/drawable/ic_kg_fingerprint.xml
index 91d72a7902c0..91d72a7902c0 100644
--- a/packages/SystemUI/res/drawable/ic_fingerprint.xml
+++ b/packages/SystemUI/res/drawable/ic_kg_fingerprint.xml
diff --git a/packages/SystemUI/res/drawable/ic_notification_block.xml b/packages/SystemUI/res/drawable/ic_notification_block.xml
deleted file mode 100644
index 276907401d5a..000000000000
--- a/packages/SystemUI/res/drawable/ic_notification_block.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
-
- <path
- android:fillColor="#FF000000"
- android:pathData="M12.0,2.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0zM4.0,12.0c0.0,-4.42 3.58,-8.0 8.0,-8.0 1.85,0.0 3.5,0.63 4.9,1.69L5.69,16.9C4.63,15.55 4.0,13.85 4.0,12.0zm8.0,8.0c-1.85,0.0 -3.55,-0.63 -4.9,-1.69L18.31,7.1C19.37,8.45 20.0,10.15 20.0,12.0c0.0,4.42 -3.58,8.0 -8.0,8.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_notification_gentle.xml b/packages/SystemUI/res/drawable/ic_notification_gentle.xml
deleted file mode 100644
index de54b1040b03..000000000000
--- a/packages/SystemUI/res/drawable/ic_notification_gentle.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<!--
-Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:id="@+id/back">
- <shape android:shape="oval">
- <solid
- android:color="@color/notification_silence_color" />
- <size
- android:height="24dp"
- android:width="24dp"/>
- </shape>
- </item>
- <item
- android:id="@+id/fore"
- android:gravity="center">
- <vector
- android:width="13dp"
- android:height="13dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M15,14.5c-1.38,0 -2.5,-1.12 -2.5,-2.5c0,-0.28 -0.22,-0.5 -0.5,-0.5s-0.5,0.22 -0.5,0.5c0,1.38 -1.12,2.5 -2.5,2.5S6.5,13.38 6.5,12c0,-0.28 -0.22,-0.5 -0.5,-0.5c-0.24,0 -0.46,0.18 -0.49,0.42C5.41,12.55 4.89,13 4.27,13H2v-2h1.71C4.1,10.11 5,9.5 6,9.5c1.38,0 2.5,1.12 2.5,2.5c0,0.28 0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5c0,0.28 0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5c0,-1.38 1.12,-2.5 2.5,-2.5c1.02,0 1.91,0.6 2.29,1.5H22v2h-2.27c-0.62,0 -1.14,-0.45 -1.23,-1.08c-0.04,-0.24 -0.25,-0.42 -0.49,-0.42c-0.28,0 -0.5,0.22 -0.5,0.5C17.5,13.38 16.38,14.5 15,14.5z"/>
- </vector>
- </item>
-</layer-list>
diff --git a/packages/SystemUI/res/drawable/ic_notification_interruptive.xml b/packages/SystemUI/res/drawable/ic_notification_interruptive.xml
deleted file mode 100644
index f49aa4a198bd..000000000000
--- a/packages/SystemUI/res/drawable/ic_notification_interruptive.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<!--
-Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:id="@+id/back">
- <shape android:shape="oval">
- <solid
- android:color="@color/notification_alert_color" />
- <size
- android:height="24dp"
- android:width="24dp"/>
- </shape>
- </item>
- <item
- android:id="@+id/fore"
- android:gravity="center">
- <vector
- android:width="13dp"
- android:height="13dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M8.98,16.65c-0.47,0 -0.91,-0.27 -1.12,-0.69l-1.93,-4.61L5.46,12.3c-0.21,0.43 -0.64,0.69 -1.12,0.69H2v-2h1.88l1,-2C5.1,8.56 5.52,8.3 6,8.3s0.9,0.26 1.12,0.69l1.73,4.14l2,-7c0.2,-0.46 0.65,-0.76 1.15,-0.76s0.95,0.3 1.15,0.76l0.04,0.12l1.96,6.88l1.7,-4.08c0.49,-0.98 1.84,-0.91 2.26,-0.06l1,2H22v2h-2.35c-0.47,0 -0.91,-0.27 -1.12,-0.7l-0.47,-0.95l-1.9,4.55c-0.25,0.5 -0.69,0.77 -1.18,0.75c-0.48,-0.01 -0.92,-0.31 -1.11,-0.76l-0.04,-0.12L12,9.37l-1.87,6.52c-0.19,0.45 -0.63,0.74 -1.11,0.76C9.01,16.65 9,16.65 8.98,16.65zM20.32,11.4L20.32,11.4C20.32,11.4 20.32,11.4 20.32,11.4z" />
- </vector>
- </item>
-</layer-list>
diff --git a/packages/SystemUI/res/drawable/ic_pause_white.xml b/packages/SystemUI/res/drawable/ic_pause_white.xml
deleted file mode 100644
index 5b65f100490c..000000000000
--- a/packages/SystemUI/res/drawable/ic_pause_white.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_photo_camera.xml b/packages/SystemUI/res/drawable/ic_photo_camera.xml
deleted file mode 100644
index 63cd4e2e5cc4..000000000000
--- a/packages/SystemUI/res/drawable/ic_photo_camera.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M9,2L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2L9,2zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z"/>
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_play_arrow_white.xml b/packages/SystemUI/res/drawable/ic_play_arrow_white.xml
deleted file mode 100644
index ddc9e8dd17a0..000000000000
--- a/packages/SystemUI/res/drawable/ic_play_arrow_white.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M8 5v14l11-7z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_power_settings_new_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_power_settings_new_gm2_24px.xml
deleted file mode 100644
index f4edd875ddff..000000000000
--- a/packages/SystemUI/res/drawable/ic_power_settings_new_gm2_24px.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:fillColor="#FF000000"
- android:pathData="M11,2h2v10h-2zM18.37,5.64l-1.41,1.41c2.73,2.73 2.72,7.16 -0.01,9.89 -2.73,2.73 -7.17,2.73 -9.89,0.01 -2.73,-2.73 -2.74,-7.18 -0.01,-9.91l-1.41,-1.4c-3.51,3.51 -3.51,9.21 0.01,12.73 3.51,3.51 9.21,3.51 12.72,-0.01 3.51,-3.51 3.51,-9.2 0,-12.72z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
deleted file mode 100644
index 1c867064773c..000000000000
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 11,14.41L11,22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM13,5.83l1.88,1.88L13,9.59L13,5.83zM14.88,16.29L13,18.17v-3.76l1.88,1.88z"/>
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_qs_no_internet_airplane.xml b/packages/SystemUI/res/drawable/ic_qs_no_internet_airplane.xml
deleted file mode 100644
index 3d6ca7acda87..000000000000
--- a/packages/SystemUI/res/drawable/ic_qs_no_internet_airplane.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
- Copyright (C) 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10c0.34,0 0.68,-0.02 1.01,-0.05V20h-1v-0.04c-0.83,-1.2 -1.48,-2.53 -1.91,-3.96H13v-2H9.66c-0.09,-0.66 -0.16,-1.32 -0.16,-2s0.07,-1.35 0.16,-2H21.8C20.87,5.44 16.83,2 11.99,2zM18.92,8h-2.95c-0.32,-1.25 -0.78,-2.45 -1.38,-3.56C16.43,5.07 17.96,6.35 18.92,8zM12,4.04c0.83,1.2 1.48,2.53 1.91,3.96h-3.82C10.52,6.57 11.17,5.24 12,4.04zM4.26,14C4.1,13.36 4,12.69 4,12s0.1,-1.36 0.26,-2h3.38c-0.08,0.66 -0.14,1.32 -0.14,2s0.06,1.34 0.14,2H4.26zM5.08,16h2.95c0.32,1.25 0.78,2.45 1.38,3.56C7.57,18.93 6.04,17.66 5.08,16zM8.03,8H5.08c0.96,-1.66 2.49,-2.93 4.33,-3.56C8.81,5.55 8.35,6.75 8.03,8z"
- android:fillAlpha="0.3"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M22,19.3v-0.9l-3.37,-2.25v-2.47C18.63,13.3 18.35,13 18,13s-0.63,0.3 -0.63,0.68v2.47L14,18.4v0.9l3.37,-1.12v2.48l-0.84,0.68V22L18,21.55L19.47,22v-0.67l-0.84,-0.68v-2.48L22,19.3z"/>
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_qs_screenrecord.xml b/packages/SystemUI/res/drawable/ic_qs_screenrecord.xml
deleted file mode 100644
index 687c9c417fa6..000000000000
--- a/packages/SystemUI/res/drawable/ic_qs_screenrecord.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:fillColor="#FF000000"
- android:pathData="M18,10.48L18,6c0,-1.1 -0.9,-2 -2,-2L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2v-4.48l4,3.98v-11l-4,3.98zM16,9.69L16,18L4,18L4,6h12v3.69z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_0.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_0.xml
deleted file mode 100644
index 7cbc26f1faba..000000000000
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_0.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<!--
- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="25.50"
- android:viewportHeight="25.50">
- <group
- android:translateX="0.77"
- android:translateY="0.23" >
- <path
- android:pathData="M14,12h6.54l3.12,-3.89c0.39,-0.48 0.29,-1.19 -0.22,-1.54C21.67,5.36 17.55,3 12,3C6.44,3 2.33,5.36 0.56,6.57C0.05,6.92 -0.05,7.63 0.33,8.11L11.16,21.6c0.42,0.53 1.23,0.53 1.66,0L14,20.13V12z"
- android:fillAlpha="0.3"
- android:fillColor="#FFFFFF"/>
- <path
- android:pathData="M22.71,15.67l-1.83,1.83l1.83,1.83c0.38,0.38 0.38,1 0,1.38v0c-0.38,0.38 -1,0.39 -1.38,0l-1.83,-1.83l-1.83,1.83c-0.38,0.38 -1,0.38 -1.38,0l-0.01,-0.01c-0.38,-0.38 -0.38,-1 0,-1.38l1.83,-1.83l-1.82,-1.82c-0.38,-0.38 -0.38,-1 0,-1.38l0.01,-0.01c0.38,-0.38 1,-0.38 1.38,0l1.82,1.82l1.82,-1.82c0.38,-0.38 1,-0.38 1.38,0l0,0C23.09,14.67 23.09,15.29 22.71,15.67z"
- android:fillColor="#FFFFFF"/>
- </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_1.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_1.xml
deleted file mode 100644
index 694b0ddc127f..000000000000
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_1.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M22,16.41L20.59,15l-2.09,2.09L16.41,15L15,16.41l2.09,2.09L15,20.59L16.41,22l2.09,-2.08L20.59,22L22,20.59l-2.08,-2.09L22,16.41z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,2.01C7.25,2.01 2.97,4.09 0,7.4L7.582,16.625C7.582,16.627 7.58,16.629 7.58,16.631L11.99,22L12,22L13,20.789L13,17.641L13,13.119C12.68,13.039 12.34,13 12,13C10.601,13 9.351,13.64 8.531,14.639L2.699,7.539C5.269,5.279 8.58,4.01 12,4.01C15.42,4.01 18.731,5.279 21.301,7.539L16.811,13L19.4,13L24,7.4C21.03,4.09 16.75,2.01 12,2.01z"
- android:fillAlpha="0.3"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_2.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_2.xml
deleted file mode 100644
index dcb3fa82eb5d..000000000000
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_2.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M22,16.41L20.59,15l-2.09,2.09L16.41,15L15,16.41l2.09,2.09L15,20.59L16.41,22l2.09,-2.08L20.59,22L22,20.59l-2.08,-2.09L22,16.41z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,2C7.25,2 2.97,4.081 0,7.391L12,22L13,20.779L13,17.631L13,13L16.801,13L18,13L19.391,13L24,7.391C21.03,4.081 16.75,2 12,2zM12,4C14.747,4 17.423,4.819 19.701,6.313C20.259,6.678 20.795,7.085 21.301,7.529L17.389,12.287C16.029,10.868 14.119,9.99 12,9.99C9.88,9.99 7.969,10.869 6.609,12.289L2.699,7.529C5.269,5.269 8.58,4 12,4z"
- android:fillAlpha="0.3"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_3.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_3.xml
deleted file mode 100644
index d68a2f6fe426..000000000000
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_3.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M22,16.41L20.59,15l-2.09,2.09L16.41,15L15,16.41l2.09,2.09L15,20.59L16.41,22l2.09,-2.08L20.59,22L22,20.59l-2.08,-2.09L22,16.41z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,2C7.25,2 2.97,4.081 0,7.391L3.301,11.41L12,22L13,20.779L13,17.631L13,13L16.801,13L19.391,13L20.699,11.41C20.699,11.409 20.698,11.409 20.697,11.408L24,7.391C21.03,4.081 16.75,2 12,2zM12,4C15.42,4 18.731,5.269 21.301,7.529L19.35,9.9C17.43,8.1 14.86,6.99 12,6.99C9.14,6.99 6.57,8.1 4.65,9.9C4.65,9.901 4.649,9.902 4.648,9.902L2.699,7.529C5.269,5.269 8.58,4 12,4z"
- android:fillAlpha="0.3"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_4.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_4.xml
deleted file mode 100644
index 886cc3534322..000000000000
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_4.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,2C7.25,2 2.97,4.08 0,7.39L12,22l1,-1.22V13h6.39L24,7.39C21.03,4.08 16.75,2 12,2z"
- android:fillAlpha="0.3"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M22,16.41L20.59,15l-2.09,2.09L16.41,15L15,16.41l2.09,2.09L15,20.59L16.41,22l2.09,-2.08L20.59,22L22,20.59l-2.08,-2.09L22,16.41z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_settings_16dp.xml b/packages/SystemUI/res/drawable/ic_settings_16dp.xml
deleted file mode 100644
index 89764cff03e0..000000000000
--- a/packages/SystemUI/res/drawable/ic_settings_16dp.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="16dp"
- android:height="16dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M13.85,22.25h-3.7c-0.74,0 -1.36,-0.54 -1.45,-1.27l-0.27,-1.89c-0.27,-0.14 -0.53,-0.29 -0.79,-0.46l-1.8,0.72c-0.7,0.26 -1.47,-0.03 -1.81,-0.65L2.2,15.53c-0.35,-0.66 -0.2,-1.44 0.36,-1.88l1.53,-1.19c-0.01,-0.15 -0.02,-0.3 -0.02,-0.46c0,-0.15 0.01,-0.31 0.02,-0.46l-1.52,-1.19C1.98,9.9 1.83,9.09 2.2,8.47l1.85,-3.19c0.34,-0.62 1.11,-0.9 1.79,-0.63l1.81,0.73c0.26,-0.17 0.52,-0.32 0.78,-0.46l0.27,-1.91c0.09,-0.7 0.71,-1.25 1.44,-1.25h3.7c0.74,0 1.36,0.54 1.45,1.27l0.27,1.89c0.27,0.14 0.53,0.29 0.79,0.46l1.8,-0.72c0.71,-0.26 1.48,0.03 1.82,0.65l1.84,3.18c0.36,0.66 0.2,1.44 -0.36,1.88l-1.52,1.19c0.01,0.15 0.02,0.3 0.02,0.46s-0.01,0.31 -0.02,0.46l1.52,1.19c0.56,0.45 0.72,1.23 0.37,1.86l-1.86,3.22c-0.34,0.62 -1.11,0.9 -1.8,0.63l-1.8,-0.72c-0.26,0.17 -0.52,0.32 -0.78,0.46l-0.27,1.91C15.21,21.71 14.59,22.25 13.85,22.25zM13.32,20.72c0,0.01 0,0.01 0,0.02L13.32,20.72zM10.68,20.7l0,0.02C10.69,20.72 10.69,20.71 10.68,20.7zM10.62,20.25h2.76l0.37,-2.55l0.53,-0.22c0.44,-0.18 0.88,-0.44 1.34,-0.78l0.45,-0.34l2.38,0.96l1.38,-2.4l-2.03,-1.58l0.07,-0.56c0.03,-0.26 0.06,-0.51 0.06,-0.78c0,-0.27 -0.03,-0.53 -0.06,-0.78l-0.07,-0.56l2.03,-1.58l-1.39,-2.4l-2.39,0.96l-0.45,-0.35c-0.42,-0.32 -0.87,-0.58 -1.33,-0.77L13.75,6.3l-0.37,-2.55h-2.76L10.25,6.3L9.72,6.51C9.28,6.7 8.84,6.95 8.38,7.3L7.93,7.63L5.55,6.68L4.16,9.07l2.03,1.58l-0.07,0.56C6.09,11.47 6.06,11.74 6.06,12c0,0.26 0.02,0.53 0.06,0.78l0.07,0.56l-2.03,1.58l1.38,2.4l2.39,-0.96l0.45,0.35c0.43,0.33 0.86,0.58 1.33,0.77l0.53,0.22L10.62,20.25zM18.22,17.72c0,0.01 -0.01,0.02 -0.01,0.03L18.22,17.72zM5.77,17.71l0.01,0.02C5.78,17.72 5.77,17.71 5.77,17.71zM3.93,9.47L3.93,9.47C3.93,9.47 3.93,9.47 3.93,9.47zM18.22,6.27c0,0.01 0.01,0.02 0.01,0.02L18.22,6.27zM5.79,6.25L5.78,6.27C5.78,6.27 5.79,6.26 5.79,6.25zM13.31,3.28c0,0.01 0,0.01 0,0.02L13.31,3.28zM10.69,3.26l0,0.02C10.69,3.27 10.69,3.27 10.69,3.26z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12,12m-3.5,0a3.5,3.5 0,1 1,7 0a3.5,3.5 0,1 1,-7 0"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_tune_black_16dp.xml b/packages/SystemUI/res/drawable/ic_tune_black_16dp.xml
deleted file mode 100644
index c41d1020e3d3..000000000000
--- a/packages/SystemUI/res/drawable/ic_tune_black_16dp.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="16dp"
- android:height="16dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/textColorPrimary">
- <path
- android:fillColor="#FF000000"
- android:pathData="M3,17v2h6v-2L3,17zM3,5v2h10L13,5L3,5zM13,21v-2h8v-2h-8v-2h-2v6h2zM7,9v2L3,11v2h4v2h2L9,9L7,9zM21,13v-2L11,11v2h10zM15,9h2L17,7h4L21,5h-4L17,3h-2v6z"/>
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_unlock.xml b/packages/SystemUI/res/drawable/ic_unlock.xml
deleted file mode 100644
index 46023e6160f5..000000000000
--- a/packages/SystemUI/res/drawable/ic_unlock.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<!--
- Copyright (C) 2021 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:height="65dp" android:width="46dp" android:viewportHeight="65" android:viewportWidth="46">
- <group android:translateX="8.625" android:translateY="13.625">
- <path
- android:strokeColor="#FF000000"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- 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">
- <path
- android:strokeColor="#FF000000"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- 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">
- <path
- android:fillColor="#FF000000"
- android:fillAlpha="1"
- android:fillType="nonZero"
- android:pathData=" M2.75 5.25 C4.13,5.25 5.25,4.13 5.25,2.75 C5.25,1.37 4.13,0.25 2.75,0.25 C1.37,0.25 0.25,1.37 0.25,2.75 C0.25,4.13 1.37,5.25 2.75,5.25c " />
- </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_volume_voice.xml b/packages/SystemUI/res/drawable/ic_volume_voice.xml
deleted file mode 100644
index 3e7748a0fb2e..000000000000
--- a/packages/SystemUI/res/drawable/ic_volume_voice.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:height="24.0dp"
- android:viewportHeight="48.0"
- android:viewportWidth="48.0"
- android:width="24.0dp"
- android:tint="?android:attr/textColorPrimary" >
-
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M13.25,21.59c2.88,5.66 7.51,10.29 13.18,13.17l4.4,-4.41c0.55,-0.55 1.34,-0.71 2.03,-0.49C35.1,30.6 37.51,31.0 40.0,31.0c1.11,0.0 2.0,0.89 2.0,2.0l0.0,7.0c0.0,1.11 -0.89,2.0 -2.0,2.0C21.22,42.0 6.0,26.78 6.0,8.0c0.0,-1.1 0.9,-2.0 2.0,-2.0l7.0,0.0c1.11,0.0 2.0,0.89 2.0,2.0 0.0,2.4 0.4,4.9 1.14,7.1 0.2,0.6 0.06,1.48 -0.49,2.03l-4.4,4.42z" />
-
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_width.xml b/packages/SystemUI/res/drawable/ic_width.xml
deleted file mode 100644
index a302c81efb15..000000000000
--- a/packages/SystemUI/res/drawable/ic_width.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M7.77,6.76L6.23,5.4 0.82,12.0l5.41,6.52 1.54,-1.28L3.42,12.0l4.35,-5.24z
- M17.77,5.48l-1.54,1.28L20.58,12.0l-4.35,5.24 1.54,1.28L23.18,12.0l-5.41,-6.52z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M2.0,13.0l20.0,0.0l0.0,-2.0l-20.0,0.0l0.0,2.0z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/internet_dialog_background.xml b/packages/SystemUI/res/drawable/internet_dialog_background.xml
deleted file mode 100644
index 3ceb0f6ac06a..000000000000
--- a/packages/SystemUI/res/drawable/internet_dialog_background.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<inset xmlns:android="http://schemas.android.com/apk/res/android">
- <shape android:shape="rectangle">
- <corners android:radius="8dp" />
- <solid android:color="?android:attr/colorBackground" />
- </shape>
-</inset>
diff --git a/packages/SystemUI/res/drawable/internet_dialog_rounded_top_corner_background.xml b/packages/SystemUI/res/drawable/internet_dialog_rounded_top_corner_background.xml
deleted file mode 100644
index 14672ef3dcfe..000000000000
--- a/packages/SystemUI/res/drawable/internet_dialog_rounded_top_corner_background.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<inset xmlns:android="http://schemas.android.com/apk/res/android">
- <shape android:shape="rectangle">
- <corners
- android:topLeftRadius="@dimen/internet_dialog_corner_radius"
- android:topRightRadius="@dimen/internet_dialog_corner_radius"
- android:bottomLeftRadius="@dimen/internet_dialog_corner_radius"
- android:bottomRightRadius="@dimen/internet_dialog_corner_radius"/>
- <solid android:color="?android:attr/colorBackground" />
- </shape>
-</inset>
diff --git a/packages/SystemUI/res/drawable/pip_icon.xml b/packages/SystemUI/res/drawable/pip_icon.xml
deleted file mode 100644
index bd92ccd2e6e3..000000000000
--- a/packages/SystemUI/res/drawable/pip_icon.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="36dp"
- android:height="36dp"
- android:viewportWidth="25"
- android:viewportHeight="25">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19,7h-8v6h8L19,7zM21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,1.98 2,1.98h18c1.1,0 2,-0.88 2,-1.98L23,5c0,-1.1 -0.9,-2 -2,-2zM21,19.01L3,19.01L3,4.98h18v14.03z"/>
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pip_resize_handle.xml b/packages/SystemUI/res/drawable/pip_resize_handle.xml
deleted file mode 100644
index 0a8cbc429dd8..000000000000
--- a/packages/SystemUI/res/drawable/pip_resize_handle.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="12.0dp"
- android:height="12.0dp"
- android:viewportWidth="12"
- android:viewportHeight="12">
- <group
- android:translateX="12"
- android:rotation="90">
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M3.41421 0L2 1.41422L10.4853 9.8995L11.8995 8.48528L3.41421 0ZM2.41421 4.24268L1 5.65689L6.65685 11.3137L8.07107 9.89953L2.41421 4.24268Z" />
- </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/qs_bg_gradient.xml b/packages/SystemUI/res/drawable/qs_bg_gradient.xml
deleted file mode 100644
index a1ad52841eb8..000000000000
--- a/packages/SystemUI/res/drawable/qs_bg_gradient.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<shape
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <gradient
- android:angle="270"
- android:startColor="#ff000000"
- android:endColor="#00000000"
- android:type="linear" />
-</shape>
diff --git a/packages/SystemUI/res/drawable/qs_dual_tile_caret.xml b/packages/SystemUI/res/drawable/qs_dual_tile_caret.xml
deleted file mode 100644
index e27bc7a090c1..000000000000
--- a/packages/SystemUI/res/drawable/qs_dual_tile_caret.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18.0dp"
- android:height="18.0dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
-
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M14.0,20.0l10.0,10.0 10.0,-10.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/rounded_bg_bottom_background.xml b/packages/SystemUI/res/drawable/rounded_bg_bottom_background.xml
deleted file mode 100644
index 382ca20268b7..000000000000
--- a/packages/SystemUI/res/drawable/rounded_bg_bottom_background.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="?android:attr/panelColorBackground" />
- <corners
- android:bottomLeftRadius="?android:attr/dialogCornerRadius"
- android:topLeftRadius="0dp"
- android:bottomRightRadius="?android:attr/dialogCornerRadius"
- android:topRightRadius="0dp"
- />
-</shape>
diff --git a/packages/SystemUI/res/drawable/rounded_bg_top.xml b/packages/SystemUI/res/drawable/rounded_bg_top.xml
deleted file mode 100644
index 988ab5874b07..000000000000
--- a/packages/SystemUI/res/drawable/rounded_bg_top.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="?android:attr/colorPrimaryDark" />
- <corners
- android:topLeftRadius="?android:attr/dialogCornerRadius"
- android:topRightRadius="?android:attr/dialogCornerRadius" />
-</shape>
diff --git a/packages/SystemUI/res/drawable/screenrecord_switch_thumb.xml b/packages/SystemUI/res/drawable/screenrecord_switch_thumb.xml
deleted file mode 100644
index f78c582dffd9..000000000000
--- a/packages/SystemUI/res/drawable/screenrecord_switch_thumb.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:top="4dp"
- android:left="4dp"
- android:right="4dp"
- android:bottom="4dp">
- <shape android:shape="oval" >
- <size android:height="20dp" android:width="20dp" />
- <solid android:color="@color/screenrecord_switch_thumb_color" />
- </shape>
- </item>
-</layer-list> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_notify_image.xml b/packages/SystemUI/res/drawable/stat_notify_image.xml
deleted file mode 100644
index c8745d7d046c..000000000000
--- a/packages/SystemUI/res/drawable/stat_notify_image.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M21,19V5c0-1.1-0.9-2-2-2H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14C20.1,21,21,20.1,21,19z
-M8.5,13.5l2.5,3l3.5-4.5l4.5,6H5 L8.5,13.5z" />
- <path
- android:pathData="M0,0h24v24H0V0z" />
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_camera.xml b/packages/SystemUI/res/drawable/stat_sys_camera.xml
deleted file mode 100644
index c914262571ea..000000000000
--- a/packages/SystemUI/res/drawable/stat_sys_camera.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2018, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="3dp"
- android:insetRight="3dp"
- android:drawable="@drawable/ic_camera" /> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_location.xml b/packages/SystemUI/res/drawable/stat_sys_location.xml
deleted file mode 100644
index 7a5aeb9ae558..000000000000
--- a/packages/SystemUI/res/drawable/stat_sys_location.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<!--
- ~ Copyright (C) 2014 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
- -->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="2.5dp"
- android:insetRight="2.5dp"
- android:drawable="@drawable/ic_location" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_managed_profile_status.xml b/packages/SystemUI/res/drawable/stat_sys_managed_profile_status.xml
index c415ecd4f0a8..88914ded15c8 100644
--- a/packages/SystemUI/res/drawable/stat_sys_managed_profile_status.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_managed_profile_status.xml
@@ -20,5 +20,5 @@
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
- android:pathData="M20,6h-4V4c0-1.1-0.9-2-2-2h-4C8.9,2,8,2.9,8,4v2H4C2.9,6,2,6.9,2,8l0,11c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8 C22,6.9,21.1,6,20,6z M10,4h4v2h-4V4z M20,19H4V8h16V19z" />
+ android:pathData="@*android:string/config_work_badge_path_24" />
</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_mic_none.xml b/packages/SystemUI/res/drawable/stat_sys_mic_none.xml
deleted file mode 100644
index d6bdf9fbaa78..000000000000
--- a/packages/SystemUI/res/drawable/stat_sys_mic_none.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2018, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18dp"
- android:height="18dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFF"
- android:pathData="M12,14c1.66,0 3,-1.34 3,-3V5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6C9,12.66 10.34,14 12,14zM11,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v6c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V5z"/>
- <path
- android:fillColor="#FFF"
- android:pathData="M17,11c0,2.76 -2.24,5 -5,5s-5,-2.24 -5,-5H5c0,3.53 2.61,6.43 6,6.92V21h2v-3.08c3.39,-0.49 6,-3.39 6,-6.92H17z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/tv_ic_mic_white.xml b/packages/SystemUI/res/drawable/tv_ic_mic_white.xml
deleted file mode 100644
index d887113c7717..000000000000
--- a/packages/SystemUI/res/drawable/tv_ic_mic_white.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="32dp"
- android:height="32dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12,14c1.66,0 3,-1.34 3,-3V5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6C9,12.66 10.34,14 12,14zM11,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v6c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V5z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M17,11c0,2.76 -2.24,5 -5,5s-5,-2.24 -5,-5H5c0,3.53 2.61,6.43 6,6.92V21h2v-3.08c3.39,-0.49 6,-3.39 6,-6.92H17z"/>
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/udfps_enroll_checkmark.xml b/packages/SystemUI/res/drawable/udfps_enroll_checkmark.xml
new file mode 100644
index 000000000000..f8169d377f12
--- /dev/null
+++ b/packages/SystemUI/res/drawable/udfps_enroll_checkmark.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="54dp"
+ android:height="54dp"
+ android:viewportWidth="54"
+ android:viewportHeight="54">
+ <path
+ android:pathData="M26.9999,3.9619C39.7029,3.9619 50.0369,14.2969 50.0369,26.9999C50.0369,39.7029 39.7029,50.0379 26.9999,50.0379C14.2969,50.0379 3.9629,39.7029 3.9629,26.9999C3.9629,14.2969 14.2969,3.9619 26.9999,3.9619Z"
+ android:fillColor="?android:colorBackground"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M27,0C12.088,0 0,12.088 0,27C0,41.912 12.088,54 27,54C41.912,54 54,41.912 54,27C54,12.088 41.912,0 27,0ZM27,3.962C39.703,3.962 50.037,14.297 50.037,27C50.037,39.703 39.703,50.038 27,50.038C14.297,50.038 3.963,39.703 3.963,27C3.963,14.297 14.297,3.962 27,3.962Z"
+ android:fillColor="@color/udfps_enroll_progress"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M23.0899,38.8534L10.4199,26.1824L13.2479,23.3544L23.0899,33.1974L41.2389,15.0474L44.0679,17.8754L23.0899,38.8534Z"
+ android:fillColor="@color/udfps_enroll_progress"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/packages/SystemUI/res/interpolator/assist_disclosure_trace.xml b/packages/SystemUI/res/interpolator/assist_disclosure_trace.xml
deleted file mode 100644
index 6b5cd37b7bf3..000000000000
--- a/packages/SystemUI/res/interpolator/assist_disclosure_trace.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2015 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
- -->
-
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:controlX1="0.6"
- android:controlY1="0"
- android:controlX2="0.7"
- android:controlY2="1"/> \ No newline at end of file
diff --git a/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_0.xml b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_0.xml
deleted file mode 100644
index 7f4fdbfbe38d..000000000000
--- a/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_0.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 1.0,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_1.xml b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_1.xml
deleted file mode 100644
index 169596299bef..000000000000
--- a/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_1.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.4,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_2.xml b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_2.xml
deleted file mode 100644
index 91c08f869baf..000000000000
--- a/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_2.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 l 0.236439499305,0.0 c 0.763560500695,0.0 0.458136300417,1.0 0.763560500695,1.0 L 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_3.xml b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_3.xml
deleted file mode 100644
index f5cbc3142986..000000000000
--- a/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_3.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.00100000000001,0.0 0.2,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_4.xml b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_4.xml
deleted file mode 100644
index cf21d8153b43..000000000000
--- a/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_4.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.00100000000002,0.0 0.2,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_5.xml b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_5.xml
deleted file mode 100644
index 0c18d9293933..000000000000
--- a/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_5.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.8,0.0 0.2,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_6.xml b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_6.xml
deleted file mode 100644
index 0bf41e54d386..000000000000
--- a/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_6.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.2,0.0 0.0,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_caret_down_animation_interpolator_0.xml b/packages/SystemUI/res/interpolator/ic_caret_down_animation_interpolator_0.xml
deleted file mode 100644
index ed90d64fdeff..000000000000
--- a/packages/SystemUI/res/interpolator/ic_caret_down_animation_interpolator_0.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.2,0.0 0.0,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_caret_up_animation_interpolator_0.xml b/packages/SystemUI/res/interpolator/ic_caret_up_animation_interpolator_0.xml
deleted file mode 100644
index ed90d64fdeff..000000000000
--- a/packages/SystemUI/res/interpolator/ic_caret_up_animation_interpolator_0.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.2,0.0 0.0,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_0.xml b/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_0.xml
deleted file mode 100644
index fcd751dadb26..000000000000
--- a/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_0.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.16666666667,0.0 0.83333333333,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_1.xml b/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_1.xml
deleted file mode 100644
index 38dbdb71f35f..000000000000
--- a/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_1.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.8,0.0 0.5,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_2.xml b/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_2.xml
deleted file mode 100644
index 169596299bef..000000000000
--- a/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_2.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.4,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_3.xml b/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_3.xml
deleted file mode 100644
index 8538f9895aa9..000000000000
--- a/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_3.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 l 0.286298568507,0.0 c 0.142740286299,0.0 0.0,1.0 0.713701431493,1.0 L 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_4.xml b/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_4.xml
deleted file mode 100644
index 0bf41e54d386..000000000000
--- a/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_4.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.2,0.0 0.0,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_5.xml b/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_5.xml
deleted file mode 100644
index 220209432136..000000000000
--- a/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_5.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.00010,0.0 0.2,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_6.xml b/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_6.xml
deleted file mode 100644
index 0c18d9293933..000000000000
--- a/packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_6.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.8,0.0 0.2,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_0.xml b/packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_0.xml
deleted file mode 100644
index ac1b566e9dc4..000000000000
--- a/packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_0.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 l 0.555555555556,0.0 c 0.177777777778,0.0 0.0888888888889,1.0 0.444444444444,1.0 L 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_1.xml b/packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_1.xml
deleted file mode 100644
index 7f4fdbfbe38d..000000000000
--- a/packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_1.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 1.0,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_2.xml b/packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_2.xml
deleted file mode 100644
index 169596299bef..000000000000
--- a/packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_2.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.4,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_3.xml b/packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_3.xml
deleted file mode 100644
index 02c6cd51b65a..000000000000
--- a/packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_3.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 l 0.445544554455,0.0 c 0.554455445545,0.0 0.332673267327,1.0 0.554455445545,1.0 L 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_4.xml b/packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_4.xml
deleted file mode 100644
index 7ae249e9bc4f..000000000000
--- a/packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_4.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.00010,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_5.xml b/packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_5.xml
deleted file mode 100644
index 0c18d9293933..000000000000
--- a/packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_5.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.8,0.0 0.2,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_landscape_to_rotate_animation_interpolator_0.xml b/packages/SystemUI/res/interpolator/ic_landscape_to_rotate_animation_interpolator_0.xml
deleted file mode 100644
index 793e7fff11e0..000000000000
--- a/packages/SystemUI/res/interpolator/ic_landscape_to_rotate_animation_interpolator_0.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.4,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_rotate_to_landscape_animation_interpolator_0.xml b/packages/SystemUI/res/interpolator/ic_rotate_to_landscape_animation_interpolator_0.xml
deleted file mode 100644
index 793e7fff11e0..000000000000
--- a/packages/SystemUI/res/interpolator/ic_rotate_to_landscape_animation_interpolator_0.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.4,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_rotate_to_portrait_animation_interpolator_0.xml b/packages/SystemUI/res/interpolator/ic_rotate_to_portrait_animation_interpolator_0.xml
deleted file mode 100644
index 793e7fff11e0..000000000000
--- a/packages/SystemUI/res/interpolator/ic_rotate_to_portrait_animation_interpolator_0.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.4,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/lockscreen_fingerprint_draw_off_animation_interpolator_0.xml b/packages/SystemUI/res/interpolator/lockscreen_fingerprint_draw_off_animation_interpolator_0.xml
deleted file mode 100644
index e8c1f90c2049..000000000000
--- a/packages/SystemUI/res/interpolator/lockscreen_fingerprint_draw_off_animation_interpolator_0.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2015 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
- -->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.5,0.0 1.0,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/lockscreen_fingerprint_draw_off_animation_interpolator_1.xml b/packages/SystemUI/res/interpolator/lockscreen_fingerprint_draw_off_animation_interpolator_1.xml
deleted file mode 100644
index cb59de9313fa..000000000000
--- a/packages/SystemUI/res/interpolator/lockscreen_fingerprint_draw_off_animation_interpolator_1.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2015 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
- -->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.5,0.0 0.5,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/lockscreen_fingerprint_draw_on_animation_interpolator_0.xml b/packages/SystemUI/res/interpolator/lockscreen_fingerprint_draw_on_animation_interpolator_0.xml
deleted file mode 100644
index 708de2a2cb53..000000000000
--- a/packages/SystemUI/res/interpolator/lockscreen_fingerprint_draw_on_animation_interpolator_0.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2015 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
- -->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.0,0.0 0.29,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/lockscreen_fingerprint_draw_on_animation_interpolator_1.xml b/packages/SystemUI/res/interpolator/lockscreen_fingerprint_draw_on_animation_interpolator_1.xml
deleted file mode 100644
index a5ffc400901b..000000000000
--- a/packages/SystemUI/res/interpolator/lockscreen_fingerprint_draw_on_animation_interpolator_1.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2015 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
- -->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.0,0.0 0.5,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_0.xml b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_0.xml
deleted file mode 100644
index 7f4fdbfbe38d..000000000000
--- a/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_0.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 1.0,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_1.xml b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_1.xml
deleted file mode 100644
index 169596299bef..000000000000
--- a/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_1.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.4,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_2.xml b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_2.xml
deleted file mode 100644
index 138851e307d9..000000000000
--- a/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_2.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.001,0.0 0.2,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_3.xml b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_3.xml
deleted file mode 100644
index 7657cb6b1ac7..000000000000
--- a/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_3.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 l 0.364238410596,0.0 c 0.127152317881,0.0 0.0,1.0 0.635761589404,1.0 L 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_4.xml b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_4.xml
deleted file mode 100644
index 3e5efd7699ba..000000000000
--- a/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_4.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 l 0.4,0.0 c 0.0006,0.0 0.12,1.0 0.6,1.0 L 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_5.xml b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_5.xml
deleted file mode 100644
index 220209432136..000000000000
--- a/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_5.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.00010,0.0 0.2,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/wireless_charging_animation_interpolator_1.xml b/packages/SystemUI/res/interpolator/wireless_charging_animation_interpolator_1.xml
deleted file mode 100644
index 3fe59aeea8dc..000000000000
--- a/packages/SystemUI/res/interpolator/wireless_charging_animation_interpolator_1.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2018, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<pathInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0.0,0.0 c 0.001,0.0 0.2,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/layout-land/global_actions_column_seascape.xml b/packages/SystemUI/res/layout-land/global_actions_column_seascape.xml
deleted file mode 100644
index 412beb789deb..000000000000
--- a/packages/SystemUI/res/layout-land/global_actions_column_seascape.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<com.android.systemui.globalactions.GlobalActionsColumnLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@id/global_actions_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal"
- android:clipToPadding="false"
- android:theme="@style/Theme.SystemUI.QuickSettings"
- android:gravity="center_horizontal | bottom"
- android:clipChildren="false"
->
- <LinearLayout
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:padding="0dp"
- android:orientation="horizontal"
- >
- <!-- Grid of action items -->
- <com.android.systemui.globalactions.ListGridLayout
- android:id="@android:id/list"
- android:layout_gravity="bottom|left"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_marginBottom="@dimen/global_actions_grid_side_margin"
- android:translationZ="@dimen/global_actions_translate"
- android:paddingLeft="@dimen/global_actions_grid_vertical_padding"
- android:paddingRight="@dimen/global_actions_grid_vertical_padding"
- android:paddingTop="@dimen/global_actions_grid_horizontal_padding"
- android:paddingBottom="@dimen/global_actions_grid_horizontal_padding"
- android:background="?android:attr/colorBackgroundFloating"
- />
- <!-- For separated items-->
- <LinearLayout
- android:id="@+id/separated_button"
- android:layout_gravity="top|left"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="@dimen/global_actions_grid_side_margin"
- android:layout_marginBottom="@dimen/global_actions_grid_side_margin"
- android:paddingLeft="@dimen/global_actions_grid_vertical_padding"
- android:paddingRight="@dimen/global_actions_grid_vertical_padding"
- android:paddingTop="@dimen/global_actions_grid_horizontal_padding"
- android:paddingBottom="@dimen/global_actions_grid_horizontal_padding"
- android:orientation="horizontal"
- android:background="?android:attr/colorBackgroundFloating"
- android:translationZ="@dimen/global_actions_translate"
- />
- </LinearLayout>
-
-</com.android.systemui.globalactions.GlobalActionsColumnLayout>
diff --git a/packages/SystemUI/res/layout-land/global_actions_grid_item.xml b/packages/SystemUI/res/layout-land/global_actions_grid_item.xml
deleted file mode 100644
index 0f9deaa3c569..000000000000
--- a/packages/SystemUI/res/layout-land/global_actions_grid_item.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<!-- RelativeLayouts have an issue enforcing minimum heights, so just
- work around this for now with LinearLayouts. -->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:layout_marginTop="@dimen/global_actions_grid_item_side_margin"
- android:layout_marginBottom="@dimen/global_actions_grid_item_side_margin"
- android:layout_marginLeft="@dimen/global_actions_grid_item_vertical_margin"
- android:layout_marginRight="@dimen/global_actions_grid_item_vertical_margin"
->
- <LinearLayout
- android:layout_width="@dimen/global_actions_grid_item_height"
- android:layout_height="@dimen/global_actions_grid_item_width"
- android:gravity="top|center_horizontal"
- android:orientation="vertical"
- >
- <ImageView
- android:id="@*android:id/icon"
- android:layout_width="@dimen/global_actions_grid_item_icon_width"
- android:layout_height="@dimen/global_actions_grid_item_icon_height"
- android:layout_marginTop="@dimen/global_actions_grid_item_icon_top_margin"
- android:layout_marginBottom="@dimen/global_actions_grid_item_icon_bottom_margin"
- android:layout_marginLeft="@dimen/global_actions_grid_item_icon_side_margin"
- android:layout_marginRight="@dimen/global_actions_grid_item_icon_side_margin"
- android:scaleType="centerInside"
- android:tint="@color/global_actions_text"
- />
-
- <TextView
- android:id="@*android:id/message"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:ellipsize="marquee"
- android:marqueeRepeatLimit="marquee_forever"
- android:singleLine="true"
- android:gravity="center"
- android:textSize="12dp"
- android:textColor="@color/global_actions_text"
- android:textAppearance="?android:attr/textAppearanceSmall"
- />
- </LinearLayout>
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml b/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml
deleted file mode 100644
index e52ad2acadc0..000000000000
--- a/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<com.android.systemui.globalactions.GlobalActionsGridLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@id/global_actions_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal"
- android:theme="@style/Theme.SystemUI.QuickSettings"
- android:gravity="left | center_vertical"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:paddingLeft="@dimen/global_actions_grid_container_shadow_offset"
- android:layout_marginLeft="@dimen/global_actions_grid_container_negative_shadow_offset"
->
- <LinearLayout
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:padding="0dp"
- android:orientation="vertical"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:layout_marginLeft="@dimen/global_actions_grid_container_bottom_margin"
- >
- <!-- For separated items-->
- <LinearLayout
- android:id="@+id/separated_button"
- android:layout_gravity="top|left"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/global_actions_grid_side_margin"
- android:layout_marginBottom="@dimen/global_actions_grid_side_margin"
- android:paddingLeft="@dimen/global_actions_grid_vertical_padding"
- android:paddingRight="@dimen/global_actions_grid_vertical_padding"
- android:paddingTop="@dimen/global_actions_grid_horizontal_padding"
- android:paddingBottom="@dimen/global_actions_grid_horizontal_padding"
- android:orientation="horizontal"
- android:layoutDirection="rtl"
- android:background="?android:attr/colorBackgroundFloating"
- android:gravity="center"
- android:translationZ="@dimen/global_actions_translate"
- />
- <!-- Grid of action items -->
- <com.android.systemui.globalactions.ListGridLayout
- android:id="@android:id/list"
- android:layout_gravity="bottom|left"
- android:gravity="right"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_marginBottom="@dimen/global_actions_grid_side_margin"
- android:translationZ="@dimen/global_actions_translate"
- android:paddingLeft="@dimen/global_actions_grid_vertical_padding"
- android:paddingRight="@dimen/global_actions_grid_vertical_padding"
- android:paddingTop="@dimen/global_actions_grid_horizontal_padding"
- android:paddingBottom="@dimen/global_actions_grid_horizontal_padding"
- android:background="?android:attr/colorBackgroundFloating"
- >
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="gone"
- android:layoutDirection="locale"
- />
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="gone"
- android:layoutDirection="locale"
- />
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="gone"
- android:layoutDirection="locale"
- />
- </com.android.systemui.globalactions.ListGridLayout>
- </LinearLayout>
-
-</com.android.systemui.globalactions.GlobalActionsGridLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp-land/global_actions_grid_v2.xml b/packages/SystemUI/res/layout-sw600dp-land/global_actions_grid_v2.xml
deleted file mode 100644
index 953a29e3a07e..000000000000
--- a/packages/SystemUI/res/layout-sw600dp-land/global_actions_grid_v2.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/global_actions_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal">
-
- <LinearLayout
- android:layout_weight="1"
- android:layout_height="match_parent"
- android:layout_width="0dp"
- android:clipChildren="false"
- android:orientation="vertical"
- android:clipToPadding="false"
- android:id="@+id/controls_pane"
- >
- <LinearLayout
- android:id="@+id/global_actions_controls"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"/>
- </LinearLayout>
-
- <LinearLayout
- android:layout_weight="1"
- android:layout_height="match_parent"
- android:layout_width="0dp"
- android:orientation="vertical"
- android:id="@+id/nfc_pane"
- >
- <include layout="@layout/global_actions_view" />
-
- <include layout="@layout/global_actions_lock_view" />
-
- <LinearLayout
- android:id="@+id/global_actions_grid_root"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:clipChildren="false"
- android:orientation="vertical"
- android:clipToPadding="false">
-
- <FrameLayout
- android:id="@+id/global_actions_wallet"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
-
- </LinearLayout>
-
- </LinearLayout>
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp/global_actions_grid_v2.xml b/packages/SystemUI/res/layout-sw600dp/global_actions_grid_v2.xml
deleted file mode 100644
index 6ffcef7b24e6..000000000000
--- a/packages/SystemUI/res/layout-sw600dp/global_actions_grid_v2.xml
+++ /dev/null
@@ -1,76 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/global_actions_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <LinearLayout
- android:layout_weight="1"
- android:layout_height="0dp"
- android:layout_width="match_parent"
- android:orientation="vertical"
- android:id="@+id/nfc_pane"
- >
-
- <include layout="@layout/global_actions_view" />
-
- <include layout="@layout/global_actions_lock_view" />
-
-
- <com.android.systemui.globalactions.MinHeightScrollView
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:scrollbars="none">
-
- <LinearLayout
- android:id="@+id/global_actions_grid_root"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:clipChildren="false"
- android:orientation="vertical"
- android:clipToPadding="false">
-
- <FrameLayout
- android:id="@+id/global_actions_wallet"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
-
- </LinearLayout>
- </com.android.systemui.globalactions.MinHeightScrollView>
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_weight="1"
- android:layout_height="0dp"
- android:layout_width="match_parent"
- android:orientation="vertical"
- android:id="@+id/controls_pane"
- android:clipToPadding="false"
- android:clipChildren="false">
- <LinearLayout
- android:id="@+id/global_actions_controls"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"/>
- </LinearLayout>
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/app_ops_info.xml b/packages/SystemUI/res/layout/app_ops_info.xml
deleted file mode 100644
index ecf572ba4a5c..000000000000
--- a/packages/SystemUI/res/layout/app_ops_info.xml
+++ /dev/null
@@ -1,96 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 2018, The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<com.android.systemui.statusbar.notification.row.AppOpsInfo
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:id="@+id/app_ops_info"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:orientation="vertical"
- android:paddingStart="@*android:dimen/notification_content_margin_start"
- android:paddingEnd="@*android:dimen/notification_content_margin_end"
- android:background="?android:attr/colorBackground"
- android:theme="@*android:style/Theme.DeviceDefault.Light">
-
- <!-- Package Info -->
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:layout_marginTop="@*android:dimen/notification_header_padding_top" >
- <ImageView
- android:id="@+id/pkgicon"
- android:layout_width="@dimen/notification_guts_header_height"
- android:layout_height="@dimen/notification_guts_header_height"
- android:layout_centerVertical="true"
- android:layout_marginEnd="3dp" />
- <TextView
- android:id="@+id/pkgname"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="@*android:style/TextAppearance.Material.Notification.Info"
- android:layout_marginStart="3dp"
- android:layout_marginEnd="2dp"
- android:singleLine="true"
- android:layout_centerVertical="true"
- android:layout_toEndOf="@id/pkgicon" />
- </RelativeLayout>
-
- <TextView
- android:id="@+id/prompt"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="@*android:dimen/notification_header_padding_top"
- style="@style/TextAppearance.NotificationInfo.Secondary" />
-
- <!-- Settings and Done buttons -->
- <RelativeLayout
- android:id="@+id/bottom_buttons"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:paddingStart="4dp"
- android:paddingEnd="4dp">
- <TextView
- android:id="@+id/settings"
- android:text="@string/notification_appops_settings"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toStartOf="@+id/ok"
- android:gravity="center_vertical"
- android:background="@drawable/ripple_drawable"
- android:layout_marginEnd="8dp"
- android:minWidth="@dimen/min_clickable_item_size"
- android:minHeight="@dimen/min_clickable_item_size"
- style="@style/TextAppearance.NotificationInfo.Button"/>
- <TextView
- android:id="@+id/ok"
- android:text="@string/notification_appops_ok"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentEnd="true"
- android:gravity="end|center_vertical"
- android:background="@drawable/ripple_drawable"
- android:minWidth="@dimen/min_clickable_item_size"
- android:minHeight="@dimen/min_clickable_item_size"
- style="@style/TextAppearance.NotificationInfo.Button"/>
- </RelativeLayout>
-</com.android.systemui.statusbar.notification.row.AppOpsInfo>
diff --git a/packages/SystemUI/res/layout/combined_qs_header.xml b/packages/SystemUI/res/layout/combined_qs_header.xml
new file mode 100644
index 000000000000..1f10e5dfeed8
--- /dev/null
+++ b/packages/SystemUI/res/layout/combined_qs_header.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<androidx.constraintlayout.motion.widget.MotionLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/split_shade_status_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/split_shade_header_min_height"
+ android:clickable="false"
+ android:focusable="true"
+ android:paddingLeft="@dimen/qs_panel_padding"
+ android:paddingRight="@dimen/qs_panel_padding"
+ android:visibility="gone"
+ android:theme="@style/Theme.SystemUI.QuickSettings.Header"
+ app:layoutDescription="@xml/combined_qs_header_scene">
+
+ <androidx.constraintlayout.widget.Guideline
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/center"
+ app:layout_constraintGuide_percent="0.5"
+ android:orientation="vertical" />
+
+ <com.android.systemui.statusbar.policy.Clock
+ android:id="@+id/clock"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:gravity="start|center_vertical"
+ android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
+ android:paddingEnd="@dimen/status_bar_left_clock_end_padding"
+ android:singleLine="true"
+ android:textAppearance="@style/TextAppearance.QS.Status"
+ />
+
+ <com.android.systemui.statusbar.policy.DateView
+ android:id="@+id/date"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_gravity="start|center_vertical"
+ android:gravity="center_vertical"
+ android:singleLine="true"
+ android:textAppearance="@style/TextAppearance.QS.Status"
+ app:datePattern="@string/abbrev_wday_month_day_no_year_alarm"
+ />
+
+ <include
+ android:id="@+id/carrier_group"
+ layout="@layout/qs_carrier_group"
+ app:layout_constraintHeight_min="@dimen/split_shade_header_min_height"
+ android:minHeight="@dimen/split_shade_header_min_height"
+ app:layout_constraintWidth_min="48dp"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constrainedWidth="true"
+ android:layout_gravity="end|center_vertical"
+ android:layout_marginStart="8dp"
+ app:layout_constraintStart_toEndOf="@id/date"
+ app:layout_constraintEnd_toStartOf="@id/statusIcons"
+ app:layout_constraintTop_toTopOf="@id/clock"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintHorizontal_bias="1"
+ />
+
+ <com.android.systemui.statusbar.phone.StatusIconContainer
+ android:id="@+id/statusIcons"
+ app:layout_constraintHeight_min="@dimen/split_shade_header_min_height"
+ android:paddingEnd="@dimen/signal_cluster_battery_padding"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ app:layout_constraintStart_toEndOf="@id/carrier_group"
+ app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
+ app:layout_constraintTop_toTopOf="@id/clock"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintHorizontal_bias="1"
+ />
+
+ <com.android.systemui.battery.BatteryMeterView
+ android:id="@+id/batteryRemainingIcon"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ app:layout_constraintHeight_min="@dimen/split_shade_header_min_height"
+ app:textAppearance="@style/TextAppearance.QS.Status"
+ app:layout_constraintStart_toEndOf="@id/statusIcons"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="@id/clock"
+ app:layout_constraintBottom_toBottomOf="parent"
+ />
+
+</androidx.constraintlayout.motion.widget.MotionLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/controls_icon.xml b/packages/SystemUI/res/layout/controls_icon.xml
deleted file mode 100644
index 12bc5f6837fc..000000000000
--- a/packages/SystemUI/res/layout/controls_icon.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2020, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<ImageView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:scaleType="fitCenter"
- android:layout_marginLeft="5dp"
- android:layout_marginRight="5dp" />
diff --git a/packages/SystemUI/res/layout/global_actions_grid_item.xml b/packages/SystemUI/res/layout/global_actions_grid_item.xml
deleted file mode 100644
index 31c7cbf6ff1b..000000000000
--- a/packages/SystemUI/res/layout/global_actions_grid_item.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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.
--->
-
-<!-- RelativeLayouts have an issue enforcing minimum heights, so just
- work around this for now with LinearLayouts. -->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:layout_marginTop="@dimen/global_actions_grid_item_vertical_margin"
- android:layout_marginBottom="@dimen/global_actions_grid_item_vertical_margin"
- android:layout_marginLeft="@dimen/global_actions_grid_item_side_margin"
- android:layout_marginRight="@dimen/global_actions_grid_item_side_margin"
->
- <LinearLayout
- android:layout_width="@dimen/global_actions_grid_item_width"
- android:layout_height="@dimen/global_actions_grid_item_height"
- android:gravity="top|center_horizontal"
- android:orientation="vertical"
- >
- <ImageView
- android:id="@*android:id/icon"
- android:layout_width="@dimen/global_actions_grid_item_icon_width"
- android:layout_height="@dimen/global_actions_grid_item_icon_height"
- android:layout_marginTop="@dimen/global_actions_grid_item_icon_top_margin"
- android:layout_marginBottom="@dimen/global_actions_grid_item_icon_bottom_margin"
- android:layout_marginLeft="@dimen/global_actions_grid_item_icon_side_margin"
- android:layout_marginRight="@dimen/global_actions_grid_item_icon_side_margin"
- android:scaleType="centerInside"
- android:tint="@color/global_actions_text"
- />
-
- <TextView
- android:id="@*android:id/message"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:ellipsize="marquee"
- android:marqueeRepeatLimit="marquee_forever"
- android:singleLine="true"
- android:gravity="center"
- android:textSize="12dp"
- android:textColor="@color/global_actions_text"
- android:textAppearance="?android:attr/textAppearanceSmall"
- />
- </LinearLayout>
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/global_actions_grid_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
deleted file mode 100644
index f06a4be5f7b8..000000000000
--- a/packages/SystemUI/res/layout/global_actions_grid_v2.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/global_actions_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
->
-
- <include layout="@layout/global_actions_view" />
-
- <include layout="@layout/global_actions_lock_view" />
-
- <com.android.systemui.globalactions.MinHeightScrollView
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:scrollbars="none">
-
- <LinearLayout
- android:id="@+id/global_actions_grid_root"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:clipChildren="false"
- android:orientation="vertical"
- android:clipToPadding="false">
-
- <FrameLayout
- android:id="@+id/global_actions_wallet"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
-
- </LinearLayout>
- </com.android.systemui.globalactions.MinHeightScrollView>
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/global_actions_item.xml b/packages/SystemUI/res/layout/global_actions_item.xml
deleted file mode 100644
index 66a4b737d09b..000000000000
--- a/packages/SystemUI/res/layout/global_actions_item.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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.
--->
-
-<!-- RelativeLayouts have an issue enforcing minimum heights, so just
- work around this for now with LinearLayouts. -->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:minWidth="92dp"
- android:minHeight="92dp"
- android:gravity="center"
- android:orientation="vertical"
- android:paddingEnd="4dip"
- android:paddingStart="4dip">
-
- <ImageView
- android:id="@*android:id/icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="center"
- android:scaleType="center"
- android:alpha="?android:attr/primaryContentAlpha"
- />
-
- <TextView
- android:id="@*android:id/message"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center_horizontal"
- android:paddingTop="10dp"
- android:gravity="center"
- android:textSize="12sp"
- android:textAppearance="?android:attr/textAppearanceSmall"
- />
-
- <TextView
- android:id="@*android:id/status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center_horizontal"
- android:gravity="center"
- android:textColor="?android:attr/textColorTertiary"
- android:textAppearance="?android:attr/textAppearanceSmall"
- />
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/global_actions_lock_view.xml b/packages/SystemUI/res/layout/global_actions_lock_view.xml
deleted file mode 100644
index eccc63688065..000000000000
--- a/packages/SystemUI/res/layout/global_actions_lock_view.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<androidx.constraintlayout.widget.ConstraintLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/global_actions_lock_message_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="gone">
- <TextView
- android:id="@+id/global_actions_lock_message"
- style="@style/TextAppearance.Control.Title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/global_actions_side_margin"
- android:drawablePadding="12dp"
- android:gravity="center"
- android:text="@string/global_action_lock_message"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintVertical_bias="0.35"/>
-</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_screenshot_static.xml b/packages/SystemUI/res/layout/global_screenshot_static.xml
index 21c5ab04eb9a..b319d44da500 100644
--- a/packages/SystemUI/res/layout/global_screenshot_static.xml
+++ b/packages/SystemUI/res/layout/global_screenshot_static.xml
@@ -94,7 +94,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:elevation="@dimen/screenshot_preview_elevation"
- android:contentDescription="@string/screenshot_edit_label"
+ android:contentDescription="@string/screenshot_edit_description"
android:scaleType="fitEnd"
android:background="@drawable/screenshot_preview_background"
android:adjustViewBounds="true"
diff --git a/packages/SystemUI/res/layout/horizontal_divider.xml b/packages/SystemUI/res/layout/horizontal_divider.xml
deleted file mode 100644
index a060f08039e1..000000000000
--- a/packages/SystemUI/res/layout/horizontal_divider.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 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.
--->
-<View
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:layout_marginTop="10dp"
- android:layout_marginBottom="10dp"
- android:layout_marginStart="40dp"
- android:layout_marginEnd="40dp"
- android:background="#4dffffff" />
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index 79ac737ba304..86e2661f9534 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -20,8 +20,7 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@+id/internet_connectivity_dialog"
android:layout_width="@dimen/large_dialog_width"
- android:layout_height="@dimen/internet_dialog_list_max_height"
- android:background="@drawable/internet_dialog_rounded_top_corner_background"
+ android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
@@ -330,7 +329,8 @@
android:layout_height="wrap_content"
android:paddingBottom="4dp"
android:clickable="false"
- android:focusable="false">
+ android:focusable="false"
+ android:visibility="gone">
<LinearLayout
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/mland.xml b/packages/SystemUI/res/layout/mland.xml
deleted file mode 100644
index d1b6d002effe..000000000000
--- a/packages/SystemUI/res/layout/mland.xml
+++ /dev/null
@@ -1,103 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 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.
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
- <com.android.systemui.egg.MLand
- android:id="@+id/world"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- </com.android.systemui.egg.MLand>
- <FrameLayout
- android:id="@+id/welcome"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="gone"
- android:background="#a0000000"
- android:clickable="true"
- >
- <FrameLayout
- android:id="@+id/play_button"
- android:layout_width="72dp"
- android:layout_height="72dp"
- android:layout_gravity="center"
- android:clickable="true"
- android:background="@drawable/ripplebg"
- android:focusable="true"
- android:onClick="startButtonPressed"
- >
- <ImageView
- android:id="@+id/play_button_image"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:scaleType="fitCenter"
- android:layout_gravity="center"
- android:tint="#000000"
- android:src="@drawable/play"
- />
- <TextView
- android:id="@+id/play_button_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:alpha="0"
- android:textSize="40dp"
- android:textColor="#000000"
- />
- </FrameLayout>
- </FrameLayout>
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center_horizontal"
- android:orientation="horizontal"
- android:gravity="center_vertical"
- android:id="@+id/player_setup"
- >
- <ImageButton
- style="@android:style/Widget.Material.Button.Borderless"
- android:id="@+id/player_minus_button"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:padding="10dp"
- android:scaleType="centerInside"
- android:onClick="playerMinus"
- android:src="@drawable/minus"
- />
- <LinearLayout
- android:id="@+id/scores"
- android:layout_width="wrap_content"
- android:layout_height="64dp"
- android:padding="12dp"
- android:orientation="horizontal"
- android:clipToPadding="false"
- >
- </LinearLayout>
- <ImageButton
- style="@android:style/Widget.Material.Button.Borderless"
- android:id="@+id/player_plus_button"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:padding="10dp"
- android:scaleType="centerInside"
- android:onClick="playerPlus"
- android:src="@drawable/plus"
- />
- </LinearLayout>
-</FrameLayout>
diff --git a/packages/SystemUI/res/layout/mland_scorefield.xml b/packages/SystemUI/res/layout/mland_scorefield.xml
deleted file mode 100644
index 0ed72e43b40a..000000000000
--- a/packages/SystemUI/res/layout/mland_scorefield.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 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.
--->
-<TextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/score"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:textStyle="bold"
- android:textSize="22sp"
- android:gravity="center"
- android:textColor="#FFAAAAAA"
- android:paddingStart="12dp"
- android:paddingEnd="12dp"
- android:paddingTop="4dp"
- android:paddingBottom="4dp"
- android:background="@drawable/scorecard"
- android:elevation="@dimen/hud_z"
- />
diff --git a/packages/SystemUI/res/layout/nav_control_widget.xml b/packages/SystemUI/res/layout/nav_control_widget.xml
deleted file mode 100644
index 51dd68fd5a97..000000000000
--- a/packages/SystemUI/res/layout/nav_control_widget.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 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.
--->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:gravity="center"
- android:orientation="horizontal">
-
- <ImageView
- android:id="@+id/width"
- android:layout_width="48dp"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_width"
- android:clickable="true"
- android:tint="?android:attr/textColorPrimary" />
-
- <View
- android:layout_width="1dp"
- android:layout_height="match_parent"
- android:background="?android:attr/listDivider" />
-
- <ImageView
- android:id="@+id/close"
- android:layout_width="48dp"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_close"
- android:clickable="true"
- android:tint="?android:attr/textColorPrimary" />
-
- <View
- android:layout_width="1dp"
- android:layout_height="match_parent"
- android:background="?android:attr/listDivider" />
-
- <ImageView
- android:id="@+id/drag"
- android:layout_width="48dp"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_drag_handle"
- android:clickable="true"
- android:tint="?android:attr/textColorPrimary" />
-
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/nav_width_view.xml b/packages/SystemUI/res/layout/nav_width_view.xml
deleted file mode 100644
index 6a72faf9fbea..000000000000
--- a/packages/SystemUI/res/layout/nav_width_view.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2016, 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.
-*/
--->
-
-<SeekBar
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/seekbar"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:paddingTop="12dp"
- android:paddingBottom="4dp" />
diff --git a/packages/SystemUI/res/layout/navigation_bar_app_item.xml b/packages/SystemUI/res/layout/navigation_bar_app_item.xml
deleted file mode 100644
index 1078d2901d7d..000000000000
--- a/packages/SystemUI/res/layout/navigation_bar_app_item.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 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.
--->
-
-<!--
- ImageView for an app icon in the navigation bar. Used to launch the app. The ImageView size is
- used to compute the size of the drag shadow.
--->
-<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="64dp"
- android:layout_height="48dp"
- android:paddingLeft="14dp"
- android:paddingRight="14dp"
- android:paddingTop="6dp"
- android:paddingBottom="6dp"
- android:layout_gravity="center"
- android:scaleType="centerInside"
- />
diff --git a/packages/SystemUI/res/layout/ongoing_call_chip.xml b/packages/SystemUI/res/layout/ongoing_call_chip.xml
index 5389d9bbcc97..c949ba0db171 100644
--- a/packages/SystemUI/res/layout/ongoing_call_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_call_chip.xml
@@ -21,6 +21,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical|start"
+ android:layout_marginStart="5dp"
>
<LinearLayout
android:id="@+id/ongoing_call_chip_background"
diff --git a/packages/SystemUI/res/layout/people_space_widget.xml b/packages/SystemUI/res/layout/people_space_widget.xml
deleted file mode 100644
index f4db321b8714..000000000000
--- a/packages/SystemUI/res/layout/people_space_widget.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<ListView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/widget_list_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/people_space_widget_background"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:padding="2dp"
- android:divider="@null"
- android:dividerHeight="0dp"/> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/people_space_widget_item.xml b/packages/SystemUI/res/layout/people_space_widget_item.xml
deleted file mode 100644
index 492d3abcb6d0..000000000000
--- a/packages/SystemUI/res/layout/people_space_widget_item.xml
+++ /dev/null
@@ -1,93 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:padding="4dp"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <LinearLayout
- android:background="@drawable/people_space_tile_view_card"
- android:clipToOutline="true"
- android:id="@android:id/background"
- android:orientation="vertical"
- android:padding="4dp"
- android:layout_marginBottom="2dp"
- android:elevation="4dp"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <LinearLayout
- android:orientation="horizontal"
- android:gravity="center_vertical"
- android:paddingStart="12dp"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <ImageView
- android:id="@+id/person_icon"
- android:layout_width="60dp"
- android:layout_height="60dp" />
-
- <LinearLayout
- android:background="@drawable/people_space_rounded_border"
- android:layout_marginStart="-12dp"
- android:layout_marginTop="28dp"
- android:layout_marginBottom="14dp"
- android:layout_width="16dp"
- android:layout_height="16dp">
-
- <ImageView
- android:id="@+id/package_icon"
- android:layout_width="12dp"
- android:layout_marginStart="2dp"
- android:layout_marginEnd="2dp"
- android:layout_marginBottom="2dp"
- android:layout_marginTop="2dp"
- android:layout_height="12dp" />
- </LinearLayout>
-
- <LinearLayout
- android:orientation="vertical"
- android:paddingStart="8dp"
- android:paddingEnd="12dp"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <TextView
- android:id="@+id/name"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="16sp"
- android:maxLines="1"
- android:ellipsize="end"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
- <TextView
- android:id="@+id/status"
- android:textColor="?android:attr/textColorSecondary"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title"
- android:paddingVertical="2dp"
- android:textSize="12sp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:maxLines="3"
- android:ellipsize="end" />
- </LinearLayout>
- </LinearLayout>
- </LinearLayout>
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/preference_widget_settings.xml b/packages/SystemUI/res/layout/preference_widget_settings.xml
deleted file mode 100644
index 082a29577aa7..000000000000
--- a/packages/SystemUI/res/layout/preference_widget_settings.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 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.
--->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content">
-
- <RadioButton
- android:id="@+id/radio_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="4dp"
- android:clickable="false"
- android:focusable="false" />
-
- <View
- android:layout_width="1dp"
- android:layout_height="match_parent"
- android:background="?android:attr/listDivider" />
-
- <ImageView
- android:id="@+id/widget_icon"
- android:layout_width="50dp"
- android:layout_height="24dp"
- android:tint="@android:color/black"
- android:src="@drawable/ic_settings"
- android:layout_gravity="center_vertical" />
-
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/punctuation_layout.xml b/packages/SystemUI/res/layout/punctuation_layout.xml
deleted file mode 100644
index 25c7648530d6..000000000000
--- a/packages/SystemUI/res/layout/punctuation_layout.xml
+++ /dev/null
@@ -1,100 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/punctuation_layout"
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="start">
- <TextView
- android:id="@+id/punctuation1"
- android:textColor="?android:attr/textColorSecondary"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
- android:textSize="36sp"
- android:textStyle="bold"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="5dp"
- android:maxLines="1"
- android:alpha="0.2"
- android:rotation="350"/>
- <TextView
- android:id="@+id/punctuation2"
- android:textColor="?android:attr/textColorSecondary"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
- android:textSize="36sp"
- android:textStyle="bold"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="25dp"
- android:maxLines="1"
- android:alpha="0.2"
- android:rotation="5"/>
- <TextView
- android:id="@+id/punctuation3"
- android:textColor="?android:attr/textColorSecondary"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
- android:textSize="36sp"
- android:textStyle="bold"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="5dp"
- android:layout_marginStart="25dp"
- android:maxLines="1"
- android:alpha="0.2"
- android:rotation="355"/>
- <TextView
- android:id="@+id/punctuation4"
- android:textColor="?android:attr/textColorSecondary"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
- android:textSize="36sp"
- android:textStyle="bold"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="-5dp"
- android:layout_marginStart="25dp"
- android:maxLines="1"
- android:alpha="0.2"
- android:rotation="10"/>
- <TextView
- android:id="@+id/punctuation5"
- android:textColor="?android:attr/textColorSecondary"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
- android:textSize="36sp"
- android:textStyle="bold"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="5dp"
- android:layout_marginStart="25dp"
- android:maxLines="1"
- android:alpha="0.2"
- android:rotation="15"/>
- <TextView
- android:id="@+id/punctuation6"
- android:textColor="?android:attr/textColorSecondary"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
- android:textSize="36sp"
- android:textStyle="bold"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="-5dp"
- android:layout_marginStart="25dp"
- android:maxLines="1"
- android:alpha="0.2"
- android:rotation="345"/>
-</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_add_tiles_list.xml b/packages/SystemUI/res/layout/qs_add_tiles_list.xml
deleted file mode 100644
index 312c207446b6..000000000000
--- a/packages/SystemUI/res/layout/qs_add_tiles_list.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 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.
--->
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <ListView
- android:id="@android:id/list"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
- <TextView
- android:paddingTop="10dp"
- android:id="@+id/empty_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:text="@string/no_tiles_add" />
-</FrameLayout>
diff --git a/packages/SystemUI/res/layout/qs_page_indicator.xml b/packages/SystemUI/res/layout/qs_page_indicator.xml
deleted file mode 100644
index 583753a362f1..000000000000
--- a/packages/SystemUI/res/layout/qs_page_indicator.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2016 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.PageIndicator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/page_indicator"
- android:layout_width="match_parent"
- android:layout_height="48dp"
- android:layout_gravity="center"
- android:layout_marginBottom="24dp"
- android:focusable="true"
- android:gravity="center"
- android:importantForAccessibility="yes"
- android:visibility="gone"/>
diff --git a/packages/SystemUI/res/layout/qs_tile_layout.xml b/packages/SystemUI/res/layout/qs_tile_layout.xml
deleted file mode 100644
index b5d1a1e90a0f..000000000000
--- a/packages/SystemUI/res/layout/qs_tile_layout.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 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.TileLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_height="wrap_content"
- android:layout_width="match_parent" />
diff --git a/packages/SystemUI/res/layout/qs_user_dialog_content.xml b/packages/SystemUI/res/layout/qs_user_dialog_content.xml
index 543b7d77243b..9495ee6f3139 100644
--- a/packages/SystemUI/res/layout/qs_user_dialog_content.xml
+++ b/packages/SystemUI/res/layout/qs_user_dialog_content.xml
@@ -16,78 +16,74 @@
~ limitations under the License.
-->
-<FrameLayout
+<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:sysui="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <androidx.constraintlayout.widget.ConstraintLayout
- android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="24dp"
+ android:layout_marginStart="16dp"
+ android:layout_marginEnd="16dp"
+>
+ <TextView
+ android:id="@+id/title"
android:layout_height="wrap_content"
- android:padding="24dp"
- android:layout_marginStart="16dp"
- android:layout_marginEnd="16dp"
- >
- <TextView
- android:id="@+id/title"
- android:layout_height="wrap_content"
- android:layout_width="0dp"
- android:textAlignment="center"
- android:text="@string/qs_user_switch_dialog_title"
- android:textAppearance="@style/TextAppearance.QSDialog.Title"
- android:layout_marginBottom="32dp"
- sysui:layout_constraintTop_toTopOf="parent"
- sysui:layout_constraintStart_toStartOf="parent"
- sysui:layout_constraintEnd_toEndOf="parent"
- sysui:layout_constraintBottom_toTopOf="@id/grid"
- />
-
- <com.android.systemui.qs.PseudoGridView
- android:id="@+id/grid"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="28dp"
- sysui:verticalSpacing="4dp"
- sysui:horizontalSpacing="4dp"
- sysui:fixedChildWidth="80dp"
- sysui:layout_constraintTop_toBottomOf="@id/title"
- sysui:layout_constraintStart_toStartOf="parent"
- sysui:layout_constraintEnd_toEndOf="parent"
- sysui:layout_constraintBottom_toTopOf="@id/barrier"
+ android:layout_width="0dp"
+ android:textAlignment="center"
+ android:text="@string/qs_user_switch_dialog_title"
+ android:textAppearance="@style/TextAppearance.QSDialog.Title"
+ android:layout_marginBottom="32dp"
+ sysui:layout_constraintTop_toTopOf="parent"
+ sysui:layout_constraintStart_toStartOf="parent"
+ sysui:layout_constraintEnd_toEndOf="parent"
+ sysui:layout_constraintBottom_toTopOf="@id/grid"
/>
- <androidx.constraintlayout.widget.Barrier
- android:id="@+id/barrier"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- sysui:barrierDirection="top"
- sysui:constraint_referenced_ids="settings,done"
- />
+ <com.android.systemui.qs.PseudoGridView
+ android:id="@+id/grid"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="28dp"
+ sysui:verticalSpacing="4dp"
+ sysui:horizontalSpacing="4dp"
+ sysui:fixedChildWidth="80dp"
+ sysui:layout_constraintTop_toBottomOf="@id/title"
+ sysui:layout_constraintStart_toStartOf="parent"
+ sysui:layout_constraintEnd_toEndOf="parent"
+ sysui:layout_constraintBottom_toTopOf="@id/barrier"
+ />
- <Button
- android:id="@+id/settings"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:text="@string/quick_settings_more_user_settings"
- sysui:layout_constraintTop_toBottomOf="@id/barrier"
- sysui:layout_constraintBottom_toBottomOf="parent"
- sysui:layout_constraintStart_toStartOf="parent"
- sysui:layout_constraintEnd_toStartOf="@id/done"
- sysui:layout_constraintHorizontal_chainStyle="spread_inside"
- style="@style/Widget.QSDialog.Button.BorderButton"
- />
+ <androidx.constraintlayout.widget.Barrier
+ android:id="@+id/barrier"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ sysui:barrierDirection="top"
+ sysui:constraint_referenced_ids="settings,done"
+ />
- <Button
- android:id="@+id/done"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:text="@string/quick_settings_done"
- sysui:layout_constraintTop_toBottomOf="@id/barrier"
- sysui:layout_constraintBottom_toBottomOf="parent"
- sysui:layout_constraintStart_toEndOf="@id/settings"
- sysui:layout_constraintEnd_toEndOf="parent"
- style="@style/Widget.QSDialog.Button"
- />
+ <Button
+ android:id="@+id/settings"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:text="@string/quick_settings_more_user_settings"
+ sysui:layout_constraintTop_toBottomOf="@id/barrier"
+ sysui:layout_constraintBottom_toBottomOf="parent"
+ sysui:layout_constraintStart_toStartOf="parent"
+ sysui:layout_constraintEnd_toStartOf="@id/done"
+ sysui:layout_constraintHorizontal_chainStyle="spread_inside"
+ style="@style/Widget.QSDialog.Button.BorderButton"
+ />
+
+ <Button
+ android:id="@+id/done"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:text="@string/quick_settings_done"
+ sysui:layout_constraintTop_toBottomOf="@id/barrier"
+ sysui:layout_constraintBottom_toBottomOf="parent"
+ sysui:layout_constraintStart_toEndOf="@id/settings"
+ sysui:layout_constraintEnd_toEndOf="parent"
+ style="@style/Widget.QSDialog.Button"
+ />
- </androidx.constraintlayout.widget.ConstraintLayout>
-</FrameLayout> \ No newline at end of file
+</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 6b14c96b58e2..10a2f4c625c6 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -63,7 +63,7 @@
android:id="@+id/qqs_footer_actions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
+ android:layout_marginTop="@dimen/qqs_layout_margin_top"
android:layout_marginStart="@dimen/qs_footer_margin"
android:layout_marginEnd="@dimen/qs_footer_margin"
/>
diff --git a/packages/SystemUI/res/layout/recents_onboarding.xml b/packages/SystemUI/res/layout/recents_onboarding.xml
deleted file mode 100644
index 2538612db452..000000000000
--- a/packages/SystemUI/res/layout/recents_onboarding.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:paddingBottom="13dp"
- android:orientation="vertical">
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="24dp"
- android:paddingEnd="4dp"
- android:background="@drawable/recents_onboarding_toast_rounded_background"
- android:layout_gravity="center_horizontal"
- android:elevation="2dp"
- android:orientation="horizontal">
-
- <TextView
- android:id="@+id/onboarding_text"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_gravity="center_vertical"
- android:textColor="?attr/wallpaperTextColor"
- android:textSize="16sp"/>
- <ImageView
- android:id="@+id/dismiss"
- android:layout_width="40dp"
- android:layout_height="40dp"
- android:layout_gravity="center_vertical"
- android:padding="10dp"
- android:layout_marginStart="2dp"
- android:layout_marginEnd="2dp"
- android:alpha="0.7"
- android:src="@drawable/ic_close_white"
- android:tint="?attr/wallpaperTextColor"
- android:background="?android:attr/selectableItemBackgroundBorderless"
- android:contentDescription="@string/accessibility_desc_close"/>
- </LinearLayout>
-
- <View
- android:id="@+id/arrow"
- android:elevation="2dp"
- android:layout_width="10dp"
- android:layout_height="8dp"
- android:layout_marginTop="-2dp"
- android:layout_gravity="center_horizontal"/>
-</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/remember_permission_checkbox.xml b/packages/SystemUI/res/layout/remember_permission_checkbox.xml
deleted file mode 100644
index 4985ff5a72ad..000000000000
--- a/packages/SystemUI/res/layout/remember_permission_checkbox.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 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.
--->
-
-<!-- Check box that is displayed in the activity resolver UI for the user
- to make their selection the preferred activity. -->
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
- android:paddingTop="16dp">
-
- <CheckBox
- android:id="@+id/remember"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:focusable="true"
- android:clickable="true"
- android:text="@string/media_projection_remember_text" />
-</FrameLayout>
diff --git a/packages/SystemUI/res/layout/rotate_suggestion.xml b/packages/SystemUI/res/layout/rotate_suggestion.xml
index 1c3eedba4f6f..2fb775cbc9be 100644
--- a/packages/SystemUI/res/layout/rotate_suggestion.xml
+++ b/packages/SystemUI/res/layout/rotate_suggestion.xml
@@ -18,15 +18,13 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
>
-
- <com.android.systemui.navigationbar.buttons.KeyButtonView
+ <com.android.systemui.shared.rotation.FloatingRotationButtonView
android:id="@+id/rotate_suggestion"
android:layout_width="@dimen/floating_rotation_button_diameter"
android:layout_height="@dimen/floating_rotation_button_diameter"
- android:contentDescription="@string/accessibility_rotate_button"
android:paddingStart="@dimen/navigation_key_padding"
android:paddingEnd="@dimen/navigation_key_padding"
android:layout_gravity="bottom|left"
android:scaleType="center"
android:visibility="invisible" />
-</FrameLayout> \ No newline at end of file
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/rounded_corners.xml b/packages/SystemUI/res/layout/rounded_corners.xml
deleted file mode 100644
index 04fe9184cf60..000000000000
--- a/packages/SystemUI/res/layout/rounded_corners.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-** Copyright 2012, 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.
--->
-
-<!-- TODO: remove this in favor of requiring top and bottom layouts -->
-<com.android.systemui.RegionInterceptingFrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/rounded_corners_default"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <ImageView
- android:id="@+id/left"
- android:layout_width="12dp"
- android:layout_height="12dp"
- android:layout_gravity="left|top"
- android:tint="#ff000000"
- android:src="@drawable/rounded"/>
-
- <FrameLayout
- android:id="@+id/privacy_dot_left_container"
- android:layout_height="@dimen/status_bar_height"
- android:layout_width="wrap_content"
- android:layout_marginTop="@dimen/status_bar_padding_top"
- android:layout_marginLeft="8dp"
- android:layout_gravity="left|top"
- android:visibility="invisible" >
- <ImageView
- android:id="@+id/privacy_dot_left"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_gravity="center"
- android:src="@drawable/system_animation_ongoing_dot"
- android:visibility="visible" />
- </FrameLayout>
-
-
- <ImageView
- android:id="@+id/right"
- android:layout_width="12dp"
- android:layout_height="12dp"
- android:tint="#ff000000"
- android:layout_gravity="right|bottom"
- android:src="@drawable/rounded"/>
- <FrameLayout
- android:id="@+id/privacy_dot_right_container"
- android:layout_height="@dimen/status_bar_height"
- android:layout_width="wrap_content"
- android:layout_marginTop="@dimen/status_bar_padding_top"
- android:layout_marginRight="8dp"
- android:layout_gravity="right|top"
- android:visibility="invisible" >
- <ImageView
- android:id="@+id/privacy_dot_right"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_gravity="center"
- android:src="@drawable/system_animation_ongoing_dot"
- android:visibility="visible" />
-
- </FrameLayout>
-
-</com.android.systemui.RegionInterceptingFrameLayout>
diff --git a/packages/SystemUI/res/layout/screen_record_dialog.xml b/packages/SystemUI/res/layout/screen_record_dialog.xml
index c122829c01b6..e43a149a6cd9 100644
--- a/packages/SystemUI/res/layout/screen_record_dialog.xml
+++ b/packages/SystemUI/res/layout/screen_record_dialog.xml
@@ -17,8 +17,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:background="@drawable/rounded_bg_full">
+ android:orientation="vertical">
<!-- Scrollview is necessary to fit everything in landscape layout -->
<ScrollView
diff --git a/packages/SystemUI/res/layout/shelf_menu_anchor.xml b/packages/SystemUI/res/layout/shelf_menu_anchor.xml
deleted file mode 100644
index 984f65539f97..000000000000
--- a/packages/SystemUI/res/layout/shelf_menu_anchor.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 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.
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:alpha="0">
- <ImageView android:id="@+id/shelf_menu_anchor_anchor"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:alpha="0"/>
-</FrameLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index cc1af873ce2b..82186c13394e 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -75,7 +75,11 @@
android:clipToPadding="false"
android:clipChildren="false">
- <include layout="@layout/split_shade_header"/>
+ <ViewStub
+ android:id="@+id/qs_header_stub"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ />
<include
layout="@layout/keyguard_status_view"
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 5176d966a694..6f5d7beb8008 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -18,7 +18,7 @@
-->
<!-- This is the status bar window. -->
-<com.android.systemui.statusbar.phone.StatusBarWindowView
+<com.android.systemui.statusbar.window.StatusBarWindowView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:sysui="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
@@ -35,4 +35,4 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/system_bar_background" />
-</com.android.systemui.statusbar.phone.StatusBarWindowView>
+</com.android.systemui.statusbar.window.StatusBarWindowView>
diff --git a/packages/SystemUI/res/layout/tuner_activity.xml b/packages/SystemUI/res/layout/tuner_activity.xml
index 0b792aecc5ca..83cbf14edd39 100644
--- a/packages/SystemUI/res/layout/tuner_activity.xml
+++ b/packages/SystemUI/res/layout/tuner_activity.xml
@@ -16,9 +16,7 @@
-->
<!-- The tuner content view -->
-<LinearLayout
- android:id="@+id/content_parent"
- xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
diff --git a/packages/SystemUI/res/layout/udfps_surface_view.xml b/packages/SystemUI/res/layout/udfps_surface_view.xml
deleted file mode 100644
index 18858d62a64c..000000000000
--- a/packages/SystemUI/res/layout/udfps_surface_view.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<com.android.systemui.biometrics.UdfpsSurfaceView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/udfps_surface_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
diff --git a/packages/SystemUI/res/mipmap-hdpi/ic_daydreams.png b/packages/SystemUI/res/mipmap-hdpi/ic_daydreams.png
deleted file mode 100644
index 4779a098fa61..000000000000
--- a/packages/SystemUI/res/mipmap-hdpi/ic_daydreams.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/mipmap-mdpi/ic_daydreams.png b/packages/SystemUI/res/mipmap-mdpi/ic_daydreams.png
deleted file mode 100644
index b3a634d974c9..000000000000
--- a/packages/SystemUI/res/mipmap-mdpi/ic_daydreams.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/mipmap-xhdpi/ic_daydreams.png b/packages/SystemUI/res/mipmap-xhdpi/ic_daydreams.png
deleted file mode 100644
index 50b1f50153b3..000000000000
--- a/packages/SystemUI/res/mipmap-xhdpi/ic_daydreams.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/transition/tv_privacy_chip_collapse.xml b/packages/SystemUI/res/transition/tv_privacy_chip_collapse.xml
deleted file mode 100644
index f22e8ef9d005..000000000000
--- a/packages/SystemUI/res/transition/tv_privacy_chip_collapse.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
- <fade android:fadingMode="fade_in" />
- <changeBounds/>
-</transitionSet>
diff --git a/packages/SystemUI/res/transition/tv_privacy_chip_expand.xml b/packages/SystemUI/res/transition/tv_privacy_chip_expand.xml
deleted file mode 100644
index 059ebc84ea7e..000000000000
--- a/packages/SystemUI/res/transition/tv_privacy_chip_expand.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
- <changeBounds/>
- <fade android:fadingMode="fade_out" />
-</transitionSet>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 0873a4f9c001..083e3e48f514 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Groep"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 toestel gekies"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> toestelle gekies"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ontkoppel)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ontkoppel)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Kon nie koppel nie. Probeer weer."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Bind nuwe toestel saam"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Bounommer"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 579b5d278588..e68a6f579497 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"ቡድን"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 መሣሪያ ተመርጧል"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> መሣሪያዎች ተመርጠዋል"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ግንኙነት ተቋርጧል)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ተቋርጧል)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ማገናኘት አልተቻለም። እንደገና ይሞክሩ።"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"አዲስ መሣሪያ ያጣምሩ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"የግንብ ቁጥር"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 5875d2b9ebb0..60e1f06ba470 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -349,7 +349,7 @@
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"سماعات الأذن الطبية"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"جارٍ التفعيل…"</string>
<string name="quick_settings_brightness_label" msgid="680259653088849563">"السطوع"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"تدوير تلقائي"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"التدوير التلقائي"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"التدوير التلقائي للشاشة"</string>
<string name="accessibility_quick_settings_rotation_value" msgid="2916484894750819251">"وضع <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="quick_settings_rotation_locked_label" msgid="4420863550666310319">"تم قفل التدوير"</string>
@@ -1066,7 +1066,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"نقله إلى الحافة وإخفاؤه"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"نقله إلى خارج الحافة وإظهاره"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"إيقاف/تفعيل"</string>
- <string name="quick_controls_title" msgid="6839108006171302273">"أدوات التحكم بالأجهزة"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"التحكم بالجهاز"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"اختيار تطبيق لإضافة عناصر التحكّم"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="zero">تمت إضافة <xliff:g id="NUMBER_1">%s</xliff:g> عنصر تحكّم.</item>
@@ -1135,7 +1135,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"مجموعة"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"تم اختيار جهاز واحد."</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"تم اختيار <xliff:g id="COUNT">%1$d</xliff:g> جهاز."</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (غير متّصل)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(غير متّصل)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"تعذّر الاتصال. يُرجى إعادة المحاولة."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"إقران جهاز جديد"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"رقم الإصدار"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index d6d2900b8d1c..fc53a1082f80 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -235,7 +235,7 @@
<string name="accessibility_battery_level_charging" msgid="8892191177774027364">"বেটাৰী চাৰ্জ হৈ আছে, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> শতাংশ।"</string>
<string name="accessibility_settings_button" msgid="2197034218538913880">"ছিষ্টেমৰ ছেটিং৷"</string>
<string name="accessibility_notifications_button" msgid="3960913924189228831">"জাননীসমূহ।"</string>
- <string name="accessibility_overflow_action" msgid="8555835828182509104">"সকলো জাননীবোৰ চাওক"</string>
+ <string name="accessibility_overflow_action" msgid="8555835828182509104">"আটাইবোৰ জাননী চাওক"</string>
<string name="accessibility_remove_notification" msgid="1641455251495815527">"জাননী মচক৷"</string>
<string name="accessibility_gps_enabled" msgid="4061313248217660858">"জিপিএছ সক্ষম হ\'ল৷"</string>
<string name="accessibility_gps_acquiring" msgid="896207402196024040">"জিপিএছ বিচাৰি থকা হৈছে।"</string>
@@ -311,7 +311,7 @@
<string name="gps_notification_found_text" msgid="3145873880174658526">"জিপিএছএ অৱস্থান ছেট কৰিছে"</string>
<string name="accessibility_location_active" msgid="2845747916764660369">"অৱস্থানৰ অনুৰোধ সক্ৰিয় হৈ আছে"</string>
<string name="accessibility_sensors_off_active" msgid="2619725434618911551">"ছেন্সৰ অফ সক্ৰিয় কৰা আছে"</string>
- <string name="accessibility_clear_all" msgid="970525598287244592">"সকলো জাননী মচক৷"</string>
+ <string name="accessibility_clear_all" msgid="970525598287244592">"আটাইবোৰ জাননী মচক৷"</string>
<string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192">
<item quantity="one"> ভিতৰত আৰু <xliff:g id="NUMBER_1">%s</xliff:g>টা জাননী আছে।</item>
@@ -448,8 +448,8 @@
<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" msgid="6117517737057344014">"এই কার্যই এলার্ম, মিউজিক, ভিডিঅ\' আৰু গেইমকে ধৰি সকলোৰে ধ্বনি আৰু কম্পন অৱৰোধ কৰে।"</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>
@@ -482,7 +482,7 @@
<string name="user_add_user" msgid="4336657383006913022">"ব্যৱহাৰকাৰী যোগ কৰক"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"নতুন ব্যৱহাৰকাৰী"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"অতিথি আঁতৰাবনে?"</string>
- <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই ছেশ্বনৰ সকলো এপ্ আৰু ডেটা মচা হ\'ব।"</string>
+ <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই ছেশ্বনৰ আটাইবোৰ এপ্ আৰু ডেটা মচা হ\'ব।"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"আঁতৰাওক"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"অতিথি, আপোনাক পুনৰ স্বাগতম!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"আপুনি আপোনাৰ ছেশ্বন অব্যাহত ৰাখিব বিচাৰেনে?"</string>
@@ -502,24 +502,24 @@
<item quantity="other">আপুনি <xliff:g id="COUNT">%d</xliff:g> জনলৈকে ব্যৱহাৰকাৰী যোগ কৰিব পাৰে।</item>
</plurals>
<string name="user_remove_user_title" msgid="9124124694835811874">"ব্যৱহাৰকাৰীক আঁতৰাবনে?"</string>
- <string name="user_remove_user_message" msgid="6702834122128031833">"এই ব্যৱহাৰকাৰীৰ সকলো এপ্ আৰু ডেটা মচা হ\'ব।"</string>
+ <string name="user_remove_user_message" msgid="6702834122128031833">"এই ব্যৱহাৰকাৰীৰ আটাইবোৰ এপ্ আৰু ডেটা মচা হ\'ব।"</string>
<string name="user_remove_user_remove" msgid="8387386066949061256">"আঁতৰাওক"</string>
<string name="battery_saver_notification_title" msgid="8419266546034372562">"বেটাৰী সঞ্চয়কাৰী অন হৈ আছে"</string>
<string name="battery_saver_notification_text" msgid="2617841636449016951">"কাৰ্যদক্ষতা আৰু নেপথ্য ডেটা হ্ৰাস কৰে"</string>
<string name="battery_saver_notification_action_text" msgid="6022091913807026887">"বেটাৰী সঞ্চয়কাৰী অফ কৰক"</string>
- <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>এ আপোনাৰ স্ক্ৰীনত দৃশ্যমান হোৱা অথবা ৰেকর্ডিং অথবা কাষ্টিঙৰ সময়ত আপোনাৰ ডিভাইচত প্লে\' কৰা সকলো তথ্যলৈ এক্সেছ পাব। এইটোত পাছৱর্ড, পৰিশোধৰ সবিশেষ, ফট\', বার্তাসমূহ আৰু আপুনি প্লে\' কৰা অডিঅ\'ৰ দৰে তথ্য অন্তর্ভুক্ত হয়।"</string>
- <string name="media_projection_dialog_service_text" msgid="958000992162214611">"এই সুবিধাটো প্ৰদান কৰা সেৱাটোৱে আপোনাৰ স্ক্ৰীনত দৃশ্যমান হোৱা অথবা ৰেকর্ডিং অথবা কাষ্টিংৰ সময়ত আপোনাৰ ডিভাইচত প্লে\' কৰা সকলো তথ্যলৈ এক্সেছ পাব। এইটোত পাছৱর্ড, পৰিশোধৰ সবিশেষ, ফট\', বার্তাসমূহ আৰু আপুনি প্লে\' কৰা অডিঅ\'ৰ দৰে তথ্য অন্তর্ভুক্ত হয়।"</string>
+ <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>এ আপোনাৰ স্ক্ৰীনত দৃশ্যমান হোৱা অথবা ৰেকর্ডিং অথবা কাষ্টিঙৰ সময়ত আপোনাৰ ডিভাইচত প্লে\' কৰা আটাইবোৰ তথ্যলৈ এক্সেছ পাব। এইটোত পাছৱর্ড, পৰিশোধৰ সবিশেষ, ফট\', বার্তাসমূহ আৰু আপুনি প্লে\' কৰা অডিঅ\'ৰ দৰে তথ্য অন্তর্ভুক্ত হয়।"</string>
+ <string name="media_projection_dialog_service_text" msgid="958000992162214611">"এই সুবিধাটো প্ৰদান কৰা সেৱাটোৱে আপোনাৰ স্ক্ৰীনত দৃশ্যমান হোৱা অথবা ৰেকর্ডিং অথবা কাষ্টিঙৰ সময়ত আপোনাৰ ডিভাইচত প্লে\' কৰা আটাইবোৰ তথ্যলৈ এক্সেছ পাব। এইটোত পাছৱর্ড, পৰিশোধৰ সবিশেষ, ফট\', বার্তাসমূহ আৰু আপুনি প্লে\' কৰা অডিঅ\'ৰ দৰে তথ্য অন্তর্ভুক্ত হয়।"</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ৰেকর্ডিং অথবা কাষ্টিং আৰম্ভ কৰিবনে?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>ৰ জৰিয়তে ৰেকর্ডিং অথবা কাষ্টিং আৰম্ভ কৰিবনে ?"</string>
<string name="media_projection_remember_text" msgid="6896767327140422951">"পুনৰাই নেদেখুৱাব"</string>
- <string name="clear_all_notifications_text" msgid="348312370303046130">"সকলো মচক"</string>
+ <string name="clear_all_notifications_text" msgid="348312370303046130">"আটাইবোৰ মচক"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"পৰিচালনা"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"ইতিহাস"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"নতুন"</string>
<string name="notification_section_header_gentle" msgid="6804099527336337197">"নীৰৱ"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"জাননীসমূহ"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"বাৰ্তালাপ"</string>
- <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"সকলো নীৰৱ জাননী মচক"</string>
+ <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"আটাইবোৰ নীৰৱ জাননী মচক"</string>
<string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"অসুবিধা নিদিব-ই জাননী পজ কৰিছে"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"এতিয়াই আৰম্ভ কৰক"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"কোনো জাননী নাই"</string>
@@ -704,7 +704,7 @@
<string name="enable_bluetooth_message" msgid="6740938333772779717">"আপোনাৰ টেবলেটত আপোনাৰ কীব\'ৰ্ড সংযোগ কৰিবলৈ আপুনি প্ৰথমে ব্লুটুথ অন কৰিব লাগিব।"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="2866408183324184876">"অন কৰক"</string>
<string name="show_silently" msgid="5629369640872236299">"জাননীসমূহ নীৰৱে দেখুৱাওক"</string>
- <string name="block" msgid="188483833983476566">"সকলো জাননী অৱৰোধ কৰক"</string>
+ <string name="block" msgid="188483833983476566">"আটাইবোৰ জাননী অৱৰোধ কৰক"</string>
<string name="do_not_silence" msgid="4982217934250511227">"নীৰৱ নকৰিব"</string>
<string name="do_not_silence_block" msgid="4361847809775811849">"নীৰৱ অথবা অৱৰোধ নকৰিব"</string>
<string name="tuner_full_importance_settings" msgid="1388025816553459059">"জাননী নিয়ন্ত্ৰণৰ অধিক কৰ্তৃত্ব"</string>
@@ -754,7 +754,7 @@
<string name="notification_unblockable_desc" msgid="2073030886006190804">"এই জাননীসমূহ সংশোধন কৰিব নোৱাৰি।"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"এই ধৰণৰ জাননীবোৰ ইয়াত কনফিগাৰ কৰিব পৰা নাযায়"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"প্ৰক্সি হিচাপে পঠিওৱা জাননী"</string>
- <string name="notification_channel_dialog_title" msgid="6856514143093200019">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ সকলো জাননী"</string>
+ <string name="notification_channel_dialog_title" msgid="6856514143093200019">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ আটাইবোৰ জাননী"</string>
<string name="see_more_title" msgid="7409317011708185729">"অধিক চাওক"</string>
<string name="appops_camera" msgid="5215967620896725715">"এই এপে কেমেৰা ব্য়ৱহাৰ কৰি আছে।"</string>
<string name="appops_microphone" msgid="8805468338613070149">"এই এপে মাইক্ৰ\'ফ\'ন ব্য়ৱহাৰ কৰি আছে।"</string>
@@ -1062,7 +1062,7 @@
<string name="controls_favorite_default_title" msgid="967742178688938137">"নিয়ন্ত্ৰণসমূহ"</string>
<string name="controls_favorite_subtitle" msgid="6481675111056961083">"ক্ষিপ্ৰ ছেটিঙৰ পৰা এক্সেছ কৰিবলৈ নিয়ন্ত্ৰণসমূহ বাছনি কৰক"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"নিয়ন্ত্ৰণসমূহ পুনৰ সজাবলৈ ধৰি ৰাখক আৰু টানি আনি এৰক"</string>
- <string name="controls_favorite_removed" msgid="5276978408529217272">"সকলো নিয়ন্ত্ৰণ আঁতৰোৱা হৈছে"</string>
+ <string name="controls_favorite_removed" msgid="5276978408529217272">"আটাইবোৰ নিয়ন্ত্ৰণ আঁতৰোৱা হৈছে"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"সালসলনিসমূহ ছেভ নহ’ল"</string>
<string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"অন্য এপ্‌সমূহ চাওক"</string>
<string name="controls_favorite_load_error" msgid="5126216176144877419">"নিয়ন্ত্ৰণসমূহ ল’ড কৰিবপৰা নগ’ল। এপ্‌টোৰ ছেটিং সলনি কৰা হোৱা নাই বুলি নিশ্চিত কৰিবলৈ <xliff:g id="APP">%s</xliff:g> এপ্‌টো পৰীক্ষা কৰক।"</string>
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"গোট"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"১ টা ডিভাইচ বাছনি কৰা হৈছে"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> টা ডিভাইচ বাছনি কৰা হৈছে"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (সংযোগ বিচ্ছিন্ন হৈছে)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(সংযোগ বিচ্ছিন্ন কৰা হৈছে)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"সংযোগ কৰিব পৰা নগ’ল। পুনৰ চেষ্টা কৰক।"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"নতুন ডিভাইচ পেয়াৰ কৰক"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"বিল্ডৰ নম্বৰ"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index a23283437a7f..1f1997fdaf6b 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Qrup"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 cihaz seçilib"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> cihaz seçilib"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (bağlantı kəsilib)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(bağlantı kəsildi)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Qoşulmaq alınmadı. Yenə cəhd edin."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Cihaz əlavə edin"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Montaj nömrəsi"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index caab5543aded..ee82b070f473 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -1117,7 +1117,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupa"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Izabran je 1 uređaj"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Izabranih uređaja: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (veza je prekinuta)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(veza je prekinuta)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Povezivanje nije uspelo. Probajte ponovo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Upari novi uređaj"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
@@ -1161,7 +1161,7 @@
<string name="person_available" msgid="2318599327472755472">"Dostupno"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem sa očitavanjem merača baterije"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dodirnite za više informacija"</string>
- <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Alarm nije podešen"</string>
+ <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nije podešen"</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Senzor za otisak prsta"</string>
<string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"Senzor za otisak prsta je onemogućen"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"potvrdite identitet"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index d327b4deb4e2..58dbe0e180db 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -1123,7 +1123,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Група"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Выбрана 1 прылада"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Выбрана прылад: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (адключана)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(адключана)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Не ўдалося падключыцца. Паўтарыце спробу."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Спалучыць з новай прыладай"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Нумар зборкі"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 42b80f4aceae..8968dab785fe 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Група"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 избрано устройство"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> избрани устройства"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (връзката е прекратена)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(връзката е прекратена)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Неуспешно свързване. Опитайте отново."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Сдвояване на ново устройство"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер на компилацията"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 5b8c662213af..3478b4d90431 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"গ্রুপ"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"১টি ডিভাইস বেছে নেওয়া হয়েছে"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g>টি ডিভাইস বেছে নেওয়া হয়েছে"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (কানেক্ট করা নেই)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ডিসকানেক্ট হয়ে গেছে)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"কানেক্ট করা যায়নি। আবার চেষ্টা করুন।"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"নতুন ডিভাইস পেয়ার করুন"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"বিল্ড নম্বর"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 19e868f5e6ea..84e806f17b3d 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -1117,7 +1117,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupa"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Odabran je 1 uređaj"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Broj odabranih uređaja: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (veza je prekinuta)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(veza je prekinuta)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Povezivanje nije uspjelo. Pokušajte ponovo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uparite novi uređaj"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index f31a72dad3a3..8dedb28b23eb 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grup"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositiu seleccionat"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"S\'han seleccionat <xliff:g id="COUNT">%1$d</xliff:g> dispositius"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (desconnectat)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(desconnectat)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"No s\'ha pogut connectar. Torna-ho a provar."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincula un dispositiu nou"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilació"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 05e4b1ec0207..fbef25aa7800 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -1123,7 +1123,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Skupina"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Je vybráno 1 zařízení"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Vybraná zařízení: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (odpojeno)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(odpojeno)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Spojení se nezdařilo. Zkuste to znovu."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Spárovat nové zařízení"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo sestavení"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 8145ffa2de46..72771df230a3 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Gruppe"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Der er valgt 1 enhed"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Der er valgt <xliff:g id="COUNT">%1$d</xliff:g> enhed"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ingen forbindelse)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(afbrudt)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Der kunne ikke oprettes forbindelse. Prøv igen."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Par ny enhed"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildnummer"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index fc36c84914f8..933de430bdb3 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Gruppe"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Ein Gerät ausgewählt"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> Geräte ausgewählt"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (nicht verbunden)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(nicht verbunden)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Verbindung nicht möglich. Versuch es noch einmal."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Neues Gerät koppeln"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build-Nummer"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index a93fec5d25f6..bd197608cd07 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Ομάδα"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Επιλέχτηκε 1 συσκευή"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Επιλέχτηκαν <xliff:g id="COUNT">%1$d</xliff:g> συσκευές"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (αποσυνδέθηκε)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(αποσυνδέθηκε)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Δεν ήταν δυνατή η σύνδεση. Δοκιμάστε ξανά."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Σύζευξη νέας συσκευής"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Αριθμός έκδοσης"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 2f4a17d07b62..8f8f195a2a71 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Group"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"One device selected"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> devices selected"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (disconnected)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnected)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index e1ab43a00da4..5532dcb84da0 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Group"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"One device selected"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> devices selected"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (disconnected)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnected)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 2f4a17d07b62..8f8f195a2a71 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Group"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"One device selected"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> devices selected"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (disconnected)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnected)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 2f4a17d07b62..8f8f195a2a71 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Group"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"One device selected"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> devices selected"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (disconnected)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnected)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Couldn\'t connect. Try again."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 7ddbdd69850b..1b538a7bf9ce 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‏‎‏‎‎‏‎‎‎‏‎‏‎‎‏‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‎‎Group‎‏‎‎‏‎"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‏‏‏‎‎‏‏‎‏‏‎‏‏‎‏‏‎‏‎‏‎‎‏‎‎‎‎‏‏‏‎‎‏‏‎‎‏‏‎‏‎‏‎‎‎‎‏‎‎‏‎‎1 device selected‎‏‎‎‏‎"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‏‏‏‎‏‏‎‏‎‏‏‏‏‎‏‏‏‎‏‎‏‎‎‏‏‏‎‎‏‏‏‎‎‎‎‏‏‎‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="COUNT">%1$d</xliff:g>‎‏‎‎‏‏‏‎ devices selected‎‏‎‎‏‎"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‏‏‎‏‏‏‎‎‏‎‎‎‏‏‏‎‎‎‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‏‎‎‏‎‏‏‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ (disconnected)‎‏‎‎‏‎"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎‎‏‏‎‏‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‏‎‏‏‏‎‎‎‎‎‎‏‎‏‏‎‏‎‎‎‏‎‎‏‎‎‎‏‎(disconnected)‎‏‎‎‏‎"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‎‎‎‏‎‎‎‏‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‏‎‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎Couldn\'t connect. Try again.‎‏‎‎‏‎"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‎‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎Pair new device‎‏‎‎‏‎"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‎‎‏‎‎Build number‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 95cd9ba1b13d..08d0a0523b6d 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -807,7 +807,7 @@
<string name="battery_detail_switch_title" msgid="6940976502957380405">"Ahorro de batería"</string>
<string name="battery_detail_switch_summary" msgid="3668748557848025990">"Reduce el rendimiento y el uso de datos en segundo plano"</string>
<string name="keyboard_key_button_template" msgid="8005673627272051429">"Botón <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="keyboard_key_home" msgid="3734400625170020657">"Página principal"</string>
+ <string name="keyboard_key_home" msgid="3734400625170020657">"Inicio"</string>
<string name="keyboard_key_back" msgid="4185420465469481999">"Atrás"</string>
<string name="keyboard_key_dpad_up" msgid="2164184320424941416">"Arriba"</string>
<string name="keyboard_key_dpad_down" msgid="2110172278574325796">"Abajo"</string>
@@ -827,7 +827,7 @@
<string name="keyboard_key_page_up" msgid="173914303254199845">"Re Pág"</string>
<string name="keyboard_key_page_down" msgid="9035902490071829731">"Av Pág"</string>
<string name="keyboard_key_forward_del" msgid="5325501825762733459">"Borrar"</string>
- <string name="keyboard_key_move_home" msgid="3496502501803911971">"Página principal"</string>
+ <string name="keyboard_key_move_home" msgid="3496502501803911971">"Inicio"</string>
<string name="keyboard_key_move_end" msgid="99190401463834854">"Fin"</string>
<string name="keyboard_key_insert" msgid="4621692715704410493">"Insertar"</string>
<string name="keyboard_key_num_lock" msgid="7209960042043090548">"Bloqueo numérico"</string>
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Se seleccionó 1 dispositivo"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Se seleccionaron <xliff:g id="COUNT">%1$d</xliff:g> dispositivos"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (desconectado)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(desconectado)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"No se pudo establecer la conexión. Vuelve a intentarlo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular dispositivo nuevo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 15af90396cba..eda51baac58f 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo seleccionado"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> dispositivos seleccionados"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (desconectado)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(desconectado)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"No se ha podido conectar. Inténtalo de nuevo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Emparejar nuevo dispositivo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 39d29cc4fc98..e67462791bbd 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -345,7 +345,7 @@
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Kuuldeaparaadid"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Sisselülitamine …"</string>
<string name="quick_settings_brightness_label" msgid="680259653088849563">"Heledus"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automaatne pööramine"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. pööramine"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Kuva automaatne pööramine"</string>
<string name="accessibility_quick_settings_rotation_value" msgid="2916484894750819251">"Režiim <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="quick_settings_rotation_locked_label" msgid="4420863550666310319">"Pööramine on lukustatud"</string>
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupp"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 seade on valitud"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> seadet on valitud"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (pole ühendatud)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ühendus on katkestatud)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ühenduse loomine ebaõnnestus. Proovige uuesti."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uue seadme sidumine"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Järgunumber"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index bacf6efa74cd..5f3a2863e1b1 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Taldea"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 gailu hautatu da"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> gailu hautatu dira"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (deskonektatuta)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(deskonektatuta)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ezin izan da konektatu. Saiatu berriro."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parekatu beste gailu batekin"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Konpilazio-zenbakia"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 9a9c20f2eb5d..6cd43497a14b 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"گروه"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"۱ دستگاه انتخاب شد"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> دستگاه انتخاب شد"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (اتصال قطع شد)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(اتصال قطع شد)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"متصل نشد. دوباره امتحان کنید."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"مرتبط کردن دستگاه جدید"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"شماره ساخت"</string>
@@ -1155,7 +1155,7 @@
<string name="person_available" msgid="2318599327472755472">"دردسترس"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"مشکلی در خواندن میزان باتری وجود دارد"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"برای اطلاعات بیشتر ضربه بزنید"</string>
- <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"هشداری تنظیم نشده است"</string>
+ <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"هشداری تنظیم نشده"</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"حسگر اثرانگشت"</string>
<string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"حسگر اثر انگشت غیرفعال است"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"اصالت‌سنجی کردن"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index ca0f4525a40d..c0dc8a070ec1 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -1046,7 +1046,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Siirrä reunaan ja piilota"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Siirrä pois reunasta ja näytä"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"vaihda"</string>
- <string name="quick_controls_title" msgid="6839108006171302273">"Laitteiden hallinta"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Laitehallinta"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Valitse sovellus lisätäksesi säätimiä"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> säädintä lisätty</item>
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Ryhmä"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 laite valittu"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> laitetta valittu"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (yhteys katkaistu)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(yhteys katkaistu)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ei yhteyttä. Yritä uudelleen."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Muodosta uusi laitepari"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Koontiversion numero"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index ef4f86dc4b71..675c30c6449a 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Groupe"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Un appareil sélectionné"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> appareil sélectionné"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (déconnecté)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(déconnecté)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Impossible de se connecter. Réessayez."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Associer un autre appareil"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numéro de version"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 3d6dd559855a..e3d6ef9fa5d1 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Groupe"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 appareil sélectionné"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> appareils sélectionnés"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (déconnecté)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(déconnecté)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Impossible de se connecter. Réessayez."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Associer un nouvel appareil"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numéro de build"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 8570e9a6b52b..e12796a58e90 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Seleccionouse 1 dispositivo"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Seleccionáronse <xliff:g id="COUNT">%1$d</xliff:g> dispositivos"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (dispositivo desconectado)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(desconectado)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Non se puido establecer a conexión. Téntao de novo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular dispositivo novo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 95efbad63afe..e81fedb8181c 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"ગ્રૂપ"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 ડિવાઇસ પસંદ કર્યું"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> ડિવાઇસ પસંદ કર્યા"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ડિસ્કનેક્ટ થયેલું)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ડિસ્કનેક્ટ કરેલું)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"કનેક્ટ કરી શકાયું નહીં. ફરી પ્રયાસ કરો."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"નવા ડિવાઇસ સાથે જોડાણ કરો"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"બિલ્ડ નંબર"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 2a6475566a69..d344f3e5cd96 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"ग्रुप"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"एक डिवाइस चुना गया"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> डिवाइस चुने गए"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (डिसकनेक्ट किया गया)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(डिसकनेक्ट हो गया)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"कनेक्ट नहीं किया जा सका. फिर से कोशिश करें."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नया डिवाइस जोड़ें"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 3edd928b9488..59179e627eb5 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -346,7 +346,7 @@
<string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="3003338571871392293">"Slušni aparati"</string>
<string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Uključivanje…"</string>
<string name="quick_settings_brightness_label" msgid="680259653088849563">"Svjetlina"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatsko zakretanje"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. zakretanje"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatsko zakretanje zaslona"</string>
<string name="accessibility_quick_settings_rotation_value" msgid="2916484894750819251">"Način: <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="quick_settings_rotation_locked_label" msgid="4420863550666310319">"Izmjenjivanje je zaključano"</string>
@@ -1117,7 +1117,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupa"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Odabran je jedan uređaj"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Odabrano uređaja: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (nije povezano)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(nije povezano)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Povezivanje nije bilo moguće. Pokušajte ponovo."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uparite novi uređaj"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj međuverzije"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 34858083c04a..f1b694ee9342 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Csoport"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 eszköz kiválasztva"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> eszköz kiválasztva"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (leválasztva)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(leválasztva)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Sikertelen csatlakozás. Próbálja újra."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Új eszköz párosítása"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildszám"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index fde4d32ad87b..7e62a823329c 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Խումբ"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Ընտրված է 1 սարք"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Ընտրված է <xliff:g id="COUNT">%1$d</xliff:g> սարք"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (անջատված է)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(անջատված է)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Չհաջողվեց միանալ։ Նորից փորձեք։"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Նոր սարքի զուգակցում"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Կառուցման համարը"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index f3bf7dfc0448..fcb81ba450de 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grup"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 perangkat dipilih"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> perangkat dipilih"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (terputus)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(terputus)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Tidak dapat terhubung. Coba lagi."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sambungkan perangkat baru"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nomor build"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 7cd5444f2a09..52d45fee0fa8 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Hópur"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 tæki valið"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> tæki valin"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (aftengt)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(aftengt)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Tenging mistókst. Reyndu aftur."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Para nýtt tæki"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Útgáfunúmer smíðar"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 496b2871eac4..b4c936570301 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -516,7 +516,7 @@
<string name="manage_notifications_text" msgid="6885645344647733116">"Gestisci"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Cronologia"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"Nuove"</string>
- <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silenziose"</string>
+ <string name="notification_section_header_gentle" msgid="6804099527336337197">"Notifiche silenziose"</string>
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifiche"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Conversazioni"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Cancella tutte le notifiche silenziose"</string>
@@ -1046,7 +1046,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Sposta fino a bordo e nascondi"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Sposta fuori da bordo e mostra"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"attiva/disattiva"</string>
- <string name="quick_controls_title" msgid="6839108006171302273">"Controllo dei dispositivi"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Controllo dispositivi"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Scegli un\'app per aggiungere controlli"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> controlli aggiunti.</item>
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Gruppo"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo selezionato"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> dispositivi selezionati"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (disconnesso)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(disconnesso)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Impossibile connettersi. Riprova."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Accoppia nuovo dispositivo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero build"</string>
@@ -1155,7 +1155,7 @@
<string name="person_available" msgid="2318599327472755472">"Disponibile"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema durante la lettura dell\'indicatore di livello della batteria"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tocca per ulteriori informazioni"</string>
- <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nessuna sveglia"</string>
+ <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nessuna"</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Sensore di impronte digitali"</string>
<string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"Sensore di impronte digitali disattivato"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"effettuare l\'autenticazione"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index ec9d32346493..32be1c12428a 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -1123,7 +1123,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"קבוצה"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"נבחר מכשיר אחד"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"נבחרו <xliff:g id="COUNT">%1$d</xliff:g> מכשירים"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (מנותק)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(מנותק)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"לא ניתן היה להתחבר. יש לנסות שוב."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"התאמה של מכשיר חדש"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"‏מספר Build"</string>
@@ -1167,7 +1167,7 @@
<string name="person_available" msgid="2318599327472755472">"אונליין"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"בעיה בקריאת מדדי הסוללה"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"יש להקיש כדי להציג מידע נוסף"</string>
- <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"לא הוגדרה התראה"</string>
+ <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"לא הוגדרה"</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"חיישן טביעות אצבע"</string>
<string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"חיישן טביעות האצבע מושבת"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"אימות"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index dc8f668d494e..ee9790f19ef5 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"グループ"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"選択したデバイス: 1 台"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"選択したデバイス: <xliff:g id="COUNT">%1$d</xliff:g> 台"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>(未接続)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(接続解除済み)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"接続できませんでした。もう一度お試しください。"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"新しいデバイスとのペア設定"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ビルド番号"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index bcd7af2d7b98..9d34a60ce28d 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"ჯგუფი"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"არჩეულია 1 მოწყობილობა"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"არჩეულია <xliff:g id="COUNT">%1$d</xliff:g> მოწყობილობა"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (კავშირი გაწყვეტილია)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(კავშირი გაწყვეტილია)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"დაკავშირება ვერ მოხერხდა. ცადეთ ხელახლა."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ახალი მოწყობილობის დაწყვილება"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ანაწყობის ნომერი"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 6685dc370943..6f13d09b2169 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Топ"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 құрылғы таңдалды."</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> құрылғы таңдалды."</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ажыратылған)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ажыратулы)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Қосылмады. Қайта қосылып көріңіз."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Жаңа құрылғымен жұптау"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Құрама нөмірі"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 70d10f99e48e..8a3953280d33 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"ក្រុម"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"បានជ្រើសរើស​ឧបករណ៍ 1"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"បានជ្រើសរើស​ឧបករណ៍ <xliff:g id="COUNT">%1$d</xliff:g>"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (បាន​ផ្ដាច់)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(បាន​ដាច់)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"មិន​អាច​ភ្ជាប់​បាន​ទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ផ្គូផ្គង​ឧបករណ៍ថ្មី"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"លេខ​កំណែបង្កើត"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 3a1e6a6739a1..7d0661c30a2b 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"ಗುಂಪು"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 ಸಾಧನವನ್ನು ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> ಸಾಧನಗಳನ್ನು ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ಡಿಸ್‌ಕನೆಕ್ಟ್ ಆಗಿದೆ)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ಹೊಸ ಸಾಧನವನ್ನು ಜೋಡಿಸಿ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ಬಿಲ್ಡ್ ಸಂಖ್ಯೆ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 4b705fbce07f..bd775daef1e4 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"그룹"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"기기 1대 선택됨"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"기기 <xliff:g id="COUNT">%1$d</xliff:g>대 선택됨"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>(연결 끊김)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(연결 끊김)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"연결할 수 없습니다. 다시 시도하세요."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"새 기기와 페어링"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"빌드 번호"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 58114d88f015..272ea77ec5f9 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Топ"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 түзмөк тандалды"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> түзмөк тандалды"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ажыратылды)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ажыратылды)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Байланышпай койду. Кайталоо."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Жаңы түзмөктү жупташтыруу"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Курама номери"</string>
diff --git a/packages/SystemUI/res/values-land/styles.xml b/packages/SystemUI/res/values-land/styles.xml
index 82cba58e48fa..f3d83645a8e0 100644
--- a/packages/SystemUI/res/values-land/styles.xml
+++ b/packages/SystemUI/res/values-land/styles.xml
@@ -25,12 +25,6 @@
<item name="android:layout_gravity">center_horizontal</item>
</style>
- <style name="DockedDividerHandle">
- <item name="android:layout_gravity">center_vertical</item>
- <item name="android:layout_width">48dp</item>
- <item name="android:layout_height">96dp</item>
- </style>
-
<style name="DockedDividerMinimizedShadow">
<item name="android:layout_width">8dp</item>
<item name="android:layout_height">match_parent</item>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 9ff47acbbcdc..820dab60f6d5 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"ກຸ່ມ"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"ເລືອກ 1 ອຸປະກອນແລ້ວ"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"ເລືອກ <xliff:g id="COUNT">%1$d</xliff:g> ອຸປະກອນແລ້ວ"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ຕັດການເຊື່ອມຕໍ່ແລ້ວ)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ຕັດການເຊື່ອມຕໍ່ແລ້ວ)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້. ລອງໃໝ່."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ຈັບຄູ່ອຸປະກອນໃໝ່"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ໝາຍເລກສ້າງ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 0161aafb8952..6a4ecfe06870 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -1123,7 +1123,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupė"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Pasirinktas 1 įrenginys"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Pasirinkta įrenginių: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"„<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“ (atjungta)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(atjungta)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nepavyko prijungti. Bandykite dar kartą."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Naujo įrenginio susiejimas"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijos numeris"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 2ff48e34a0de..0ec38d3c4f81 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -1117,7 +1117,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupa"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Atlasīta viena ierīce"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Atlasītas vairākas ierīces (kopā <xliff:g id="COUNT">%1$d</xliff:g>)"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (savienojums pārtraukts)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(savienojums pārtraukts)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nevarēja izveidot savienojumu. Mēģiniet vēlreiz."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Savienošana pārī ar jaunu ierīci"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijas numurs"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 6c495a719af2..e0a971e86046 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Група"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Избран е 1 уред"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Избрани се <xliff:g id="COUNT">%1$d</xliff:g> уреди"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (исклучен)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(врската е прекината)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Не може да се поврзе. Обидете се повторно."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Спарете нов уред"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Број на верзија"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index db338ef4e634..6fe5815b1543 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"ഗ്രൂപ്പ്"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"ഒരു ഉപകരണം തിരഞ്ഞെടുത്തു"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> ഉപകരണങ്ങൾ തിരഞ്ഞെടുത്തു"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (വിച്ഛേദിച്ചു)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(വിച്ഛേദിച്ചു)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"കണക്റ്റ് ചെയ്യാനായില്ല. വീണ്ടും ശ്രമിക്കുക."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"പുതിയ ഉപകരണവുമായി ജോടിയാക്കുക"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ബിൽഡ് നമ്പർ"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index b34b75b7e2e3..86869533af94 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Бүлэг"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 төхөөрөмж сонгосон"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> төхөөрөмж сонгосон"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (салсан)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(салсан)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Холбогдож чадсангүй. Дахин оролдоно уу."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Шинэ төхөөрөмж хослуулах"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Хийцийн дугаар"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 674290d8e7ec..978217ba2d99 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"गट"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"एक डिव्हाइस निवडले"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> डिव्हाइस निवडली आहेत"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (डिस्कनेक्ट केले)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(डिस्कनेक्ट केलेले)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"कनेक्ट करू शकलो नाही. पुन्हा प्रयत्न करा."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नवीन डिव्हाइससोबत पेअर करा"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index f3490407de17..35909d8e75f9 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Kumpulan"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 peranti dipilih"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> peranti dipilih"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (diputuskan sambungan)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(diputuskan sambungan)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Tidak boleh menyambung. Cuba lagi."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Gandingkan peranti baharu"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nombor binaan"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index b434294ac1d9..ec665e920d43 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -512,7 +512,7 @@
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ရိုက်ကူးဖမ်းယူခြင်း (သို့) ကာစ်လုပ်ခြင်း စတင်မလား။"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> နှင့် ဖမ်းယူခြင်း သို့မဟုတ် ကာစ်လုပ်ခြင်း စတင်မလား။"</string>
<string name="media_projection_remember_text" msgid="6896767327140422951">"နောက်ထပ် မပြပါနှင့်"</string>
- <string name="clear_all_notifications_text" msgid="348312370303046130">"အားလုံးထုတ်ပစ်ရန်"</string>
+ <string name="clear_all_notifications_text" msgid="348312370303046130">"အားလုံးရှင်းရန်"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"စီမံရန်"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"မှတ်တမ်း"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"အသစ်"</string>
@@ -1111,7 +1111,8 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"အုပ်စု"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"စက်ပစ္စည်း ၁ ခုကို ရွေးချယ်ထားသည်"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"စက်ပစ္စည်း <xliff:g id="COUNT">%1$d</xliff:g> ခုကို ရွေးချယ်ထားသည်"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ချိတ်ဆက်မထားပါ)"</string>
+ <!-- no translation found for media_output_dialog_disconnected (7090512852817111185) -->
+ <skip />
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ချိတ်ဆက်၍ မရပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"စက်အသစ် တွဲချိတ်ရန်"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"တည်ဆောက်မှုနံပါတ်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index c64eb1c7d3ea..0c911203bec3 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Gruppe"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 enhet er valgt"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> enheter er valgt"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (frakoblet)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(frakoblet)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Kunne ikke koble til. Prøv på nytt."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Koble til en ny enhet"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Delversjonsnummer"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index fad92262c772..c9a97763acc4 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"समूह"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"१ यन्त्र चयन गरियो"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> वटा यन्त्र चयन गरिए"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (डिस्कनेक्ट गरिएको)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(डिस्कनेक्ट गरिएको छ)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"कनेक्ट गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नयाँ डिभाइस कनेक्ट गर्नुहोस्"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नम्बर"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 2dd2bb7fbd21..a28a10ca461d 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Groep"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Eén apparaat geselecteerd"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> apparaten geselecteerd"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (verbinding verbroken)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(verbinding verbroken)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Kan geen verbinding maken. Probeer het nog eens."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Nieuw apparaat koppelen"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build-nummer"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index ee96b319be71..fce44d7e1592 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"ଗୋଷ୍ଠୀ"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1ଟି ଡିଭାଇସ୍ ଚୟନ କରାଯାଇଛି"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g>ଟି ଡିଭାଇସ୍ ଚୟନ କରାଯାଇଛି"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ବିଚ୍ଛିନ୍ନ କରାଯାଇଛି)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ବିଚ୍ଛିନ୍ନ କରାଯାଇଛି)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ସଂଯୋଗ କରାଯାଇପାରିଲା ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ନୂଆ ଡିଭାଇସକୁ ପେୟାର୍ କରନ୍ତୁ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ବିଲ୍ଡ ନମ୍ୱର"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 80fae3d62206..26f4641049eb 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"ਗਰੁੱਪ"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 ਡੀਵਾਈਸ ਨੂੰ ਚੁਣਿਆ ਗਿਆ"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> ਡੀਵਾਈਸਾਂ ਨੂੰ ਚੁਣਿਆ ਗਿਆ"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ਡਿਸਕਨੈਕਟ ਹੋਇਆ)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ਡਿਸਕਨੈਕਟ ਹੈ)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ਨਵਾਂ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ਬਿਲਡ ਨੰਬਰ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 7f8f47b187fa..01debf4b52d4 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -1123,7 +1123,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupa"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Wybrano 1 urządzenie"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Wybrane urządzenia: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (rozłączono)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(odłączono)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nie udało się połączyć. Spróbuj ponownie."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sparuj nowe urządzenie"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numer kompilacji"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 41e5a77c5f85..37592ac524bb 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo selecionado"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> dispositivos selecionados"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (desconectado)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(sem conexão)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Não foi possível conectar. Tente novamente."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parear novo dispositivo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index fa10607a4a23..8c044dfe3da9 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo selecionado"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> dispositivos selecionados"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (desligado)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(desligado)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Não foi possível ligar. Tente novamente."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sincronize o novo dispositivo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da compilação"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 41e5a77c5f85..37592ac524bb 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo selecionado"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> dispositivos selecionados"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (desconectado)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(sem conexão)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Não foi possível conectar. Tente novamente."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parear novo dispositivo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 0a7ab9040d53..a78167f6da8c 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -1117,7 +1117,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grup"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"S-a selectat un dispozitiv"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"S-au selectat <xliff:g id="COUNT">%1$d</xliff:g> dispozitive"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (s-a deconectat)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(deconectat)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nu s-a putut conecta. Reîncercați."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Asociați un nou dispozitiv"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numărul versiunii"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 77677613d7f2..6abfc8707ac6 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -1123,7 +1123,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Группа"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Выбрано 1 устройство"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Выбрано устройств: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (отключено)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(нет подключения)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Не удалось подключиться. Повторите попытку."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Подключить новое устройство"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер сборки"</string>
@@ -1167,7 +1167,7 @@
<string name="person_available" msgid="2318599327472755472">"Онлайн"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Не удалось узнать уровень заряда батареи"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Нажмите, чтобы узнать больше."</string>
- <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Будильников нет"</string>
+ <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Нет будильников"</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Сканер отпечатков пальцев"</string>
<string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"Сканер отпечатков пальцев отключен"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"выполнить аутентификацию"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index a42544e908bb..21892c535810 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"සමූහය"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"උපාංග 1ක් තෝරන ලදී"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"උපාංග <xliff:g id="COUNT">%1$d</xliff:g>ක් තෝරන ලදී"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (විසන්ධි විය)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(විසන්ධි විය)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"සම්බන්ධ වීමට නොහැකි විය. නැවත උත්සාහ කරන්න."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"නව උපාංගය යුගල කරන්න"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"නිමැවුම් අංකය"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 8bb7b4a56637..2f2fb378f437 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -1123,7 +1123,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Skupina"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 vybrané zariadenie"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Počet vybraných zariadení: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (odpojené)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(odpojené)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nepodarilo sa pripojiť. Skúste to znova."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Spárovať nové zariadenie"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo zostavy"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 1e5c20ea9593..8427534c11bb 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -1123,7 +1123,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Skupina"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Izbrana je ena naprava"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Izbranih je toliko naprav: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (povezava prekinjena)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(povezava je prekinjena)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Povezave ni bilo mogoče vzpostaviti. Poskusite znova."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Seznanitev nove naprave"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Delovna različica"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index a8b0db18cb71..1acc6e83ebaa 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupi"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 pajisje e zgjedhur"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> pajisje të zgjedhura"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (e shkëputur)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(shkëputur)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Nuk mund të lidhej. Provo sërish."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Çifto pajisjen e re"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numri i ndërtimit"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index c2d665450caf..8c96a5154283 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -1117,7 +1117,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Група"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Изабран је 1 уређај"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Изабраних уређаја: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (веза је прекинута)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(веза је прекинута)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Повезивање није успело. Пробајте поново."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Упари нови уређај"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Број верзије"</string>
@@ -1161,7 +1161,7 @@
<string name="person_available" msgid="2318599327472755472">"Доступно"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Проблем са очитавањем мерача батерије"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Додирните за више информација"</string>
- <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Аларм није подешен"</string>
+ <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Није подешен"</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Сензор за отисак прста"</string>
<string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"Сензор за отисак прста је онемогућен"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"потврдите идентитет"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 7474e2f9310b..8e44ba154764 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -297,8 +297,8 @@
<string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"Arbetsläget har aktiverats."</string>
<string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"Databesparing har inaktiverats."</string>
<string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"Databesparing har aktiverats."</string>
- <string name="accessibility_quick_settings_sensor_privacy_changed_off" msgid="7608378211873807353">"Sensorsekretess har inaktiverats."</string>
- <string name="accessibility_quick_settings_sensor_privacy_changed_on" msgid="4267393685085328801">"Sensorsekretess har aktiverats."</string>
+ <string name="accessibility_quick_settings_sensor_privacy_changed_off" msgid="7608378211873807353">"Sensorintegritet har inaktiverats."</string>
+ <string name="accessibility_quick_settings_sensor_privacy_changed_on" msgid="4267393685085328801">"Sensorintegritet har aktiverats."</string>
<string name="accessibility_brightness" msgid="5391187016177823721">"Skärmens ljusstyrka"</string>
<string name="accessibility_ambient_display_charging" msgid="7725523068728128968">"Laddas"</string>
<string name="data_usage_disabled_dialog_3g_title" msgid="5716594205739750015">"2G- och 3G-data har pausats"</string>
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupp"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 enhet har valts"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> enheter har valts"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (frånkopplad)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(frånkopplad)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Det gick inte att ansluta. Försök igen."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parkoppla en ny enhet"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versionsnummer"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 85fc39551127..f4aefb760f60 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Kikundi"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Umechagua kifaa 1"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Umechagua vifaa <xliff:g id="COUNT">%1$d</xliff:g>"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (hakijaunganishwa)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(imetenganishwa)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Imeshindwa kuunganisha. Jaribu tena."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Oanisha kifaa kipya"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nambari ya muundo"</string>
diff --git a/packages/SystemUI/res/values-sw360dp/dimens.xml b/packages/SystemUI/res/values-sw360dp/dimens.xml
index fc510bf03efd..65ca70bac0dc 100644
--- a/packages/SystemUI/res/values-sw360dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw360dp/dimens.xml
@@ -19,9 +19,6 @@
<!-- The width of the view containing navigation buttons -->
<dimen name="navigation_key_width">80dip</dimen>
- <!-- The width of the view containing the menu/ime navigation bar icons -->
- <dimen name="navigation_extra_key_width">40dip</dimen>
-
<!-- The padding on the side of the navigation bar. Must be greater than or equal to
navigation_extra_key_width -->
<dimen name="navigation_side_padding">40dip</dimen>
diff --git a/packages/SystemUI/res/values-sw392dp/dimens.xml b/packages/SystemUI/res/values-sw392dp/dimens.xml
index 4c9d02e30bfa..78279ca4f520 100644
--- a/packages/SystemUI/res/values-sw392dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw392dp/dimens.xml
@@ -20,16 +20,8 @@
<dimen name="global_actions_grid_horizontal_padding">3dp</dimen>
<dimen name="global_actions_grid_item_side_margin">10dp</dimen>
- <dimen name="global_actions_grid_item_vertical_margin">6dp</dimen>
- <dimen name="global_actions_grid_item_width">72dp</dimen>
<dimen name="global_actions_grid_item_height">72dp</dimen>
- <dimen name="global_actions_grid_item_icon_width">22dp</dimen>
- <dimen name="global_actions_grid_item_icon_height">22dp</dimen>
- <dimen name="global_actions_grid_item_icon_top_margin">14dp</dimen>
- <dimen name="global_actions_grid_item_icon_side_margin">22dp</dimen>
- <dimen name="global_actions_grid_item_icon_bottom_margin">4dp</dimen>
-
<!-- Home Controls -->
<dimen name="global_actions_side_margin">16dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw410dp/config.xml b/packages/SystemUI/res/values-sw410dp/config.xml
deleted file mode 100644
index 8ace7bf13573..000000000000
--- a/packages/SystemUI/res/values-sw410dp/config.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2016, 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources>
- <bool name="quick_settings_show_full_alarm">true</bool>
-</resources>
diff --git a/packages/SystemUI/res/values-sw410dp/dimens.xml b/packages/SystemUI/res/values-sw410dp/dimens.xml
index 6780dca130b8..d33ee9970f80 100644
--- a/packages/SystemUI/res/values-sw410dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw410dp/dimens.xml
@@ -27,14 +27,6 @@
<dimen name="global_actions_grid_horizontal_padding">4dp</dimen>
<dimen name="global_actions_grid_item_side_margin">12dp</dimen>
- <dimen name="global_actions_grid_item_vertical_margin">8dp</dimen>
- <dimen name="global_actions_grid_item_width">72dp</dimen>
<dimen name="global_actions_grid_item_height">72dp</dimen>
- <dimen name="global_actions_grid_item_icon_width">24dp</dimen>
- <dimen name="global_actions_grid_item_icon_height">24dp</dimen>
- <dimen name="global_actions_grid_item_icon_top_margin">18dp</dimen>
- <dimen name="global_actions_grid_item_icon_side_margin">24dp</dimen>
- <dimen name="global_actions_grid_item_icon_bottom_margin">4dp</dimen>
-
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml
index ab159e1c4814..362e18d785ac 100644
--- a/packages/SystemUI/res/values-sw600dp-land/config.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/config.xml
@@ -32,4 +32,5 @@
<!-- Notifications are sized to match the width of two (of 4) qs tiles in landscape. -->
<bool name="config_skinnyNotifsInLandscape">false</bool>
+
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
new file mode 100644
index 000000000000..3cfe05638032
--- /dev/null
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+-->
+<resources>
+
+ <!-- keyguard-->
+ <dimen name="keyguard_indication_margin_bottom">25dp</dimen>
+ <dimen name="ambient_indication_margin_bottom">115dp</dimen>
+ <dimen name="lock_icon_margin_bottom">60dp</dimen>
+
+ <!-- margin from keyguard status bar to clock. For split shade it should be
+ keyguard_split_shade_top_margin - status_bar_header_height_keyguard = 8dp -->
+ <dimen name="keyguard_clock_top_margin">8dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 45b5afa467ac..f5dc7e3e16da 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -23,18 +23,12 @@
<!-- The maximum number of rows in the QuickSettings -->
<integer name="quick_settings_max_rows">4</integer>
- <!-- The number of columns that the top level tiles span in the QuickSettings -->
- <integer name="quick_settings_user_time_settings_tile_span">1</integer>
-
<!-- Nav bar button default ordering/layout -->
<string name="config_navBarLayout" translatable="false">left;back,home,recent;right</string>
<!-- orientation of the dead zone when touches have recently occurred elsewhere on screen -->
<integer name="navigation_bar_deadzone_orientation">0</integer>
- <!-- Whether wallet view is shown in landscape / seascape orientations -->
- <bool name="global_actions_show_landscape_wallet_view">true</bool>
-
<!-- Max number of columns for quick controls area -->
<integer name="controls_max_columns">4</integer>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 85f8f0957a08..7d033018c27f 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -16,26 +16,6 @@
*/
-->
<resources>
-
- <!-- Diameter of outer shape drawable shown in navbar search-->
- <dimen name="navbar_search_outerring_diameter">430dip</dimen>
-
- <!-- Diameter of outer shape drawable shown in navbar search. Should be 1/2 of above value. -->
- <dimen name="navbar_search_outerring_radius">215dip</dimen>
-
- <!-- Height of search panel including navigation bar height -->
- <dimen name="navbar_search_panel_height">280dip</dimen>
-
- <!-- The width of the view containing the menu/ime navigation bar icons -->
- <dimen name="navigation_extra_key_width">48dip</dimen>
-
- <!-- Minimum fraction of the screen that should be taken up by the notification panel. -->
- <item type="dimen" name="notification_panel_min_height_frac">40%</item>
-
- <!-- How far to slide the panel out when you touch it -->
- <!-- On tablets this is just the close_handle_height -->
- <dimen name="peek_height">@dimen/close_handle_height</dimen>
-
<!-- Height of the status bar header bar when on Keyguard -->
<dimen name="status_bar_header_height_keyguard">60dp</dimen>
@@ -45,14 +25,8 @@
<dimen name="kg_framed_avatar_size">48dp</dimen>
<!-- The width of user avatar when on Keyguard -->
- <dimen name="multi_user_switch_width_keyguard">48dp</dimen>
-
- <!-- The width of user avatar when on Keyguard -->
<dimen name="multi_user_avatar_keyguard_size">30dp</dimen>
- <!-- end margin for multi user switch in collapsed quick settings -->
- <dimen name="multi_user_switch_keyguard_margin">6dp</dimen>
-
<!-- Margin on the left side of the carrier text on Keyguard -->
<dimen name="keyguard_carrier_text_margin">24dp</dimen>
@@ -60,13 +34,6 @@
<dimen name="keyguard_affordance_height">80dp</dimen>
<dimen name="keyguard_affordance_width">120dp</dimen>
- <!-- The width of the region on the left/right edge of the screen for performing the camera/
- phone hints. -->
- <dimen name="edge_tap_area_width">80dp</dimen>
-
- <!-- Margin on the right side of the system icon group on Keyguard. -->
- <dimen name="system_icons_keyguard_padding_end">2dp</dimen>
-
<!-- Screen pinning request width -->
<dimen name="screen_pinning_request_width">400dp</dimen>
<!-- Screen pinning request bottom button circle widths -->
@@ -78,9 +45,8 @@
(screen_pinning_request_width - 3 * screen_pinning_request_button_width) / 2 -->
<dimen name="screen_pinning_request_side_width">8dp</dimen>
- <dimen name="fab_margin">24dp</dimen>
-
<dimen name="navigation_key_width">128dp</dimen>
+
<dimen name="navigation_key_padding">25dp</dimen>
<!-- Keyboard shortcuts helper -->
@@ -89,8 +55,6 @@
<!-- Text size for user name in user switcher -->
<dimen name="kg_user_switcher_text_size">18sp</dimen>
- <!-- TODO(himanshujaju) - add comments -->
- <dimen name="global_actions_wallet_top_margin">5dp</dimen>
<dimen name="controls_header_bottom_margin">12dp</dimen>
<dimen name="controls_top_margin">24dp</dimen>
@@ -105,5 +69,5 @@
<dimen name="qs_detail_margin_top">0dp</dimen>
<!-- The width of large/content heavy dialogs (e.g. Internet, Media output, etc) -->
- <dimen name="large_dialog_width">624dp</dimen>
+ <dimen name="large_dialog_width">504dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/styles.xml b/packages/SystemUI/res/values-sw600dp/styles.xml
index ee2b82dca811..7a2602e29a62 100644
--- a/packages/SystemUI/res/values-sw600dp/styles.xml
+++ b/packages/SystemUI/res/values-sw600dp/styles.xml
@@ -15,9 +15,6 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer">
- <item name="android:layout_width">@dimen/notification_panel_width</item>
- </style>
<style name="UserDetailView">
<item name="numColumns">4</item>
diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml
deleted file mode 100644
index 436f8d0998f5..000000000000
--- a/packages/SystemUI/res/values-sw720dp/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources>
- <integer name="status_bar_config_maxNotificationIcons">5</integer>
-
-</resources>
-
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index 8cf4adb73a7c..1564ee8c5604 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -17,16 +17,7 @@
-->
<resources>
- <!-- ======================================== -->
- <!-- The following resources were recently moved from sw600dp; there may
- be situations where they don't sync up perfectly with PhoneStatusBar. -->
- <!-- ======================================== -->
-
<!-- gap on either side of status bar notification icons -->
<dimen name="status_bar_icon_padding">1dp</dimen>
- <!-- The minimum height of the notification panel window -->
- <dimen name="notification_panel_min_height">770dp</dimen>
- <!-- Bottom margin (from display edge) for status bar panels -->
- <dimen name="panel_float">56dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw900dp/dimens.xml b/packages/SystemUI/res/values-sw900dp/dimens.xml
index 2cff97692d9d..ed8f20a13646 100644
--- a/packages/SystemUI/res/values-sw900dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw900dp/dimens.xml
@@ -20,7 +20,6 @@
<dimen name="button_size">80dp</dimen>
<dimen name="navigation_side_padding">@dimen/button_size</dimen>
<dimen name="navigation_key_width">@dimen/button_size</dimen>
- <dimen name="navigation_extra_key_width">@dimen/button_size</dimen>
<!-- The maximum width of the navigation bar ripples. -->
<dimen name="key_button_ripple_max_width">76dp</dimen>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 413149ba5391..9b33030acd8f 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"குழு"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 சாதனம் தேர்ந்தெடுக்கப்பட்டுள்ளது"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> சாதனங்கள் தேர்ந்தெடுக்கப்பட்டுள்ளன"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (இணைப்பு துண்டிக்கப்பட்டது)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(துண்டிக்கப்பட்டது)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"இணைக்க முடியவில்லை. மீண்டும் முயலவும்."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"புதிய சாதனத்தை இணைத்தல்"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"பதிப்பு எண்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 41f45d7a17c8..ca3b09e53aae 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"గ్రూప్"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 పరికరం ఎంచుకోబడింది"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> పరికరాలు ఎంచుకోబడ్డాయి"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (డిస్‌కనెక్ట్ అయ్యింది)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(డిస్కనెక్ట్ అయ్యింది)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"కనెక్ట్ చేయడం సాధ్యపడలేదు. మళ్లీ ట్రై చేయండి."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"కొత్త పరికరాన్ని పెయిర్ చేయండి"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"బిల్డ్ నంబర్"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 75314ee0a525..340f3103225b 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"กลุ่ม"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"เลือกอุปกรณ์ไว้ 1 รายการ"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"เลือกอุปกรณ์ไว้ <xliff:g id="COUNT">%1$d</xliff:g> รายการ"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ยกเลิกการเชื่อมต่อแล้ว)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ยกเลิกการเชื่อมต่อแล้ว)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"เชื่อมต่อไม่ได้ ลองใหม่"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"จับคู่อุปกรณ์ใหม่"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"หมายเลขบิลด์"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index baefb76e6685..266f77463816 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 device ang napili"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> (na) device ang napili"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (nakadiskonekta)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(nadiskonekta)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Hindi makakonekta. Subukan ulit."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Magpares ng bagong device"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero ng build"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 905b34c610e0..5abcb4a2550e 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grup"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 cihaz seçildi"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> cihaz seçildi"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (bağlı değil)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(bağlantı kesildi)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Bağlanılamadı. Tekrar deneyin."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yeni cihaz eşle"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Derleme numarası"</string>
@@ -1155,7 +1155,7 @@
<string name="person_available" msgid="2318599327472755472">"Müsait"</string>
<string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Pil ölçeriniz okunurken sorun oluştu"</string>
<string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Daha fazla bilgi için dokunun"</string>
- <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Alarm ayarlanmadı"</string>
+ <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Alarm yok"</string>
<string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Parmak izi sensörü"</string>
<string name="accessibility_udfps_disabled_button" msgid="4284034245130239384">"Parmak izi sensörü devre dışı bırakıldı"</string>
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"kimlik doğrulaması yapın"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 7f6f91086b0a..fd5c3d449fde 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -1123,7 +1123,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Група"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Вибрано 1 пристрій"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Вибрано пристроїв: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (відключено)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(від’єднано)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Не вдалося підключитися. Повторіть спробу."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Підключити новий пристрій"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер складання"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 4dcfc09889b7..92aad208b4f6 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"گروپ"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 آلہ منتخب کیا گیا"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> آلات منتخب کیے گئے"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (غیر منسلک ہو گیا)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(غیر منسلک ہے)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"منسلک نہیں ہو سکا۔ پھر کوشش کریں۔"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"نئے آلہ کا جوڑا بنائیں"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"بلڈ نمبر"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 5d135423bbe2..a95639a3f423 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Guruh"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 ta qurilma tanlandi"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> ta qurilma tanlandi"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (uzilgan)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(uzildi)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ulanmadi. Qayta urining."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yangi qurilmani ulash"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nashr raqami"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 810f31dcf22a..9a63886fb711 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Nhóm"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Đã chọn 1 thiết bị"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"Đã chọn <xliff:g id="COUNT">%1$d</xliff:g> thiết bị"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (đã ngắt kết nối)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(đã ngắt kết nối)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Không thể kết nối. Hãy thử lại."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Ghép nối thiết bị mới"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Số bản dựng"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index b7a475d1de63..794b760b64b7 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"群组"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"已选择 1 个设备"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"已选择 <xliff:g id="COUNT">%1$d</xliff:g> 个设备"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>(已断开连接)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(已断开连接)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"无法连接。请重试。"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"与新设备配对"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本号"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index df207ad69ce1..d460fb883da1 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"群組"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"已選取 1 部裝置"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"已選取 <xliff:g id="COUNT">%1$d</xliff:g> 部裝置"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (已中斷連線)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(已中斷連線)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"無法連線,請再試一次。"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"配對新裝置"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本號碼"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 2fb31207deaf..bbcf0e4ed2b8 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"群組"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"已選取 1 部裝置"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"已選取 <xliff:g id="COUNT">%1$d</xliff:g> 部裝置"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (已中斷連線)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(連線中斷)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"無法連線,請再試一次。"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"配對新裝置"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本號碼"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 96dd7ede6f2e..6c43d3ad374e 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -1111,7 +1111,7 @@
<string name="media_output_dialog_group" msgid="5571251347877452212">"Iqembu"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"idivayisi ekhethiwe e-1"</string>
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"amadivayisi akhethiwe angu-<xliff:g id="COUNT">%1$d</xliff:g>"</string>
- <string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (inqamukile)"</string>
+ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(inqamukile)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ayikwazanga ukuxhumeka. Zama futhi."</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Bhangqa idivayisi entsha"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Yakha inombolo"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 03c6fddb145c..141b97977dab 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -18,22 +18,13 @@
-->
<resources xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<drawable name="notification_number_text_color">#ffffffff</drawable>
- <drawable name="ticker_background_color">#ff1d1d1d</drawable>
<drawable name="system_bar_background">@color/system_bar_background_opaque</drawable>
<color name="system_bar_background_opaque">#ff000000</color>
<color name="system_bar_background_transparent">#00000000</color>
- <color name="notification_panel_solid_background">#ff000000</color>
- <drawable name="status_bar_notification_row_background_color">#ff090909</drawable>
- <color name="notification_list_shadow_top">#80000000</color>
- <drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable>
- <color name="qs_batterymeter_frame_color">#FF404040</color>
<color name="qs_tile_divider">#29ffffff</color><!-- 16% white -->
- <color name="qs_subhead">#99FFFFFF</color><!-- 60% white -->
- <color name="qs_detail_button">@*android:color/quaternary_device_default_settings</color>
<color name="qs_detail_button_white">#B3FFFFFF</color><!-- 70% white -->
<color name="qs_detail_transition">#66FFFFFF</color>
<color name="status_bar_clock_color">#FFFFFFFF</color>
- <color name="qs_user_detail_icon_muted">#FFFFFFFF</color> <!-- not so muted after all -->
<color name="qs_tile_disabled_color">#9E9E9E</color> <!-- 38% black -->
<!-- The color of the background in the separated list of the Global Actions menu -->
@@ -42,16 +33,6 @@
<!-- The color of the background in the grid of the Global Actions menu -->
<color name="global_actions_grid_background">#F1F3F4</color>
- <!-- The color of the text in the Global Actions menu -->
- <color name="global_actions_text">@color/GM2_grey_700</color>
-
- <!-- The color of the text in the Global Actions menu -->
- <color name="global_actions_alert_text">@color/GM2_red_700</color>
-
- <!-- The color of the background of the emergency button when home controls are visible -->
- <color name="global_actions_emergency_background">@color/GM2_red_400</color>
- <color name="global_actions_emergency_text">@color/GM2_grey_100</color>
-
<!-- Colors for Power Menu Lite -->
<color name="global_actions_lite_background">#191C18</color>
<color name="global_actions_lite_button_background">#303030</color>
@@ -61,17 +42,9 @@
<color name="global_actions_shutdown_ui_text">@color/control_primary_text</color>
- <!-- Tint color for the content on the notification overflow card. -->
- <color name="keyguard_overflow_content_color">#ff686868</color>
-
- <color name="keyguard_affordance">#ffffffff</color>
-
<!-- Shadows under the clock, date and other keyguard text fields -->
<color name="keyguard_shadow_color">#B2000000</color>
- <!-- Color for the images in keyguard number pad buttons -->
- <color name="keyguard_keypad_image_color">?android:attr/textColorPrimaryInverse</color>
-
<!-- Color for rounded background for activated user in keyguard user switcher -->
<color name="kg_user_switcher_activated_background_color">#26000000</color>
<!-- Icon color for user avatars in keyguard user switcher -->
@@ -92,9 +65,6 @@
<!-- The color of the legacy notification background -->
<color name="notification_legacy_background_color">#ff1a1a1a</color>
- <!-- The color of the material notification background when dark -->
- <color name="notification_material_background_dark_color">#ff333333</color>
-
<!-- The color of the dividing line between grouped notifications. -->
<color name="notification_divider_color">@*android:color/background_device_default_light</color>
@@ -107,21 +77,14 @@
<!-- The color of the gear shown behind a notification -->
<color name="notification_gear_color">@color/GM2_grey_700</color>
- <!-- The color of the text inside a notification -->
- <color name="notification_primary_text_color">@*android:color/notification_primary_text_color_light</color>
-
-
<color name="notification_guts_link_icon_tint">@color/GM2_grey_700</color>
<color name="notification_guts_sub_text_color">@color/GM2_grey_700</color>
<color name="notification_guts_header_text_color">@color/GM2_grey_900</color>
- <color name="notification_silence_color">#FF32c1de</color>
- <color name="notification_alert_color">#FFF87B2B</color>
<color name="notification_guts_priority_button_content_color">@color/GM2_grey_700</color>
<color name="notification_guts_priority_button_bg_fill_color">@color/transparent</color>
<color name="notification_guts_priority_button_bg_fill_color_selected">#FFFFFF</color>
<color name="notification_guts_priority_button_bg_stroke_color">@color/GM2_grey_300</color>
- <color name="notification_section_header_label_color">@color/GM2_grey_900</color>
<color name="notification_section_clear_all_btn_color">@color/GM2_grey_700</color>
<color name="assist_orb_color">#ffffff</color>
@@ -139,8 +102,6 @@
<color name="screen_pinning_request_window_bg">#80000000</color>
- <color name="segmented_buttons_background">#14FFFFFF</color><!-- 8% white -->
-
<color name="dark_mode_icon_color_dual_tone_background">#3d000000</color>
<color name="dark_mode_icon_color_dual_tone_fill">#7a000000</color>
@@ -152,19 +113,7 @@
<!-- Chosen so fill over background matches single tone -->
<color name="dark_mode_qs_icon_color_dual_tone_fill">#99000000</color>
- <color name="docked_divider_handle">#ffffff</color>
- <drawable name="forced_resizable_background">#59000000</drawable>
- <color name="minimize_dock_shadow_start">#60000000</color>
- <color name="minimize_dock_shadow_end">#00000000</color>
-
- <color name="default_remote_input_background">@*android:color/notification_default_color</color>
<color name="notif_pill_text">@android:color/system_neutral1_900</color>
- <color name="remote_input_accent">?android:attr/colorAccent</color>
-
- <color name="quick_step_track_background_background_dark">#1F000000</color>
- <color name="quick_step_track_background_background_light">#33FFFFFF</color>
- <color name="quick_step_track_background_foreground_dark">#38000000</color>
- <color name="quick_step_track_background_foreground_light">#59FFFFFF</color>
<!-- Keyboard shortcuts colors -->
<color name="ksh_application_group_color">#fff44336</color>
@@ -192,47 +141,26 @@
<color name="udfps_enroll_progress">#ff669DF6</color> <!-- blue 400 -->
<color name="udfps_enroll_progress_help">#ffEE675C</color> <!-- red 400 -->
- <!-- Color for the Assistant invocation lights -->
- <color name="default_invocation_lights_color">#ffffffff</color> <!-- white -->
-
<!-- Global screenshot actions -->
<color name="global_screenshot_button_ripple">#1f000000</color>
<color name="global_screenshot_background_protection_start">#40000000</color> <!-- 25% black -->
<!-- GM2 colors -->
- <color name="GM2_grey_50">#F8F9FA</color>
<color name="GM2_grey_100">#F1F3F4</color>
<color name="GM2_grey_200">#E8EAED</color>
<color name="GM2_grey_300">#DADCE0</color>
- <color name="GM2_grey_400">#BDC1C6</color>
<color name="GM2_grey_500">#9AA0A6</color>
<color name="GM2_grey_600">#80868B</color>
- <color name="GM2_grey_650">#70757A</color>
<color name="GM2_grey_700">#5F6368</color>
<color name="GM2_grey_800">#3C4043</color>
<color name="GM2_grey_900">#202124</color>
- <color name="GM2_red_50">#FCE8E6</color>
- <color name="GM2_red_200">#F6AEA9</color>
<color name="GM2_red_300">#F28B82</color>
- <color name="GM2_red_400">#EE675C</color>
- <color name="GM2_red_500">#B71C1C</color>
<color name="GM2_red_700">#C5221F</color>
- <color name="GM2_blue_50">#E8F0FE</color>
- <color name="GM2_blue_200">#AECBFA</color>
<color name="GM2_blue_300">#8AB4F8</color>
- <color name="GM2_blue_500">#FF4285F4</color>
- <color name="GM2_blue_600">#1A73E8</color>
- <color name="GM2_blue_700">#1967D2</color>
- <color name="GM2_yellow_50">#FEF7E0</color>
<color name="GM2_yellow_200">#FDE293</color>
- <color name="GM2_yellow_500">#FFFBBC04</color>
-
- <color name="GM2_green_500">#FF34A853</color>
-
- <color name="GM2_orange_900">#B06000</color>
<!-- Window magnification colors -->
<color name="magnification_border_color">#FF9900</color>
@@ -244,7 +172,6 @@
<color name="volume_dialog_background_color_above_blur">@android:color/transparent</color>
<!-- media -->
- <color name="media_disabled">#80ffffff</color>
<color name="media_seamless_border">?android:attr/colorAccent</color>
<!-- controls -->
@@ -252,7 +179,6 @@
<color name="control_secondary_text">#99FFFFFF</color>
<color name="control_default_foreground">@color/GM2_grey_500</color>
<color name="control_default_background">@color/GM2_grey_900</color>
- <color name="control_list_popup_background">@*android:color/background_floating_material_dark</color>
<color name="control_spinner_dropdown">@*android:color/foreground_material_dark</color>
<color name="control_more_vert">@*android:color/foreground_material_dark</color>
<color name="control_enabled_light_background">#413C2D</color>
@@ -285,8 +211,6 @@
<!-- Internet Dialog -->
<!-- Material next state on color-->
<color name="settingslib_state_on_color">@color/settingslib_state_on</color>
- <!-- Material next state off color-->
- <color name="settingslib_state_off_color">@color/settingslib_state_off</color>
<!-- Material next track on color-->
<color name="settingslib_track_on_color">@color/settingslib_track_on</color>
<!-- Material next track off color-->
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index d0de876a6b27..e00b9410a8a7 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -20,14 +20,6 @@
<!-- These resources are around just to allow their values to be customized
for different hardware and product builds. -->
<resources>
- <!-- Whether to clip notification contents with a rounded rectangle. Might be expensive on
- certain GPU's and thus can be turned off with only minimal visual impact. -->
- <bool name="config_notifications_round_rect_clipping">true</bool>
-
- <!-- Component to be used as the status bar service. Must implement the IStatusBar
- interface. This name is in the ComponentName flattened format (package/class) -->
- <string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.StatusBar</string>
-
<!-- Component to be used as the recents implementation. Must implement the
RecentsImplementation interface. This name is in the ComponentName flattened format
(package/class) -->
@@ -45,31 +37,12 @@
<item>400</item>
</integer-array>
- <!-- How many icons may be shown at once in the system bar. Includes any
- slots that may be reused for things like IME control. -->
- <integer name="config_maxNotificationIcons">5</integer>
-
- <!-- Show phone (voice) signal strength instead of data in mobile RSSI. -->
- <bool name="config_showPhoneRSSIForData">false</bool>
-
- <!-- Show rotation lock toggle in System UI-->
- <bool name="config_showRotationLock">true</bool>
-
- <!-- Vibration duration for GlowPadView used in SearchPanelView -->
- <integer translatable="false" name="config_vibration_duration">0</integer>
-
- <!-- Vibration duration for GlowPadView used in SearchPanelView -->
- <integer translatable="false" name="config_search_panel_view_vibration_duration">20</integer>
-
<!-- Show mic or phone affordance on Keyguard -->
<bool name="config_keyguardShowLeftAffordance">false</bool>
<!-- Show camera affordance on Keyguard -->
<bool name="config_keyguardShowCameraAffordance">false</bool>
- <!-- The length of the vibration when the notification pops open. -->
- <integer name="one_finger_pop_duration_ms">10</integer>
-
<!-- decay duration (from size_max -> size), in ms -->
<integer name="navigation_bar_deadzone_hold">333</integer>
<integer name="navigation_bar_deadzone_decay">333</integer>
@@ -98,7 +71,6 @@
<integer name="quick_settings_max_rows">4</integer>
<!-- The number of columns that the top level tiles span in the QuickSettings -->
- <integer name="quick_settings_user_time_settings_tile_span">1</integer>
<!-- The default tiles to display in QuickSettings -->
<string name="quick_settings_tiles_default" translatable="false">
@@ -128,13 +100,6 @@
<item>accessibility_display_inversion_enabled:inversion</item>
</string-array>
- <!-- Whether or not the RSSI tile is capitalized or not. -->
- <bool name="quick_settings_rssi_tile_capitalization">true</bool>
-
- <!-- Timeouts for brightness dialog to disappear -->
- <integer name="quick_settings_brightness_dialog_short_timeout">2000</integer>
- <integer name="quick_settings_brightness_dialog_long_timeout">4000</integer>
-
<!-- Show indicator for Wifi on but not connected. -->
<bool name="config_showWifiIndicatorWhenEnabled">false</bool>
@@ -164,10 +129,6 @@
card. -->
<integer name="keyguard_max_notification_count">-1</integer>
- <!-- Defines the implementation of the velocity tracker to be used for the panel expansion. Can
- be 'platform' or 'noisy' (i.e. for noisy touch screens). -->
- <string name="velocity_tracker_impl" translatable="false">platform</string>
-
<!-- Doze: does this device support STATE_DOZE? -->
<bool name="doze_display_state_supported">false</bool>
@@ -206,9 +167,6 @@
low powered state yet. -->
<bool name="doze_long_press_uses_prox">true</bool>
- <!-- Doze: should notifications be used as a pulse signal? -->
- <bool name="doze_pulse_on_notifications">true</bool>
-
<!-- Doze: duration to avoid false pickup gestures triggered by notification vibrations -->
<integer name="doze_pickup_vibration_threshold">2000</integer>
@@ -311,18 +269,9 @@
<!-- Doze: whether the double tap sensor reports 2D touch coordinates -->
<bool name="doze_double_tap_reports_touch_coordinates">false</bool>
- <!-- Hotspot tile: number of days to show after feature is used. -->
- <integer name="days_to_show_hotspot_tile">30</integer>
-
- <!-- Color inversion tile: number of days to show after feature is used. -->
- <integer name="days_to_show_color_inversion_tile">7</integer>
-
<!-- Number of times to show the strong alarm warning text in the volume dialog -->
<integer name="zen_mode_alarm_warning_threshold">5</integer>
- <!-- Maximum number of total conditions to display in the zen mode selection panel -->
- <integer name="zen_mode_max_conditions">5</integer>
-
<!-- Enable the default volume dialog -->
<bool name="enable_volume_ui">true</bool>
@@ -332,12 +281,6 @@
<!-- Whether to show operator name in the status bar -->
<bool name="config_showOperatorNameInStatusBar">false</bool>
- <!-- Duration of the full carrier network change icon animation. -->
- <integer name="carrier_network_change_anim_time">3000</integer>
-
- <!-- Duration of the expansion animation in the volume dialog -->
- <item name="volume_expand_animation_duration" type="integer">300</item>
-
<!-- Whether to show the full screen user switcher. -->
<bool name="config_enableFullscreenUserSwitcher">false</bool>
@@ -393,19 +336,12 @@
<string name="config_navBarLayoutQuickstep" translatable="false">back[1.7WC];home;contextual[1.7WC]</string>
<string name="config_navBarLayoutHandle" translatable="false">back[70AC];home_handle;ime_switcher[70AC]</string>
- <bool name="quick_settings_show_full_alarm">false</bool>
-
<!-- Whether to show a warning notification when device's skin temperature is high. -->
<integer name="config_showTemperatureWarning">0</integer>
<!-- Whether to show a alarm dialog when device's usb port is overheating. -->
<integer name="config_showUsbPortAlarm">0</integer>
- <!-- Accessibility actions -->
- <item type="id" name="action_split_task_to_left" />
- <item type="id" name="action_split_task_to_right" />
- <item type="id" name="action_split_task_to_top" />
-
<item type="id" name="action_toggle_overview"/>
<!-- Whether or not to show notifications to the user. If disabled, SystemUI will still be
@@ -484,11 +420,6 @@
<!-- Notifications are sized to match the width of two (of 4) qs tiles in landscape. -->
<bool name="config_skinnyNotifsInLandscape">true</bool>
- <!-- If true, enable the advance anti-falsing classifier on the lockscreen. On some devices it
- does not work well, particularly with noisy touchscreens. Note that disabling it may
- increase the rate of unintentional unlocks. -->
- <bool name="config_lockscreenAntiFalsingClassifierEnabled">true</bool>
-
<!-- Snooze: default notificaiton snooze time. -->
<integer name="config_notification_snooze_time_default">60</integer>
@@ -545,8 +476,6 @@
<item>com.android.systemui</item>
</string-array>
- <integer name="ongoing_appops_dialog_max_apps">5</integer>
-
<!-- Launcher package name for overlaying icons. -->
<string name="launcher_overlayable_package" translatable="false">com.android.launcher3</string>
@@ -566,9 +495,6 @@
<!-- Preferred max refresh rate at keyguard, if supported by the display. -->
<integer name="config_keyguardMaxRefreshRate">-1</integer>
- <!-- Whether or not to add a "people" notifications section -->
- <bool name="config_usePeopleFiltering">false</bool>
-
<!-- Defines system icons to be excluded from the display. That is to say, the icons in the
status bar that are part of this list are never displayed. Each item in the list must be a
string defined in core/res/res/config.xml to properly exclude the icon.
@@ -615,8 +541,6 @@
<!-- Max number of columns for quick controls area -->
<integer name="controls_max_columns">2</integer>
- <!-- Max number of columns for power menu -->
- <integer name="power_menu_max_columns">3</integer>
<!-- Max number of columns for power menu lite -->
<integer name="power_menu_lite_max_columns">2</integer>
<!-- Max number of rows for power menu lite -->
@@ -645,18 +569,12 @@
<!-- content URL in a notification when ACTION_BATTERY_CHANGED.EXTRA_PRESENT field is false -->
<string translatable="false" name="config_batteryStateUnknownUrl"></string>
- <!-- Whether wallet view is shown in landscape / seascape orientations -->
- <bool name="global_actions_show_landscape_wallet_view">false</bool>
-
<!-- Package name of the preferred system app to perform eSOS action -->
<string name="config_preferredEmergencySosPackage" translatable="false"></string>
<!-- Whether to use the split 2-column notification shade -->
<bool name="config_use_split_notification_shade">false</bool>
- <!-- Determines whether the shell features all run on another thread. -->
- <bool name="config_enableShellMainThread">false</bool>
-
<!-- Default udfps icon. Same path as ic_fingerprint.xml -->
<string name="config_udfpsIcon" translatable="false">
M25.5,16.3283C28.47,14.8433 31.9167,14 35.5834,14C39.2501,14 42.6968,14.8433 45.6668,16.3283
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 7293f3148ae4..38be0932070f 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -21,15 +21,8 @@
<dimen name="remote_input_view_text_stroke">2dp</dimen>
- <!-- Amount to offset bottom of notification peek window from top of status bar. -->
- <dimen name="peek_window_y_offset">-12dp</dimen>
-
<!-- thickness (height) of the navigation bar on phones that require it -->
<dimen name="navigation_bar_size">@*android:dimen/navigation_bar_height</dimen>
- <!-- Minimum swipe distance to catch the swipe gestures to invoke assist or switch tasks. -->
- <dimen name="navigation_bar_min_swipe_distance">48dp</dimen>
- <dimen name="navigation_bar_default_edge_height">500dp</dimen>
-
<!-- thickness (height) of the dead zone at the top of the navigation bar,
reducing false presses on navbar buttons; approx 2mm -->
<dimen name="navigation_bar_deadzone_size">12dp</dimen>
@@ -39,7 +32,6 @@
<!-- dimensions for the navigation bar handle -->
<dimen name="navigation_handle_radius">1dp</dimen>
<dimen name="navigation_handle_bottom">6dp</dimen>
- <dimen name="navigation_handle_horizontal_margin">30dp</dimen>
<dimen name="navigation_handle_sample_horizontal_margin">10dp</dimen>
<dimen name="navigation_home_handle_width">72dp</dimen>
@@ -56,11 +48,6 @@
<!-- The amount by which the arrow is shifted to avoid the finger-->
<dimen name="navigation_edge_finger_offset">48dp</dimen>
- <dimen name="floating_rotation_button_diameter">40dp</dimen>
- <dimen name="floating_rotation_button_min_margin">20dp</dimen>
- <dimen name="floating_rotation_button_taskbar_left_margin">20dp</dimen>
- <dimen name="floating_rotation_button_taskbar_bottom_margin">10dp</dimen>
-
<!-- Height of notification icons in the status bar -->
<dimen name="status_bar_icon_size">@*android:dimen/status_bar_icon_size</dimen>
@@ -108,9 +95,6 @@
<dimen name="group_overflow_number_padding">@*android:dimen/notification_content_margin_end
</dimen>
- <!-- max height of a notification such that the content can still fade out when closing -->
- <dimen name="max_notification_fadeout_height">100dp</dimen>
-
<!-- End margin for the RSSI status icon of a device connected via bluetooth. -->
<dimen name="status_bar_connected_device_signal_margin_end">16dp</dimen>
@@ -187,10 +171,6 @@
<!-- the padding of the shelf icon container -->
<dimen name="shelf_icon_container_padding">13dp</dimen>
- <!-- The padding of a notification icon on top to the start of the notification. Used for custom
- views where the distance can't be measured -->
- <dimen name="notification_icon_appear_padding">15dp</dimen>
-
<!-- Vertical translation of the shelf during animation that happens after the
notification panel collapses -->
<dimen name="shelf_appear_translation">42dp</dimen>
@@ -227,48 +207,14 @@
<!-- Extra horizontal space for properly aligning guts buttons with the notification content -->
<dimen name="notification_guts_button_side_margin">8dp</dimen>
-
- <!-- The vertical padding a notification guts button has to fulfill the 48dp touch target -->
- <dimen name="notification_guts_button_vertical_padding">14dp</dimen>
-
- <!-- The horizontal padding for notification guts buttons-->
- <dimen name="notification_guts_button_horizontal_padding">8dp</dimen>
-
- <!-- The horizontal space around the buttons in the inline settings -->
- <dimen name="notification_guts_button_horizontal_spacing">8dp</dimen>
-
- <dimen name="notification_guts_conversation_header_height">84dp</dimen>
<dimen name="notification_guts_conversation_icon_size">56dp</dimen>
- <dimen name="notification_guts_conversation_action_height">56dp</dimen>
- <dimen name="notification_guts_conversation_action_text_padding_start">32dp</dimen>
- <dimen name="conversation_onboarding_bullet_gap_width">6dp</dimen>
-
<dimen name="notification_guts_header_top_padding">12dp</dimen>
-
- <!-- The height of the header in inline settings -->
- <dimen name="notification_guts_header_height">24dp</dimen>
-
- <!-- The text size of the header in inline settings -->
- <dimen name="notification_guts_header_text_size">16sp</dimen>
-
- <!-- The horizontal space between items in the alert selections in the inline settings -->
- <dimen name="notification_guts_option_horizontal_padding">15dp</dimen>
-
<!-- The vertical space between items in the alert selections in the inline settings -->
<dimen name="notification_guts_option_vertical_padding">16dp</dimen>
- <!-- The vertical space between the alert selections in the inline settings -->
- <dimen name="notification_guts_option_vertical_margin">6dp</dimen>
-
<dimen name="notification_importance_toggle_size">48dp</dimen>
- <dimen name="notification_importance_toggle_marginTop">28dp</dimen>
- <dimen name="notification_importance_toggle_marginBottom">28dp</dimen>
- <dimen name="notification_importance_text_marginTop">20dp</dimen>
<dimen name="notification_importance_button_separation">8dp</dimen>
- <dimen name="notification_importance_button_width">178dp</dimen>
- <dimen name="notification_importance_button_horiz_padding">28dp</dimen>
<dimen name="notification_importance_drawable_padding">8dp</dimen>
- <dimen name="notification_importance_description_padding">20dp</dimen>
<dimen name="notification_importance_header_text">12sp</dimen>
<dimen name="notification_importance_description_text">14sp</dimen>
<dimen name="notification_importance_channel_text">16sp</dimen>
@@ -281,12 +227,6 @@
<!-- The minimum height for the snackbar shown after the snooze option has been chosen. -->
<dimen name="snooze_snackbar_min_height">56dp</dimen>
- <!-- The text size of options in the snooze menu. -->
- <dimen name="snooze_option_text_size">14sp</dimen>
-
- <!-- The padding around options int the snooze menu. -->
- <dimen name="snooze_option_padding">8dp</dimen>
-
<!-- size at which Notification icons will be drawn in the status bar -->
<dimen name="status_bar_icon_drawing_size">15dp</dimen>
@@ -295,9 +235,6 @@
@*android:dimen/notification_header_icon_size_ambient
</dimen>
- <!-- size of notification icons when the notifications are hidden -->
- <dimen name="hidden_shelf_icon_size">16dp</dimen>
-
<!-- opacity at which Notification icons will be drawn in the status bar -->
<item type="dimen" name="status_bar_icon_drawing_alpha">90%</item>
@@ -363,40 +300,19 @@
<dimen name="navigation_key_padding">0dp</dimen>
- <!-- The width of the view containing the menu/ime navigation bar icons -->
- <dimen name="navigation_extra_key_width">36dp</dimen>
-
<!-- The padding on the side of the navigation bar. Must be greater than or equal to
navigation_extra_key_width -->
<dimen name="navigation_side_padding">36dp</dimen>
- <!-- Default distance beyond which snaps to the matching target -->
- <dimen name="navbar_search_snap_margin">40dip</dimen>
-
- <!-- Diameter of outer shape drawable shown in navbar search-->
- <dimen name="navbar_search_outerring_diameter">340dp</dimen>
-
- <!-- Diameter of outer shape drawable shown in navbar search. Should be 1/2 of above value -->
- <dimen name="navbar_search_outerring_radius">170dp</dimen>
-
- <!-- Height of search panel including navigation bar height -->
- <dimen name="navbar_search_panel_height">230dip</dimen>
-
<!-- Move the back button drawable for 3 button layout upwards in ime mode and in portrait -->
<dimen name="navbar_back_button_ime_offset">2dp</dimen>
- <!-- Height of the draggable handle at the bottom of the phone notification panel -->
- <dimen name="close_handle_height">36dp</dimen>
-
<!-- Amount of close_handle that will NOT overlap the notification list -->
<dimen name="close_handle_underlap">32dp</dimen>
<!-- Height of the status bar header bar in the car setting. -->
<dimen name="car_status_bar_header_height">128dp</dimen>
- <!-- The bottom padding of the status bar header. -->
- <dimen name="status_bar_header_padding_bottom">48dp</dimen>
-
<!-- The height of the container that holds the battery and time in the quick settings header.
Preferred over using "@*android:dimen/quick_qs_offset_height" as system icons are not always
present in quick settings (e.g. in split shade) and it's useful to be able to override this
@@ -404,9 +320,6 @@
-->
<dimen name="qs_header_system_icons_area_height">@*android:dimen/quick_qs_offset_height</dimen>
- <!-- How far the quick-quick settings panel extends below the status bar -->
- <dimen name="qs_quick_header_panel_height">128dp</dimen>
-
<!-- The height of the container that holds the system icons in the quick settings header in the
car setting. -->
<dimen name="car_qs_header_system_icons_area_height">54dp</dimen>
@@ -431,26 +344,17 @@
<!-- 3/4 of icon width 20dpx20dp -->
<dimen name="qs_footer_tuner_icon_translation">15dp</dimen>
- <!-- The padding between the notifications and the quick settings container -->
- <dimen name="qs_notification_padding">@dimen/notification_side_paddings</dimen>
-
<!-- In split shade mode notifications should be aligned to QS header so the value should be
adjusted to qs header height and height of centered content inside of it:
(quick_qs_offset_height (60dp) - ongoing_appops_chip_height (24dp) ) / 2 -->
<dimen name="notifications_top_padding_split_shade">18dp</dimen>
- <!-- Height of the status bar header bar when expanded -->
- <dimen name="status_bar_header_height_expanded">124dp</dimen>
-
<!-- Height of the status bar header bar when on Keyguard -->
<dimen name="status_bar_header_height_keyguard">40dp</dimen>
<!-- Margin start of the system icons super container -->
<dimen name="system_icons_super_container_margin_start">16dp</dimen>
- <!-- Margin end of the system icons super container when the avatar is missing. -->
- <dimen name="system_icons_super_container_avatarless_margin_end">6dp</dimen>
-
<!-- Width for the notification panel and related windows -->
<dimen name="match_parent">-1px</dimen>
@@ -487,8 +391,6 @@
<dimen name="volume_dialog_slider_corner_radius">21dp</dimen>
- <dimen name="volume_dialog_slider_height">116dp</dimen>
-
<!-- (volume_dialog_panel_width - rounded_slider_icon_size) / 2 -->
<dimen name="volume_slider_icon_inset">11dp</dimen>
@@ -506,10 +408,6 @@
<dimen name="volume_dialog_spacer">4dp</dimen>
- <dimen name="volume_dialog_slider_margin_top">14dp</dimen>
-
- <dimen name="volume_dialog_slider_margin_bottom">-2dp</dimen>
-
<dimen name="volume_dialog_row_margin_bottom">8dp</dimen>
<dimen name="volume_dialog_elevation">9dp</dimen>
@@ -518,8 +416,6 @@
<dimen name="volume_tool_tip_right_margin">76dp</dimen>
- <dimen name="volume_tool_tip_bottom_margin">32dp</dimen>
-
<dimen name="volume_tool_tip_arrow_corner_radius">2dp</dimen>
<!-- Size of each item in the ringer selector drawer. -->
@@ -529,35 +425,28 @@
<!-- Size of the icon inside each item in the ringer selector drawer. -->
<dimen name="volume_ringer_drawer_icon_size">24dp</dimen>
+ <dimen name="rounded_corner_content_padding">0dp</dimen>
+
+ <!-- Floating rotation button -->
+ <dimen name="floating_rotation_button_diameter">40dp</dimen>
+ <dimen name="floating_rotation_button_min_margin">20dp</dimen>
+ <dimen name="floating_rotation_button_taskbar_left_margin">20dp</dimen>
+ <dimen name="floating_rotation_button_taskbar_bottom_margin">10dp</dimen>
+
<!-- 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>
-
- <!-- The distance you can pull a notification before it pops open -->
- <dimen name="one_finger_pop_limit">0dp</dimen>
-
- <!-- Minimum fraction of the screen that should be taken up by the notification panel.
- Not used at this screen size. -->
- <item type="dimen" name="notification_panel_min_height_frac">0%</item>
-
- <dimen name="blinds_pop_threshold">0dp</dimen>
-
<!-- The size of the gesture span needed to activate the "pull" notification expansion -->
<dimen name="pull_span_min">25dp</dimen>
<dimen name="qs_corner_radius">28dp</dimen>
<dimen name="qs_tile_height">84dp</dimen>
- <!--notification_side_paddings + notification_content_margin_start - (qs_quick_tile_size - qs_tile_background_size) / 2 -->
- <dimen name="qs_tile_layout_margin_side">18dp</dimen>
<dimen name="qs_tile_margin_horizontal">8dp</dimen>
<dimen name="qs_tile_margin_vertical">@dimen/qs_tile_margin_horizontal</dimen>
<dimen name="qs_tile_margin_top_bottom">4dp</dimen>
- <dimen name="qs_tile_margin_top_bottom_negative">-4dp</dimen>
<dimen name="qs_brightness_margin_top">8dp</dimen>
<dimen name="qs_brightness_margin_bottom">24dp</dimen>
<dimen name="qqs_layout_margin_top">16dp</dimen>
@@ -567,8 +456,6 @@
-->
<dimen name="qs_customize_header_min_height">68dp</dimen>
<dimen name="qs_customize_internal_side_paddings">8dp</dimen>
- <dimen name="qs_tile_icon_background_stroke_width">-1dp</dimen>
- <dimen name="qs_tile_background_size">56dp</dimen>
<dimen name="qs_icon_size">20dp</dimen>
<dimen name="qs_side_view_size">28dp</dimen>
<dimen name="qs_label_container_margin">10dp</dimen>
@@ -576,8 +463,6 @@
<dimen name="qs_tile_padding">12dp</dimen>
<dimen name="qs_tile_start_padding">16dp</dimen>
<dimen name="qs_drawable_end_margin">4dp</dimen>
- <dimen name="qs_header_gear_translation">16dp</dimen>
- <dimen name="qs_header_tile_margin_bottom">18dp</dimen>
<dimen name="qs_page_indicator_width">16dp</dimen>
<dimen name="qs_page_indicator_height">8dp</dimen>
<!-- The size of a single dot in relation to the whole animation.
@@ -585,18 +470,10 @@
-->
<dimen name="qs_page_indicator_dot_width">6.4dp</dimen>
<dimen name="qs_tile_text_size">14sp</dimen>
- <dimen name="qs_tile_divider_height">1dp</dimen>
<dimen name="qs_panel_padding">16dp</dimen>
- <dimen name="qs_dual_tile_height">112dp</dimen>
- <dimen name="qs_dual_tile_padding_vertical">8dp</dimen>
<dimen name="qs_dual_tile_padding_horizontal">6dp</dimen>
- <dimen name="qs_tile_padding_top">14dp</dimen>
- <dimen name="qs_tile_padding_top_large_text">4dp</dimen>
- <dimen name="qs_tile_padding_bottom">16dp</dimen>
- <dimen name="qs_tile_spacing">4dp</dimen>
<dimen name="qs_panel_padding_bottom">0dp</dimen>
<dimen name="qs_panel_padding_top">48dp</dimen>
- <dimen name="qs_detail_header_height">56dp</dimen>
<dimen name="qs_detail_header_padding">0dp</dimen>
<dimen name="qs_detail_image_width">56dp</dimen>
<dimen name="qs_detail_image_height">56dp</dimen>
@@ -608,27 +485,19 @@
<dimen name="qs_detail_item_secondary_text_size">14sp</dimen>
<dimen name="qs_detail_empty_text_size">14sp</dimen>
<dimen name="qs_detail_header_margin_top">28dp</dimen>
- <dimen name="qs_detail_back_margin_end">16dp</dimen>
<dimen name="qs_detail_header_text_padding">16dp</dimen>
<dimen name="qs_data_usage_text_size">14sp</dimen>
<dimen name="qs_data_usage_usage_text_size">36sp</dimen>
- <dimen name="qs_battery_padding">2dp</dimen>
<dimen name="qs_detail_padding_start">16dp</dimen>
<dimen name="qs_detail_items_padding_top">4dp</dimen>
<dimen name="qs_detail_item_icon_size">24dp</dimen>
<dimen name="qs_detail_item_icon_width">32dp</dimen>
<dimen name="qs_detail_item_icon_marginStart">0dp</dimen>
<dimen name="qs_detail_item_icon_marginEnd">20dp</dimen>
- <dimen name="qs_header_alarm_icon_size">@dimen/status_bar_icon_drawing_size</dimen>
<dimen name="qs_header_mobile_icon_size">@dimen/status_bar_icon_drawing_size</dimen>
- <dimen name="qs_header_alarm_text_margin_start">6dp</dimen>
- <dimen name="qs_header_separator_width">8dp</dimen>
<dimen name="qs_header_carrier_separator_width">6dp</dimen>
- <dimen name="qs_status_separator">32dp</dimen>
<dimen name="qs_carrier_margin_width">4dp</dimen>
<dimen name="qs_footer_icon_size">20dp</dimen>
- <dimen name="qs_header_top_padding">15dp</dimen>
- <dimen name="qs_header_bottom_padding">14dp</dimen>
<dimen name="qs_header_row_min_height">48dp</dimen>
<dimen name="qs_footer_padding">20dp</dimen>
@@ -638,8 +507,6 @@
<dimen name="qs_security_footer_background_inset">0dp</dimen>
<dimen name="qs_security_footer_corner_radius">28dp</dimen>
- <dimen name="qs_notif_collapsed_space">64dp</dimen>
-
<!-- Desired qs icon overlay size. -->
<dimen name="qs_detail_icon_overlay_size">24dp</dimen>
@@ -651,24 +518,11 @@
<!-- How far the expanded QS panel peeks from the header in collapsed state. -->
<dimen name="qs_peek_height">0dp</dimen>
- <!-- How large the icons in the quick settings footer dialog are -->
- <dimen name="qs_footer_dialog_icon_size">24sp</dimen>
- <!-- Left and right margin of the icons -->
- <dimen name="qs_footer_dialog_icon_margin">8sp</dimen>
<!-- Padding between subtitles and the following text in the QSFooter dialog -->
<dimen name="qs_footer_dialog_subtitle_padding">20dp</dimen>
<dimen name="qs_detail_margin_top">@*android:dimen/quick_qs_offset_height</dimen>
- <dimen name="seek_bar_height">3dp</dimen>
- <dimen name="seek_bar_corner_radius">3dp</dimen>
-
- <!-- Zen mode panel: condition item button padding -->
- <dimen name="zen_mode_condition_detail_button_padding">8dp</dimen>
-
- <!-- Zen mode panel: spacing between condition items -->
- <dimen name="zen_mode_condition_detail_item_spacing">12dp</dimen>
-
<!-- Zen mode panel: spacing between two-line condition upper and lower lines -->
<dimen name="zen_mode_condition_detail_item_interline_spacing">4dp</dimen>
@@ -678,12 +532,6 @@
<!-- used by DessertCase -->
<dimen name="dessert_case_cell_size">192dp</dimen>
- <!-- Default glow radius for GlowPadView -->
- <dimen name="glowpadview_glow_radius">75dip</dimen>
-
- <!-- Default distance from each snap target that GlowPadView considers a "hit" -->
- <dimen name="glowpadview_inner_radius">15dip</dimen>
-
<!-- Z distance between notifications if they are in the stack -->
<dimen name="z_distance_between_notifications">0.5dp</dimen>
@@ -711,9 +559,6 @@
@*android:dimen/notification_content_margin_top
</dimen>
- <!-- The height of a notification header -->
- <dimen name="notification_header_height">@*android:dimen/notification_header_height</dimen>
-
<!-- The height of the gap between adjacent notification sections. -->
<dimen name="notification_section_divider_height">@dimen/notification_side_paddings</dimen>
@@ -732,9 +577,6 @@
<!-- The minimum amount of top overscroll to go to the quick settings. -->
<dimen name="min_top_overscroll_to_qs">36dp</dimen>
- <!-- The height of the speed bump view. -->
- <dimen name="speed_bump_height">16dp</dimen>
-
<!-- Lockscreen unlocking falsing threshold. -->
<dimen name="unlock_falsing_threshold">80dp</dimen>
@@ -747,6 +589,9 @@
<!-- Minimum distance the user has to drag down to go to the full shade. -->
<dimen name="keyguard_drag_down_min_distance">100dp</dimen>
+ <!-- The margin from the top of the screen to notifications and keyguard status view in
+ split shade on keyguard-->
+ <dimen name="keyguard_split_shade_top_margin">68dp</dimen>
<!-- The margin between the status view and the notifications on Keyguard.-->
<dimen name="keyguard_status_view_bottom_margin">20dp</dimen>
<!-- Minimum margin between clock and status bar -->
@@ -763,7 +608,6 @@
<!-- Burmese line spacing multiplier between hours and minutes of the keyguard clock -->
<item name="keyguard_clock_line_spacing_scale_burmese" type="dimen" format="float">1</item>
- <item name="scrim_behind_alpha" format="float" type="dimen">0.62</item>
<dimen name="notification_scrim_corner_radius">32dp</dimen>
<!-- The minimum amount the user needs to swipe to go to the camera / phone. -->
@@ -781,61 +625,23 @@
<!-- Distance between notifications and header when they are considered to be colliding. -->
<dimen name="header_notifications_collide_distance">48dp</dimen>
- <!-- Distance the user needs to drag vertically such that a swipe is accepted to unlock the
- device. -->
- <dimen name="unlock_move_distance">75dp</dimen>
-
<!-- Move distance for the unlock hint animation on the lockscreen -->
<dimen name="hint_move_distance">75dp</dimen>
<!-- The overshoot amount when the panel flings open -->
<dimen name="panel_overshoot_amount">16dp</dimen>
- <!-- The width of the region on the left/right edge of the screen for performing the camera/
- phone hints. -->
- <dimen name="edge_tap_area_width">48dp</dimen>
-
<!-- The padding between notification children when collapsed -->
<dimen name="notification_children_padding">4dp</dimen>
<!-- The padding on top of the first notification to the children container -->
<dimen name="notification_children_container_top_padding">8dp</dimen>
- <!-- end margin for multi user switch in expanded quick settings -->
- <dimen name="multi_user_switch_expanded_margin">8dp</dimen>
-
- <!-- end margin for multi user switch in collapsed quick settings -->
- <dimen name="multi_user_switch_collapsed_margin">13dp</dimen>
-
- <!-- end margin for multi user switch in collapsed quick settings -->
- <dimen name="multi_user_switch_keyguard_margin">3dp</dimen>
-
<!-- end margin for system icons if multi user switch is hidden -->
<dimen name="system_icons_switcher_hidden_expanded_margin">16dp</dimen>
<dimen name="data_usage_graph_marker_width">4dp</dimen>
- <!-- The padding bottom of the clock group when QS is expanded. -->
- <dimen name="clock_expanded_bottom_margin">20dp</dimen>
-
- <!-- The padding bottom of the clock group when QS is collapsed. -->
- <dimen name="clock_collapsed_bottom_margin">10dp</dimen>
-
- <!-- The padding bottom of the clock group when QS is collapsed for large text -->
- <dimen name="clock_collapsed_bottom_margin_large_text">6dp</dimen>
-
- <!-- The width of the multi user switch on keyguard and collapsed QS header. -->
- <dimen name="multi_user_switch_width_collapsed">34dp</dimen>
-
- <!-- The width of the multi user switch in expanded QS header. -->
- <dimen name="multi_user_switch_width_expanded">48dp</dimen>
-
- <!-- The width of user avatar when on Keyguard -->
- <dimen name="multi_user_switch_width_keyguard">34dp</dimen>
-
- <!-- The width of user avatar when collapsed -->
- <dimen name="multi_user_avatar_collapsed_size">22dp</dimen>
-
<!-- The width of user avatar when on Keyguard -->
<dimen name="multi_user_avatar_keyguard_size">22dp</dimen>
@@ -851,19 +657,10 @@
<!-- The font size of the "emergency calls only" label in QS -->
<dimen name="qs_emergency_calls_only_text_size">12sp</dimen>
- <!-- The font size of the date in QS -->
- <dimen name="qs_date_collapsed_size">14sp</dimen>
- <!-- Amount the date/time move when emergency calls only is present -->
- <dimen name="qs_date_time_translation">8dp</dimen>
-
<!-- Padding before battery level text in status bar, QS, and Keyguard -->
<dimen name="battery_level_padding_start">4dp</dimen>
- <!-- The top padding of the clear all button -->
- <dimen name="clear_all_padding_top">12dp</dimen>
-
<dimen name="notification_section_header_height">48dp</dimen>
- <dimen name="notification_section_header_padding_left">16dp</dimen>
<!-- Largest size an avatar might need to be drawn in the user picker, status bar, or
quick settings header -->
@@ -877,15 +674,6 @@
<!-- Margin on the left side of the carrier text on Keyguard -->
<dimen name="keyguard_carrier_text_margin">16dp</dimen>
- <!-- Margin on the left side of the battery % in the header. -->
- <dimen name="header_battery_margin_expanded">6dp</dimen>
-
- <!-- Margin on the left side of the battery % when on Keyguard. -->
- <dimen name="header_battery_margin_keyguard">6dp</dimen>
-
- <!-- Margin on the right side of the system icon group on Keyguard. -->
- <dimen name="system_icons_keyguard_padding_end">4dp</dimen>
-
<!-- Additional translation (downwards) for appearing notifications when going to the full shade
from Keyguard. -->
<dimen name="go_to_full_shade_appearing_translation">200dp</dimen>
@@ -925,49 +713,22 @@
<!-- The width/height of the unlock icon view on keyguard. -->
<dimen name="keyguard_lock_height">42dp</dimen>
- <dimen name="keyguard_lock_width">42dp</dimen>
<dimen name="keyguard_lock_padding">20dp</dimen>
<dimen name="keyguard_indication_margin_bottom">32dp</dimen>
- <dimen name="lock_icon_margin_bottom">98dp</dimen>
-
- <!-- The text size for battery level -->
- <dimen name="battery_level_text_size">12sp</dimen>
-
- <!-- TrustDrawable: Minimum inner radius of the breathing animation -->
- <dimen name="trust_circle_inner_radius_visible_min">22dp</dimen>
- <!-- TrustDrawable: Maximum inner radius of the breathing animation -->
- <dimen name="trust_circle_inner_radius_visible_max">24dp</dimen>
- <!-- TrustDrawable: Inner radius at the end of the exit animation -->
- <dimen name="trust_circle_inner_radius_exit">38dp</dimen>
- <!-- TrustDrawable: Inner radius at the beginning of the enter animation -->
- <dimen name="trust_circle_inner_radius_enter">18dp</dimen>
- <!-- TrustDrawable: Thickness of the circle -->
- <dimen name="trust_circle_thickness">2dp</dimen>
+ <dimen name="lock_icon_margin_bottom">110dp</dimen>
+ <dimen name="ambient_indication_margin_bottom">71dp</dimen>
+
<!-- How much two taps can be apart to still be recognized as a double tap on the lockscreen -->
<dimen name="double_tap_slop">32dp</dimen>
<dimen name="battery_margin_bottom">0dp</dimen>
- <!-- Padding at the end of the view that displays the mobile signal icons. If the view is
- empty, then this padding will not be added to that view. -->
- <dimen name="mobile_signal_group_end_padding">0dp</dimen>
-
- <!-- Padding between the mobile data type and the strength indicator. -->
- <dimen name="mobile_data_icon_start_padding">0dp</dimen>
-
- <!-- Extra padding between the mobile data type icon and the strength indicator when the data
- type icon is wide. -->
- <dimen name="wide_type_icon_start_padding">2dp</dimen>
-
<!-- Padding between the mobile signal indicator and the start icon when the roaming icon
is displayed in the upper left corner. -->
<dimen name="roaming_icon_start_padding">2dp</dimen>
- <!-- Extra padding between multiple phone signal icons. -->
- <dimen name="secondary_telephony_padding">2dp</dimen>
-
<!-- Extra padding between the mobile data type icon and the strength indicator when the data
type icon is wide for the tile in quick settings. -->
<dimen name="wide_type_icon_start_padding_qs">3dp</dimen>
@@ -977,21 +738,11 @@
<!-- The maximum width of the navigation bar ripples. -->
<dimen name="key_button_ripple_max_width">95dp</dimen>
- <!-- Inset shadow for FakeShadowDrawable. It is used to avoid gaps between the card
- and the shadow. -->
- <dimen name="fake_shadow_inset">1dp</dimen>
-
- <dimen name="fake_shadow_size">8dp</dimen>
-
<!-- Starting margin before the signal cluster -->
- <dimen name="signal_cluster_margin_start">2.5dp</dimen>
<!-- Padding between signal cluster and battery icon -->
<dimen name="signal_cluster_battery_padding">6dp</dimen>
- <!-- Padding for signal cluster and battery icon when there are not icons in signal cluster -->
- <dimen name="no_signal_cluster_battery_padding">3dp</dimen>
-
<!-- Screen pinning request width -->
<dimen name="screen_pinning_request_width">@dimen/match_parent</dimen>
<!-- Screen pinning request nav button circle heights -->
@@ -1022,36 +773,10 @@
<!-- Screen pinning description bullet gap width -->
<dimen name="screen_pinning_description_bullet_gap_width">6sp</dimen>
- <!-- Padding to be used on the bottom of the fingerprint icon on Keyguard so it better aligns
- with the other icons. -->
- <dimen name="fingerprint_icon_additional_padding">4dp</dimen>
-
<!-- Minimum margin of the notification panel on the side, when being positioned dynamically -->
<dimen name="notification_panel_min_side_margin">48dp</dimen>
- <!-- Vertical spacing between multiple volume slider rows -->
- <dimen name="volume_slider_interspacing">8dp</dimen>
-
- <!-- Volume dialog vertical offset from the top of the screen -->
- <dimen name="volume_offset_top">0dp</dimen>
-
- <!-- Standard image button size for volume dialog buttons -->
- <dimen name="volume_button_size">48dp</dimen>
-
- <!-- Volume dialog root view bottom margin, at rest -->
- <dimen name="volume_dialog_margin_bottom">4dp</dimen>
- <dimen name="volume_dialog_padding_top">8dp</dimen>
- <dimen name="volume_dialog_padding_end">40dp</dimen>
-
- <dimen name="volume_row_padding_bottom">9.4dp</dimen>
- <dimen name="volume_row_padding_start">4dp</dimen>
- <dimen name="volume_row_header_padding_start">16dp</dimen>
- <dimen name="volume_row_height">64dp</dimen>
<dimen name="volume_row_slider_height">192dp</dimen>
- <dimen name="volume_row_slider_padding_start">12dp</dimen>
-
- <dimen name="volume_expander_margin_end">2dp</dimen>
- <dimen name="volume_expander_margin_top">6dp</dimen>
<!-- Thickness of the assist disclosure beams -->
<dimen name="assist_disclosure_thickness">2.5dp</dimen>
@@ -1059,14 +784,6 @@
<!-- Thickness of the shadows of the assist disclosure beams -->
<dimen name="assist_disclosure_shadow_thickness">1.5dp</dimen>
- <dimen name="fab_size">56dp</dimen>
- <dimen name="fab_margin">16dp</dimen>
- <dimen name="fab_elevation">12dp</dimen>
- <dimen name="fab_press_translation_z">9dp</dimen>
-
- <dimen name="battery_detail_graph_space_top">27dp</dimen>
- <dimen name="battery_detail_graph_space_bottom">27dp</dimen>
-
<!-- Keyboard shortcuts helper -->
<dimen name="ksh_layout_width">@dimen/match_parent</dimen>
<dimen name="ksh_item_text_size">14sp</dimen>
@@ -1075,15 +792,10 @@
<!-- The size of corner radius of the arrow in the onboarding toast. -->
<dimen name="recents_onboarding_toast_arrow_corner_radius">2dp</dimen>
- <!-- The start margin of quick scrub onboarding toast. -->
- <dimen name="recents_quick_scrub_onboarding_margin_start">8dp</dimen>
<dimen name="default_gear_space">18dp</dimen>
- <dimen name="cell_overlay_padding">18dp</dimen>
<!-- Global actions power menu -->
- <dimen name="global_actions_panel_width">120dp</dimen>
- <dimen name="global_actions_padding">12dp</dimen>
<dimen name="global_actions_translate">9dp</dimen>
<!-- Distance from the top of screen in pixels, to position the power menu near the button. -->
@@ -1104,25 +816,14 @@
<dimen name="global_actions_grid_item_layout_height">98dp</dimen>
<dimen name="global_actions_grid_item_side_margin">5dp</dimen>
- <dimen name="global_actions_grid_item_vertical_margin">4dp</dimen>
- <dimen name="global_actions_grid_item_width">64dp</dimen>
<dimen name="global_actions_grid_item_height">64dp</dimen>
- <dimen name="global_actions_grid_item_icon_width">20dp</dimen>
- <dimen name="global_actions_grid_item_icon_height">20dp</dimen>
- <dimen name="global_actions_grid_item_icon_top_margin">12dp</dimen>
- <dimen name="global_actions_grid_item_icon_side_margin">22dp</dimen>
- <dimen name="global_actions_grid_item_icon_bottom_margin">4dp</dimen>
-
<!-- Margins at the left and right of the power menu and home controls widgets. -->
<dimen name="global_actions_side_margin">10dp</dimen>
<!-- Amount to shift the layout when exiting/entering for controls activities -->
<dimen name="global_actions_controls_y_translation">20dp</dimen>
- <!-- Shift quick access wallet down in Global Actions when Controls are unavailable -->
- <dimen name="global_actions_wallet_top_margin">40dp</dimen>
-
<!-- Shutdown and restart actions are larger in power options dialog -->
<dimen name="global_actions_power_dialog_item_height">190dp</dimen>
<dimen name="global_actions_power_dialog_item_width">255dp</dimen>
@@ -1159,17 +860,9 @@
<dimen name="udfps_burn_in_offset_x">7px</dimen>
<dimen name="udfps_burn_in_offset_y">28px</dimen>
- <dimen name="corner_size">8dp</dimen>
- <dimen name="top_padding">0dp</dimen>
- <dimen name="bottom_padding">48dp</dimen>
- <dimen name="edge_margin">8dp</dimen>
-
<!-- The absolute side margins of quick settings -->
<dimen name="quick_settings_bottom_margin_media">8dp</dimen>
- <dimen name="rounded_corner_content_padding">0dp</dimen>
<dimen name="nav_content_padding">0dp</dimen>
- <dimen name="nav_quick_scrub_track_edge_padding">24dp</dimen>
- <dimen name="nav_quick_scrub_track_thickness">10dp</dimen>
<!-- Navigation bar shadow params. -->
<dimen name="nav_key_button_shadow_offset_x">0dp</dimen>
@@ -1214,14 +907,6 @@
<!-- Y translation for credential contents when animating in -->
<dimen name="biometric_dialog_credential_translation_offset">60dp</dimen>
- <!-- Wireless Charging Animation values -->
- <dimen name="wireless_charging_dots_radius_start">0dp</dimen>
- <dimen name="wireless_charging_dots_radius_end">4dp</dimen>
- <dimen name="wireless_charging_circle_radius_start">28dp</dimen>
- <dimen name="wireless_charging_circle_radius_end">84dp</dimen>
- <integer name="wireless_charging_angle_offset">20</integer>
- <integer name="wireless_charging_scale_dots_duration">83</integer>
- <integer name="wireless_charging_num_dots">16</integer>
<!-- Starting text size in sp of batteryLevel for wireless charging animation -->
<item name="wireless_charging_anim_battery_level_text_size_start" format="float" type="dimen">
0
@@ -1284,7 +969,6 @@
<dimen name="ongoing_appops_dialog_side_padding">16dp</dimen>
<!-- Size of the RAT type for CellularTile -->
- <dimen name="celltile_rat_type_size">10sp</dimen>
<!-- Size of media cards in the QSPanel carousel -->
<dimen name="qs_media_padding">16dp</dimen>
@@ -1301,7 +985,6 @@
<dimen name="qs_media_action_margin">12dp</dimen>
<dimen name="qs_seamless_height">24dp</dimen>
<dimen name="qs_seamless_icon_size">12dp</dimen>
- <dimen name="qs_footer_horizontal_margin">22dp</dimen>
<dimen name="qs_media_disabled_seekbar_height">1dp</dimen>
<dimen name="qs_media_enabled_seekbar_height">2dp</dimen>
<dimen name="qs_media_enabled_seekbar_vertical_padding">28dp</dimen>
@@ -1335,7 +1018,6 @@
<dimen name="magnification_max_frame_size">300dp</dimen>
<!-- Home Controls -->
- <dimen name="controls_header_side_margin">4dp</dimen>
<dimen name="controls_header_menu_size">48dp</dimen>
<dimen name="controls_header_bottom_margin">24dp</dimen>
<dimen name="controls_header_app_icon_size">24dp</dimen>
@@ -1361,7 +1043,6 @@
<dimen name="control_base_item_margin">4dp</dimen>
<dimen name="control_status_padding">3dp</dimen>
<fraction name="controls_toggle_bg_intensity">5%</fraction>
- <fraction name="controls_dimmed_alpha">40%</fraction>
<dimen name="controls_setup_top_margin">16dp</dimen>
<dimen name="controls_setup_title">22sp</dimen>
<dimen name="controls_setup_subtitle">14sp</dimen>
@@ -1369,9 +1050,6 @@
<dimen name="controls_detail_dialog_header_height">52dp</dimen>
<!-- Home Controls activity view detail panel-->
- <dimen name="controls_activity_view_top_offset">100dp</dimen>
- <dimen name="controls_activity_view_side_offset">12dp</dimen>
- <dimen name="controls_activity_view_text_size">17sp</dimen>
<dimen name="controls_activity_view_corner_radius">@*android:dimen/config_bottomDialogCornerRadius</dimen>
<!-- Home Controls management screens -->
@@ -1397,12 +1075,7 @@
<dimen name="controls_app_icon_size">24dp</dimen>
<dimen name="controls_app_icon_frame_side_padding">16dp</dimen>
- <dimen name="controls_app_icon_frame_top_padding">4dp</dimen>
- <dimen name="controls_app_icon_frame_bottom_padding">@dimen/controls_app_icon_frame_top_padding</dimen>
- <dimen name="controls_app_bottom_margin">8dp</dimen>
- <dimen name="controls_app_text_padding">8dp</dimen>
<dimen name="controls_app_divider_height">2dp</dimen>
- <dimen name="controls_app_divider_side_margin">32dp</dimen>
<item name="controls_thumbnail_shadow_x" type="dimen" format="float">2.0</item>
<item name="controls_thumbnail_shadow_y" type="dimen" format="float">2.0</item>
@@ -1431,11 +1104,6 @@
<!-- Opacity at which the background for the shutdown UI will be drawn. -->
<item name="shutdown_scrim_behind_alpha" format="float" type="dimen">0.95</item>
- <!-- Allow CornerHandleView and PathSpecCornerPathRenderer to decouple from corner-radius -->
- <dimen name="config_rounded_mask_size">@*android:dimen/rounded_corner_radius</dimen>
- <dimen name="config_rounded_mask_size_top">@*android:dimen/rounded_corner_radius_top</dimen>
- <dimen name="config_rounded_mask_size_bottom">@*android:dimen/rounded_corner_radius_bottom</dimen>
-
<!-- Output switcher panel related dimensions -->
<dimen name="media_output_dialog_list_margin">12dp</dimen>
<dimen name="media_output_dialog_list_max_height">364dp</dimen>
@@ -1544,18 +1212,10 @@
<!-- rounded_slider_corner_radius + rounded_slider_background_padding -->
<dimen name="rounded_slider_background_rounded_corner">32dp</dimen>
- <!-- inset for ic_lock_open within a DisabledUdfpsView -->
- <dimen name="udfps_unlock_icon_inset">16dp</dimen>
-
<!-- Location on the screen of the center of the physical power button. This is a reasonable
default that should be overridden by device-specific overlays. -->
<dimen name="physical_power_button_center_screen_location_y">620px</dimen>
- <!-- Location on the screen of the center of the physical volume up/down buttons. This is a
- reasonable default that should be overridden by device-specific overlays. -->
- <dimen name="physical_volume_up_button_center_screen_location_y">950px</dimen>
- <dimen name="physical_volume_down_button_center_screen_location_y">1150px</dimen>
-
<!-- Location on the screen of the center of the fingerprint sensor. For devices with under
display fingerprint sensors, this directly corresponds to the fingerprint sensor's location.
For devices with sensors on the back of the device, this corresponds to the location on the
@@ -1601,7 +1261,6 @@
<dimen name="ongoing_call_chip_corner_radius">28dp</dimen>
<!-- Internet panel related dimensions -->
- <dimen name="internet_dialog_list_margin">12dp</dimen>
<dimen name="internet_dialog_list_max_height">662dp</dimen>
<!-- The width of large/content heavy dialogs (e.g. Internet, Media output, etc) -->
@@ -1615,13 +1274,8 @@
<!-- End margin of network layout -->
<dimen name="internet_dialog_network_layout_margin">16dp</dimen>
<!-- Size of switch bar in internet dialog -->
- <dimen name="settingslib_switchbar_margin">16dp</dimen>
<!-- Minimum width of switch -->
<dimen name="settingslib_min_switch_width">52dp</dimen>
- <!-- Size of layout margin left -->
- <dimen name="settingslib_switchbar_padding_left">20dp</dimen>
- <!-- Size of layout margin right -->
- <dimen name="settingslib_switchbar_padding_right">20dp</dimen>
<!-- Radius of switch bar -->
<dimen name="settingslib_switch_bar_radius">35dp</dimen>
<!-- Margin of switch thumb -->
@@ -1644,4 +1298,6 @@
<dimen name="qs_dialog_button_vertical_padding">8dp</dimen>
<!-- The button will be 48dp tall, but the background needs to be 36dp tall -->
<dimen name="qs_dialog_button_vertical_inset">6dp</dimen>
+
+ <dimen name="keyguard_unfold_translation_x">16dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index f4f881f1ffa5..926734c2749f 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -46,17 +46,11 @@
<item type="id" name="height_animator_start_value_tag"/>
<item type="id" name="x_animator_tag_start_value"/>
<item type="id" name="y_animator_tag_start_value"/>
- <item type="id" name="doze_saved_filter_tag"/>
<item type="id" name="qs_icon_tag"/>
<item type="id" name="qs_slash_tag"/>
<item type="id" name="scrim"/>
<item type="id" name="scrim_alpha_start"/>
<item type="id" name="scrim_alpha_end"/>
- <item type="id" name="notification_power"/>
- <item type="id" name="notification_screenshot"/>
- <item type="id" name="notification_hidden"/>
- <item type="id" name="notification_temperature"/>
- <item type="id" name="notification_plugin"/>
<item type="id" name="transformation_start_x_tag"/>
<item type="id" name="doze_intensity_tag"/>
<item type="id" name="transformation_start_y_tag"/>
diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml
index 116403c931b3..f0f7a196d694 100644
--- a/packages/SystemUI/res/values/integers.xml
+++ b/packages/SystemUI/res/values/integers.xml
@@ -17,11 +17,6 @@
<resources>
<integer name="biometric_dialog_text_gravity">8388611</integer> <!-- gravity start -->
- <!-- Action footer width used for layout_width to indicate WRAP_CONTENT (along with a weight of
- 0) as we can allow the carrier text to stretch as far as needed in the QS footer. -->
- <integer name="qs_footer_actions_width">0</integer>
- <integer name="qs_footer_actions_weight">1</integer>
-
<integer name="qs_security_footer_maxLines">2</integer>
<integer name="magnification_default_scale">2</integer>
diff --git a/packages/SystemUI/res/values/internal.xml b/packages/SystemUI/res/values/internal.xml
index c29a51f6178e..649e59e02adb 100644
--- a/packages/SystemUI/res/values/internal.xml
+++ b/packages/SystemUI/res/values/internal.xml
@@ -18,6 +18,5 @@
<dimen name="status_bar_height">@*android:dimen/status_bar_height</dimen>
<dimen name="navigation_bar_height">@*android:dimen/navigation_bar_height</dimen>
<dimen name="navigation_bar_frame_height">@*android:dimen/navigation_bar_frame_height</dimen>
- <dimen name="navigation_bar_height_car_mode">@*android:dimen/navigation_bar_height_car_mode</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/mland_config.xml b/packages/SystemUI/res/values/mland_config.xml
index 0ca88aed42ea..6cd34097adaf 100644
--- a/packages/SystemUI/res/values/mland_config.xml
+++ b/packages/SystemUI/res/values/mland_config.xml
@@ -30,7 +30,6 @@
<dimen name="cloud_size_min">10dp</dimen>
<dimen name="cloud_size_max">100dp</dimen>
<dimen name="sun_size">45dp</dimen>
- <dimen name="moon_size">30dp</dimen>
<dimen name="star_size_min">3dp</dimen>
<dimen name="star_size_max">5dp</dimen>
<dimen name="G">30dp</dimen>
diff --git a/packages/SystemUI/res/values/mland_strings.xml b/packages/SystemUI/res/values/mland_strings.xml
deleted file mode 100644
index fada1aeab795..000000000000
--- a/packages/SystemUI/res/values/mland_strings.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Name of the easter egg. DO NOT TRANSLATE -->
- <string name="mland">Marshmallow Land</string>
-</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 62737e6b6e61..879726650b88 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -20,24 +20,6 @@
<!-- Name of the status bar as seen in the applications info settings page. [CHAR LIMIT=12] -->
<string name="app_label">System UI</string>
- <!-- The text for the button in the notification window-shade that clears
- all of the currently visible notifications. [CHAR LIMIT=10]-->
- <string name="status_bar_clear_all_button">Clear</string>
-
- <!-- The label in the bar at the top of the status bar when there are no notifications
- showing. [CHAR LIMIT=40]-->
- <string name="status_bar_no_notifications_title">No notifications</string>
-
- <!-- The label for the group of notifications for ongoing events in the opened version of
- the status bar. An ongoing call is the prime example of this. The MP3 music player
- might be another example. [CHAR LIMIT=40] -->
- <string name="status_bar_ongoing_events_title">Ongoing</string>
-
- <!-- The label for the group of notifications for recent events in the opened version of
- the status bar. Recently received text messsages (SMS), emails, calendar alerts, etc.
- [CHAR LIMIT=40] -->
- <string name="status_bar_latest_events_title">Notifications</string>
-
<!-- When the battery is low, this is displayed to the user in a dialog. The title of the low battery alert. [CHAR LIMIT=NONE]-->
<string name="battery_low_title">Battery may run out soon</string>
@@ -49,22 +31,18 @@
<!-- A message that appears when the battery remaining estimate is low in a dialog. This is
appended to the subtitle of the low battery alert. "percentage" is the percentage of battery
remaining. "time" is the amount of time remaining before the phone runs out of battery [CHAR LIMIT=none]-->
- <string name="battery_low_percent_format_hybrid"><xliff:g id="percentage">%1$s</xliff:g> remaining, about <xliff:g id="time">%2$s</xliff:g> left based on your usage</string>
<!-- A message that appears when the battery remaining estimate is low in a dialog and insufficient
data was present to say it is customized to the user. This is appended to the subtitle of the
low battery alert. "percentage" is the percentage of battery remaining. "time" is the amount
of time remaining before the phone runs out of battery [CHAR LIMIT=none]-->
- <string name="battery_low_percent_format_hybrid_short"><xliff:g id="percentage">%1$s</xliff:g> remaining, about <xliff:g id="time">%2$s</xliff:g> left</string>
<!-- Same as battery_low_percent_format, with a notice about battery saver if on. [CHAR LIMIT=none]-->
- <string name="battery_low_percent_format_saver_started"><xliff:g id="percentage">%s</xliff:g> remaining. Battery Saver is on.</string>
<!-- A message that appears when a USB charger is plugged in and the device does not
support charging on it. That is, a charger that fits into the USB port and goes into
a wall socket, not into a computer. (This happens because some devices require more
current than the USB spec allows. [CHAR LIMIT=NONE] -->
- <string name="invalid_charger">Can\'t charge via USB. Use the charger that came with your device.</string>
<!-- First line of invalid_charger, used in the notification form. [CHAR LIMIT=NONE]-->
<string name="invalid_charger_title">Can\'t charge via USB</string>
@@ -72,10 +50,6 @@
<!-- Second line of invalid_charger, used in the notification form. [CHAR LIMIT=NONE]-->
<string name="invalid_charger_text">Use the charger that came with your device</string>
- <!-- When the battery is low, this is the label of the button to go to the
- power usage activity to find out what drained the battery. [CHAR LIMIT=30] -->
- <string name="battery_low_why">Settings</string>
-
<!-- Battery saver confirmation dialog title [CHAR LIMIT=NONE]-->
<string name="battery_saver_confirmation_title">Turn on Battery Saver?</string>
@@ -89,34 +63,15 @@
<string name="battery_saver_start_action">Turn on Battery Saver</string>
<!-- Name of the button that links to the Settings app. [CHAR LIMIT=NONE] -->
- <string name="status_bar_settings_settings_button">Settings</string>
<!-- Name of the button that links to the Wifi settings screen. [CHAR LIMIT=NONE] -->
- <string name="status_bar_settings_wifi_button">Wi-Fi</string>
<!-- Label in system panel saying the device will use the orientation sensor to rotate [CHAR LIMIT=30] -->
<string name="status_bar_settings_auto_rotation">Auto-rotate screen</string>
- <!-- Abbreviation / label for mute brightness mode button. Should be all caps. [CHAR LIMIT=6] -->
- <string name="status_bar_settings_mute_label">MUTE</string>
-
- <!-- Abbreviation / label for automatic brightness mode button. Should be all caps. [CHAR LIMIT=6] -->
- <string name="status_bar_settings_auto_brightness_label">AUTO</string>
-
- <!-- Label in system panel saying the device will show notifications [CHAR LIMIT=30] -->
- <string name="status_bar_settings_notifications">Notifications</string>
-
<!-- Separator for PLMN and SPN in network name. -->
<string name="status_bar_network_name_separator" translatable="false"> - </string>
- <!-- Network connection string for Bluetooth Reverse Tethering -->
- <string name="bluetooth_tethered">Bluetooth tethered</string>
- <!-- Title of a button to open the settings for input methods [CHAR LIMIT=30] -->
- <string name="status_bar_input_method_settings_configure_input_methods">Set up input methods</string>
-
- <!-- Label of a toggle switch to disable use of the physical keyboard in favor of the IME. [CHAR LIMIT=25] -->
- <string name="status_bar_use_physical_keyboard">Physical keyboard</string>
-
<!-- Prompt for the USB device permission dialog [CHAR LIMIT=80] -->
<string name="usb_device_permission_prompt">Allow <xliff:g id="application" example= "Usb Mega Player">%1$s</xliff:g> to access <xliff:g id="usb_device" example="USB Headphones">%2$s</xliff:g>?</string>
@@ -201,14 +156,6 @@
<!-- Button text to disable contaminant detection [CHAR LIMIT=NONE] -->
<string name="learn_more">Learn more</string>
- <!-- Checkbox label for application compatibility mode ON (zooming app to look like it's running
- on a phone). [CHAR LIMIT=25] -->
- <string name="compat_mode_on">Zoom to fill screen</string>
-
- <!-- Checkbox label for application compatibility mode OFF (normal mode on tablets).
- [CHAR LIMIT=25] -->
- <string name="compat_mode_off">Stretch to fill screen</string>
-
<!-- Power menu item for taking a screenshot [CHAR LIMIT=20]-->
<string name="global_action_screenshot">Screenshot</string>
<!-- Message shown in power menu when smart lock has been disabled [CHAR_LIMIT=NONE] -->
@@ -218,14 +165,10 @@
[CHAR LIMIT=50] -->
<string name="remote_input_image_insertion_text">sent an image</string>
- <!-- Notification ticker displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=30] -->
- <string name="screenshot_saving_ticker">Saving screenshot\u2026</string>
<!-- Informs the user that a screenshot is being saved. [CHAR LIMIT=50] -->
<string name="screenshot_saving_title">Saving screenshot\u2026</string>
<!-- Notification title displayed when a screenshot is saved to the Gallery. [CHAR LIMIT=50] -->
<string name="screenshot_saved_title">Screenshot saved</string>
- <!-- Notification text displayed when a screenshot is saved to the Gallery. [CHAR LIMIT=100] -->
- <string name="screenshot_saved_text">Tap to view your screenshot</string>
<!-- Notification title displayed when we fail to take a screenshot. [CHAR LIMIT=50] -->
<string name="screenshot_failed_title">Couldn\'t save screenshot</string>
<!-- Notification text displayed when we fail to save a screenshot due to locked storage. [CHAR LIMIT=100] -->
@@ -241,6 +184,8 @@
<string name="screenshot_edit_label">Edit</string>
<!-- Content description indicating that tapping the element will allow editing the screenshot [CHAR LIMIT=NONE] -->
<string name="screenshot_edit_description">Edit screenshot</string>
+ <!-- Content description indicating that tapping the element will allow sharing the screenshot [CHAR LIMIT=NONE] -->
+ <string name="screenshot_share_description">Share screenshot</string>
<!-- Label for UI element which allows the user to capture additional off-screen content in a screenshot. [CHAR LIMIT=30] -->
<string name="screenshot_scroll_label">Capture more</string>
<!-- Content description indicating that tapping a button will dismiss the screenshots UI [CHAR LIMIT=NONE] -->
@@ -285,19 +230,11 @@
<!-- Label for the checkbox to enable showing location of touches during screen recording [CHAR LIMIT=NONE]-->
<string name="screenrecord_taps_label">Show touches on screen</string>
<!-- Label for notification that the user can tap to stop and save the screen recording [CHAR LIMIT=NONE] -->
- <string name="screenrecord_stop_text">Tap to stop</string>
<!-- Label for notification action to stop and save the screen recording [CHAR LIMIT=35] -->
<string name="screenrecord_stop_label">Stop</string>
- <!-- Label for notification action to pause screen recording [CHAR LIMIT=35] -->
- <string name="screenrecord_pause_label">Pause</string>
- <!-- Label for notification action to resume screen recording [CHAR LIMIT=35] -->
- <string name="screenrecord_resume_label">Resume</string>
- <!-- Label for notification action to cancel and discard screen recording [CHAR LIMIT=35] -->
- <string name="screenrecord_cancel_label">Cancel</string>
<!-- Label for notification action to share screen recording [CHAR LIMIT=35] -->
<string name="screenrecord_share_label">Share</string>
<!-- A toast message shown after successfully canceling a screen recording [CHAR LIMIT=NONE] -->
- <string name="screenrecord_cancel_success">Screen recording canceled</string>
<!-- Notification text shown after saving a screen recording [CHAR LIMIT=100] -->
<string name="screenrecord_save_title">Screen recording saved</string>
<!-- Subtext for a notification shown after saving a screen recording to prompt the user to view it [CHAR_LIMIT=100] -->
@@ -305,19 +242,9 @@
<!-- A toast message shown when there is an error deleting a screen recording [CHAR LIMIT=NONE] -->
<string name="screenrecord_delete_error">Error deleting screen recording</string>
<!-- A toast message shown when the screen recording cannot be started due to insufficient permissions [CHAR LIMIT=NONE] -->
- <string name="screenrecord_permission_error">Failed to get permissions</string>
<!-- A toast message shown when the screen recording cannot be started due to a generic error [CHAR LIMIT=NONE] -->
<string name="screenrecord_start_error">Error starting screen recording</string>
- <!-- Title for the USB function chooser in UsbPreferenceActivity. [CHAR LIMIT=30] -->
- <string name="usb_preference_title">USB file transfer options</string>
- <!-- Label for the MTP USB function in UsbPreferenceActivity. [CHAR LIMIT=50] -->
- <string name="use_mtp_button_title">Mount as a media player (MTP)</string>
- <!-- Label for the PTP USB function in UsbPreferenceActivity. [CHAR LIMIT=50] -->
- <string name="use_ptp_button_title">Mount as a camera (PTP)</string>
- <!-- Label for the installer CD image option in UsbPreferenceActivity. [CHAR LIMIT=50] -->
- <string name="installer_cd_button_title">Install Android File Transfer app for Mac</string>
-
<!-- Content description of the back button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_back">Back</string>
<!-- Content description of the home button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -331,7 +258,6 @@
<!-- Content description of the recents button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_recent">Overview</string>
<!-- Content description of the search button for accessibility. [CHAR LIMIT=NONE] -->
- <string name="accessibility_search_light">Search</string>
<!-- Content description of the camera button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_camera_button">Camera</string>
<!-- Content description of the phone button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -345,15 +271,12 @@
<!-- Content description of the lock icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_lock_icon">Device locked</string>
<!-- Content description hint of the unlock button when fingerprint is on (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_waiting_for_fingerprint">Waiting for fingerprint</string>
<!-- Accessibility action of the unlock button when fingerpint is on (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_unlock_without_fingerprint">Unlock without using your fingerprint</string>
<!-- Content description of the Trusted Face icon for accessibility. [CHAR LIMIT=NONE] -->
<string name="accessibility_scanning_face">Scanning face</string>
<!-- Click action label for accessibility for the smart reply buttons (not shown on-screen).". [CHAR LIMIT=NONE] -->
<string name="accessibility_send_smart_reply">Send</string>
<!-- Content description of the manage notification button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_manage_notification">Manage notifications</string>
<!-- Click action label for accessibility for the phone button. [CHAR LIMIT=NONE] -->
<string name="phone_label">open phone</string>
<!-- Click action label for accessibility for the voice assist button. This is not shown on-screen and is an accessibility label for the icon which launches the voice assist from the lock screen.[CHAR LIMIT=NONE] -->
@@ -399,7 +322,6 @@
<!-- Error string shown when the user enters an incorrect PIN/pattern/password and it counts towards the max attempts before the data on the device is wiped. [CHAR LIMIT=NONE]-->
<string name="biometric_dialog_credential_attempts_before_wipe">Try again. Attempt <xliff:g id="attempts" example="1">%1$d</xliff:g> of <xliff:g id="max_attempts" example="3">%2$d</xliff:g>.</string>
-
<!-- Title of a dialog shown when the user only has one attempt left to provide the correct PIN/pattern/password before the device, one of its users, or a work profile is wiped. [CHAR LIMIT=NONE] -->
<string name="biometric_dialog_last_attempt_before_wipe_dialog_title">Your data will be deleted</string>
<!-- Content of a dialog shown when the user only has one attempt left to provide the correct lock pattern before the device is wiped. [CHAR LIMIT=NONE] -->
@@ -436,127 +358,36 @@
<string name="accessibility_fingerprint_dialog_fingerprint_icon">Fingerprint icon</string>
<!-- Message shown to inform the user a face cannot be recognized and fingerprint should instead be used.[CHAR LIMIT=50] -->
<string name="fingerprint_dialog_use_fingerprint_instead">Can\u2019t recognize face. Use fingerprint instead.</string>
- <!-- Message shown to ask the user to use fingerprint to continue.[CHAR LIMIT=50] -->
- <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>
- <!-- Content description of the face icon when the system-provided face dialog is showing, for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_face_dialog_face_icon">Face icon</string>
-
- <!-- Content description of the compatibility zoom button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_compatibility_zoom_button">Compatibility zoom button.</string>
-
- <!-- Content description of picture of the compatibility zoom example for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_compatibility_zoom_example">Zoom smaller to larger screen.</string>
-
<!-- Content description of the bluetooth icon when connected for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_bluetooth_connected">Bluetooth connected.</string>
<!-- Content description of the bluetooth icon when connecting for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_bluetooth_disconnected">Bluetooth disconnected.</string>
-
- <!-- Content description of the battery when no battery for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_no_battery">No battery.</string>
- <!-- Content description of the battery when it is one bar for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_battery_one_bar">Battery one bar.</string>
- <!-- Content description of the battery when it is two bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_battery_two_bars">Battery two bars.</string>
- <!-- Content description of the battery when it is three bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_battery_three_bars">Battery three bars.</string>
- <!-- Content description of the battery when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_battery_full">Battery full.</string>
+
<!-- Content description of the battery when battery state is unknown for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_battery_unknown">Battery percentage unknown.</string>
- <!-- Content description of the wifi label showing what we are connected to. [CHAR LIMIT=NONE] -->
- <string name="accessibility_wifi_name">Connected to <xliff:g id="wifi" example="Home Network">%s</xliff:g>.</string>
-
<!-- Content description of the bluetooth label showing what we are connected to. [CHAR LIMIT=NONE] -->
<string name="accessibility_bluetooth_name">Connected to <xliff:g id="bluetooth" example="Car Audio">%s</xliff:g>.</string>
<!-- Content description of the cast label showing what we are connected to. [CHAR LIMIT=NONE] -->
<string name="accessibility_cast_name">Connected to <xliff:g id="cast" example="TV">%s</xliff:g>.</string>
-
- <!-- Content description of the WiMAX signal when no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_no_wimax">No WiMAX.</string>
- <!-- Content description of the WiMAX signal when it is one bar for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_wimax_one_bar">WiMAX one bar.</string>
- <!-- Content description of the WiMAX signal when it is two bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_wimax_two_bars">WiMAX two bars.</string>
- <!-- Content description of the WiMAX signal when it is three bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_wimax_three_bars">WiMAX three bars.</string>
- <!-- Content description of the WiMAX signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_wimax_signal_full">WiMAX signal full.</string>
-
- <!-- Content description of an item with no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_no_signal">No signal.</string>
<!-- Content description of an item with no signal and no connection for accessibility (not shown on the screen) [CHAR LIMIT=NONE] -->
<string name="accessibility_not_connected">Not connected.</string>
- <!-- Content description of an item with zero signal bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_zero_bars">Zero bars.</string>
- <!-- Content description of an item with one signal bar for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_one_bar">One bar.</string>
- <!-- Content description of an item with two signal bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_two_bars">Two bars.</string>
- <!-- Content description of an item with three signal bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_three_bars">Three bars.</string>
- <!-- Content description of an item with full signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_signal_full">Signal full.</string>
-
- <!-- Content description of an item that is turned on for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_desc_on">On.</string>
- <!-- Content description of an item that is turned off for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_desc_off">Off.</string>
- <!-- Content description of an item that is connected for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_desc_connected">Connected.</string>
- <!-- Content description of an item that is connecting for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_desc_connecting">Connecting.</string>
-
- <!-- Content description of the data connection type HSPA and its variants. [CHAR LIMIT=NONE] -->
- <string name="data_connection_hspa">HSPA</string>
-
- <!-- Content description of the data connection type 5Ge. [CHAR LIMIT=NONE] -->
- <string name="data_connection_5ge" translatable="false">5Ge</string>
-
-
<!-- Content description of the roaming data connection type. [CHAR LIMIT=NONE] -->
<string name="data_connection_roaming">Roaming</string>
- <!-- Content description of the data connection type WiFi for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_data_connection_wifi">Wi-Fi</string>
-
- <!-- Content description of the data connection with no SIM for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_no_sim">No SIM.</string>
-
- <!-- Content description of the cell data. [CHAR LIMIT=NONE] -->
- <string name="accessibility_cell_data">Mobile Data</string>
-
- <!-- Content description of the cell data being enabled. [CHAR LIMIT=NONE] -->
- <string name="accessibility_cell_data_on">Mobile Data On</string>
-
<!-- Content description of the cell data being disabled but shortened. [CHAR LIMIT=20] -->
<string name="cell_data_off">Off</string>
- <!-- Content description of the bluetooth tethering icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_bluetooth_tether">Bluetooth tethering.</string>
-
<!-- Content description of the airplane mode icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_airplane_mode">Airplane mode.</string>
<!-- Content description of the VPN icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_vpn_on">VPN on.</string>
- <!-- Content description of the no sim icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_no_sims">No SIM card.</string>
-
- <!-- Content description of button to open battery details icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_battery_details">Open battery details</string>
-
<!-- Content description of the battery level icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_battery_level">Battery <xliff:g id="number">%d</xliff:g> percent.</string>
@@ -566,24 +397,9 @@
<!-- Content description of the battery level icon for accessibility while the device is charging (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_battery_level_charging">Battery charging, <xliff:g id="battery_percentage">%d</xliff:g> percent.</string>
- <!-- Content description of the button for showing a settings panel in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_settings_button">System settings.</string>
-
- <!-- Content description of the button for showing a notifications panel in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_notifications_button">Notifications.</string>
-
<!-- Content description of overflow icon container of the notifications for accessibility (not shown on the screen)[CHAR LIMIT=NONE] -->
<string name="accessibility_overflow_action">See all notifications</string>
- <!-- Content description of the button for removing a notification in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_remove_notification">Clear notification.</string>
-
- <!-- Content description of the enabled GPS icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_gps_enabled">GPS enabled.</string>
-
- <!-- Content description of the acquiring GPS icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_gps_acquiring">GPS acquiring.</string>
-
<!-- Content description of the TeleTypewriter(TTY) enabled icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_tty_enabled">TeleTypewriter enabled.</string>
@@ -596,41 +412,21 @@
<!-- Content description of the cast icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_casting">@string/quick_settings_casting</string>
- <!-- Content description of the work mode icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_work_mode">@string/quick_settings_work_mode_label</string>
-
- <!-- Content description to tell the user a notification has been removed from the notification shade -->
- <string name="accessibility_notification_dismissed">Notification dismissed.</string>
-
<!-- Content description for the notification shade panel (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_desc_notification_shade">Notification shade.</string>
<!-- Content description for the quick settings panel (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_desc_quick_settings">Quick settings.</string>
<!-- Content description for the lock screen (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_desc_lock_screen">Lock screen.</string>
- <!-- Content description for the settings button in the status bar header. [CHAR LIMIT=NONE] -->
- <string name="accessibility_desc_settings">Settings</string>
- <!-- Content description for the recent apps panel (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_desc_recent_apps">Overview.</string>
<!-- Content description for the work profile lock screen. This prevents work profile apps from being used, but personal apps can be used as normal (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_desc_work_lock">Work lock screen</string>
<!-- Content description for the close button in the zen mode panel introduction message. [CHAR LIMIT=NONE] -->
<string name="accessibility_desc_close">Close</string>
- <!-- Content description of the wifi tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_wifi"><xliff:g id="signal" example="Three bars">%1$s</xliff:g>.</string>
<!-- Announcement made when the wifi is turned off (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_wifi_changed_off">Wifi turned off.</string>
<!-- Announcement made when the wifi is turned on (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_wifi_changed_on">Wifi turned on.</string>
- <!-- Content description of the mobile data tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_mobile">Mobile <xliff:g id="signal" example="Three bars">%1$s</xliff:g>. <xliff:g id="type" example="4G">%2$s</xliff:g>. <xliff:g id="network" example="T-Mobile">%3$s</xliff:g>.</string>
- <!-- Content description of the battery tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_battery">Battery <xliff:g id="state" example="50% charging">%s</xliff:g>.</string>
- <!-- Content description of the airplane mode tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_airplane_off">Airplane mode off.</string>
- <!-- Content description of the airplane mode tile in quick settings when on (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_airplane_on">Airplane mode on.</string>
<!-- Announcement made when the airplane mode changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_airplane_changed_off">Airplane mode turned off.</string>
<!-- Announcement made when the airplane mode changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -647,40 +443,22 @@
<string name="accessibility_quick_settings_dnd_changed_on">Do Not Disturb turned on.</string>
<!-- Content description of the bluetooth tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_bluetooth">Bluetooth.</string>
- <!-- Content description of the bluetooth tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_bluetooth_off">Bluetooth off.</string>
<!-- Content description of the bluetooth tile in quick settings when on (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_bluetooth_on">Bluetooth on.</string>
- <!-- Content description of the bluetooth tile in quick settings when connecting (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_bluetooth_connecting">Bluetooth connecting.</string>
- <!-- Content description of the bluetooth tile in quick settings when connected (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_bluetooth_connected">Bluetooth connected.</string>
<!-- Announcement made when the bluetooth is turned off (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_bluetooth_changed_off">Bluetooth turned off.</string>
<!-- Announcement made when the bluetooth is turned on (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_bluetooth_changed_on">Bluetooth turned on.</string>
- <!-- Content description of the location tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_location_off">Location reporting off.</string>
- <!-- Content description of the location tile in quick settings when on (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_location_on">Location reporting on.</string>
<!-- Announcement made when the location tile changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_location_changed_off">Location reporting turned off.</string>
<!-- Announcement made when the location tile changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_location_changed_on">Location reporting turned on.</string>
<!-- Content description of the alarm tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_alarm">Alarm set for <xliff:g id="time" example="Wed 3:30 PM">%s</xliff:g>.</string>
- <!-- Content description of quick settings detail panel close button (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_close">Close panel.</string>
<!-- Content description of zen mode time condition plus button (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_more_time">More time.</string>
<!-- Content description of zen mode time condition minus button (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_less_time">Less time.</string>
- <!-- Content description of the flashlight tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_flashlight_off">Flashlight off.</string>
- <!-- Content description of the flashlight tile in quick settings when unavailable (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_flashlight_unavailable">Flashlight unavailable.</string>
- <!-- Content description of the flashlight tile in quick settings when on (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_flashlight_on">Flashlight on.</string>
<!-- Announcement made when the flashlight state changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_flashlight_changed_off">Flashlight turned off.</string>
<!-- Announcement made when the flashlight state changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -696,28 +474,19 @@
<!-- Announcement made when the screen stopped casting (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_casting_turned_off">Screen casting stopped.</string>
<!-- Announcement made when the work mode changes to off (not shown on the screen). Paused is used as a verb. [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_work_mode_changed_off">Work mode paused.</string>
<!-- Announcement made when the work mode changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_work_mode_changed_on">Work mode turned on.</string>
<!-- Announcement made when the Data Saver changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_data_saver_changed_off">Data Saver turned off.</string>
<!-- Announcement made when the Data Saver changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_data_saver_changed_on">Data Saver turned on.</string>
<!-- Announcement made when the Sensor Privacy changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_sensor_privacy_changed_off">Sensor Privacy turned off.</string>
<!-- Announcement made when the Sensor Privacy changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_sensor_privacy_changed_on">Sensor Privacy turned on.</string>
<!-- Content description of the display brightness slider (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_brightness">Display brightness</string>
<!-- Content description of the charging indicator on Ambient Display (lower-power version of the lock screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_ambient_display_charging">Charging</string>
- <!-- Title of dialog shown when 2G-3G data usage has exceeded limit and has been disabled. [CHAR LIMIT=48] -->
- <string name="data_usage_disabled_dialog_3g_title">2G-3G data is paused</string>
- <!-- Title of dialog shown when 4G data usage has exceeded limit and has been disabled. [CHAR LIMIT=48] -->
- <string name="data_usage_disabled_dialog_4g_title">4G data is paused</string>
<!-- Title of dialog shown when mobile data usage has exceeded limit and has been disabled. [CHAR LIMIT=48] -->
<string name="data_usage_disabled_dialog_mobile_title">Mobile data is paused</string>
<!-- Title of dialog shown when data usage has exceeded limit and has been disabled. [CHAR LIMIT=48] -->
@@ -727,12 +496,6 @@
<!-- Dialog button indicating that data connection should be re-enabled. [CHAR LIMIT=28] -->
<string name="data_usage_disabled_dialog_enable">Resume</string>
- <!-- Notification text: when GPS is getting a fix [CHAR LIMIT=50] -->
- <string name="gps_notification_searching_text">Searching for GPS</string>
-
- <!-- Notification text: when GPS has found a fix [CHAR LIMIT=50] -->
- <string name="gps_notification_found_text">Location set by GPS</string>
-
<!-- Accessibility text describing the presence of active location requests by one or more apps -->
<string name="accessibility_location_active">Location requests active</string>
@@ -752,18 +515,14 @@
</plurals>
<!-- Format to use to summarize a message from a contact in a single line of text. For example: "Julia: How's it going?". [CHAR LIMIT=NONE] -->
- <string name="notification_summary_message_format"><xliff:g id="contact_name" example="Julia">%1$s</xliff:g>: <xliff:g id="message_content" example="How is it going?">%2$s</xliff:g></string>
<!-- Content description of button in notification inspector for system settings relating to
notifications from this application [CHAR LIMIT=NONE] -->
- <string name="status_bar_notification_inspect_item_title">Notification settings</string>
<!-- Content description of button in notification inspetor for application-provided settings
for its own notifications [CHAR LIMIT=NONE] -->
- <string name="status_bar_notification_app_settings_title"><xliff:g id="app_name" example="Calendar">%s</xliff:g> settings</string>
<!-- Description of the button in the phone-style notification panel that controls auto-rotation, when auto-rotation is on. [CHAR LIMIT=NONE] -->
- <string name="accessibility_rotation_lock_off">Screen will rotate automatically.</string>
<!-- Description of the button in the phone-style notification panel that controls auto-rotation, when auto-rotation is off. [CHAR LIMIT=NONE] -->
<string name="accessibility_rotation_lock_on_landscape">Screen is locked in landscape orientation.</string>
@@ -772,13 +531,10 @@
<string name="accessibility_rotation_lock_on_portrait">Screen is locked in portrait orientation.</string>
<!-- Announcement made when the screen is rotating automatically again (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_rotation_lock_off_changed">Screen will now rotate automatically.</string>
<!-- Announcement made when the rotation lock state changes to landscape only (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_rotation_lock_on_landscape_changed">Screen is now locked in landscape orientation.</string>
<!-- Announcement made when the rotation lock state changes to portrait only (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_rotation_lock_on_portrait_changed">Screen is now locked in portrait orientation.</string>
<!-- Name of the K-release easter egg: a display case for all our tastiest desserts. [CHAR LIMIT=30] -->
<string name="dessert_case">Dessert Case</string>
@@ -790,21 +546,15 @@
<string name="ethernet_label">Ethernet</string>
<!-- QuickSettings: Onboarding text that introduces users to long press on an option in order to view the option's menu in Settings [CHAR LIMIT=NONE] -->
- <string name="quick_settings_header_onboarding_text">Touch &amp; hold icons for more options</string>
<!-- QuickSettings: Do not disturb [CHAR LIMIT=NONE] -->
<string name="quick_settings_dnd_label">Do Not Disturb</string>
<!-- QuickSettings: Do not disturb - Priority only [CHAR LIMIT=NONE] -->
- <string name="quick_settings_dnd_priority_label">Priority only</string>
<!-- QuickSettings: Do not disturb - Alarms only [CHAR LIMIT=NONE] -->
- <string name="quick_settings_dnd_alarms_label">Alarms only</string>
<!-- QuickSettings: Do not disturb - Total silence [CHAR LIMIT=NONE] -->
- <string name="quick_settings_dnd_none_label">Total silence</string>
<!-- QuickSettings: Bluetooth [CHAR LIMIT=NONE] -->
<string name="quick_settings_bluetooth_label">Bluetooth</string>
<!-- QuickSettings: Bluetooth (Multiple) [CHAR LIMIT=NONE] -->
- <string name="quick_settings_bluetooth_multiple_devices_label">Bluetooth (<xliff:g id="number">%d</xliff:g> Devices)</string>
<!-- QuickSettings: Bluetooth (Off) [CHAR LIMIT=NONE] -->
- <string name="quick_settings_bluetooth_off_label">Bluetooth Off</string>
<!-- QuickSettings: Bluetooth detail panel, text when there are no items [CHAR LIMIT=NONE] -->
<string name="quick_settings_bluetooth_detail_empty_text">No paired devices available</string>
<!-- QuickSettings: Bluetooth secondary label for the battery level of a connected device [CHAR LIMIT=20]-->
@@ -820,25 +570,18 @@
<!-- QuickSettings: Bluetooth secondary label shown when bluetooth is being enabled [CHAR LIMIT=NONE] -->
<string name="quick_settings_bluetooth_secondary_label_transient">Turning on&#8230;</string>
<!-- QuickSettings: Brightness [CHAR LIMIT=NONE] -->
- <string name="quick_settings_brightness_label">Brightness</string>
<!-- QuickSettings: Rotation Unlocked [CHAR LIMIT=NONE] -->
<string name="quick_settings_rotation_unlocked_label">Auto-rotate</string>
<!-- Accessibility label for Auto-ratate QuickSettings tile [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_rotation">Auto-rotate screen</string>
<!-- Accessibility label for value of Auto-ratate QuickSettings tile [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_rotation_value"><xliff:g name="rotation" example="Portrait">%s</xliff:g> mode</string>
<!-- QuickSettings: Rotation Locked [CHAR LIMIT=NONE] -->
- <string name="quick_settings_rotation_locked_label">Rotation locked</string>
<!-- QuickSettings: Locked to Portrait [CHAR LIMIT=NONE] -->
- <string name="quick_settings_rotation_locked_portrait_label">Portrait</string>
<!-- QuickSettings: Locked to Landscape [CHAR LIMIT=NONE] -->
- <string name="quick_settings_rotation_locked_landscape_label">Landscape</string>
<!-- QuickSettings: IME [CHAR LIMIT=NONE] -->
- <string name="quick_settings_ime_label">Input Method</string>
<!-- QuickSettings: Location [CHAR LIMIT=NONE] -->
<string name="quick_settings_location_label">Location</string>
<!-- QuickSettings: Location (Off) [CHAR LIMIT=NONE] -->
- <string name="quick_settings_location_off_label">Location Off</string>
<!-- QuickSettings: Camera [CHAR LIMIT=NONE] -->
<string name="quick_settings_camera_label">Camera access</string>
<!-- QuickSettings: Microphone [CHAR LIMIT=NONE] -->
@@ -850,19 +593,13 @@
<!-- QuickSettings: Media device [CHAR LIMIT=NONE] -->
<string name="quick_settings_media_device_label">Media device</string>
<!-- QuickSettings: RSSI [CHAR LIMIT=NONE] -->
- <string name="quick_settings_rssi_label">RSSI</string>
<!-- QuickSettings: RSSI (No network) [CHAR LIMIT=NONE] -->
- <string name="quick_settings_rssi_emergency_only">Emergency Calls Only</string>
<!-- QuickSettings: Settings [CHAR LIMIT=NONE] -->
- <string name="quick_settings_settings_label">Settings</string>
<!-- QuickSettings: Time [CHAR LIMIT=NONE] -->
- <string name="quick_settings_time_label">Time</string>
<!-- QuickSettings: User [CHAR LIMIT=NONE] -->
- <string name="quick_settings_user_label">Me</string>
<!-- QuickSettings: Title of the user detail panel [CHAR LIMIT=NONE] -->
<string name="quick_settings_user_title">User</string>
<!-- QuickSettings: Label on the item for adding a new user [CHAR LIMIT=NONE] -->
- <string name="quick_settings_user_new_user">New user</string>
<!-- QuickSettings: Wifi [CHAR LIMIT=NONE] -->
<string name="quick_settings_wifi_label">Wi-Fi</string>
<!-- QuickSettings: Internet [CHAR LIMIT=NONE] -->
@@ -872,13 +609,9 @@
<!-- QuickSettings: networks unavailable [CHAR LIMIT=NONE] -->
<string name="quick_settings_networks_unavailable">Networks unavailable</string>
<!-- QuickSettings: Wifi (Not connected) [CHAR LIMIT=NONE] -->
- <string name="quick_settings_wifi_not_connected">Not Connected</string>
<!-- QuickSettings: Wifi (No network) [CHAR LIMIT=NONE] -->
- <string name="quick_settings_wifi_no_network">No Network</string>
<!-- QuickSettings: Wifi (Off) [CHAR LIMIT=NONE] -->
- <string name="quick_settings_wifi_off_label">Wi-Fi Off</string>
<!-- QuickSettings: Wifi (On) [CHAR LIMIT=NONE] -->
- <string name="quick_settings_wifi_on_label">Wi-Fi On</string>
<!-- QuickSettings: Wifi detail panel, text when there are no items [CHAR LIMIT=NONE] -->
<string name="quick_settings_wifi_detail_empty_text">No Wi-Fi networks available</string>
<!-- QuickSettings: Wifi secondary label shown when the wifi is being enabled [CHAR LIMIT=NONE] -->
@@ -890,19 +623,15 @@
<!-- QuickSettings: Cast detail panel, default device name [CHAR LIMIT=NONE] -->
<string name="quick_settings_cast_device_default_name">Unnamed device</string>
<!-- QuickSettings: Cast detail panel, default device description [CHAR LIMIT=NONE] -->
- <string name="quick_settings_cast_device_default_description">Ready to cast</string>
<!-- QuickSettings: Cast detail panel, text when there are no items [CHAR LIMIT=NONE] -->
<string name="quick_settings_cast_detail_empty_text">No devices available</string>
<!-- QuickSettings: Cast unavailable, text when not connected to WiFi [CHAR LIMIT=NONE] -->
<string name="quick_settings_cast_no_wifi">Wi\u2011Fi not connected</string>
<!-- QuickSettings: Brightness dialog title [CHAR LIMIT=NONE] -->
<string name="quick_settings_brightness_dialog_title">Brightness</string>
- <!-- QuickSettings: Brightness dialog auto brightness button [CHAR LIMIT=NONE] -->
- <string name="quick_settings_brightness_dialog_auto_brightness_label">AUTO</string>
<!-- QuickSettings: Label for the toggle that controls whether display inversion is enabled. [CHAR LIMIT=NONE] -->
<string name="quick_settings_inversion_label">Invert colors</string>
<!-- QuickSettings: Label for the toggle that controls whether display color correction is enabled. [CHAR LIMIT=NONE] -->
- <string name="quick_settings_color_space_label">Color correction mode</string>
<!-- QuickSettings: Control panel: Label for button that navigates to settings. [CHAR LIMIT=NONE] -->
<string name="quick_settings_more_settings">More settings</string>
<!-- QuickSettings: Control panel: Label for button that navigates to user settings. [CHAR LIMIT=NONE] -->
@@ -918,7 +647,6 @@
<!-- QuickSettings: Control panel: Label for connecting device. [CHAR LIMIT=NONE] -->
<string name="quick_settings_connecting">Connecting...</string>
<!-- QuickSettings: Tethering. [CHAR LIMIT=NONE] -->
- <string name="quick_settings_tethering_label">Tethering</string>
<!-- QuickSettings: Hotspot. [CHAR LIMIT=NONE] -->
<string name="quick_settings_hotspot_label">Hotspot</string>
<!-- QuickSettings: Hotspot. Secondary label shown when the hotspot is being enabled [CHAR LIMIT=NONE] -->
@@ -932,7 +660,6 @@
<item quantity="other">%d devices</item>
</plurals>
<!-- QuickSettings: Notifications [CHAR LIMIT=NONE] -->
- <string name="quick_settings_notifications_label">Notifications</string>
<!-- QuickSettings: Flashlight [CHAR LIMIT=NONE] -->
<string name="quick_settings_flashlight_label">Flashlight</string>
<!-- QuickSettings: Flashlight, used when it's not available due to camera in use [CHAR LIMIT=NONE] -->
@@ -1013,31 +740,6 @@
<!-- QuickStep: Accessibility to toggle overview [CHAR LIMIT=40] -->
<string name="quick_step_accessibility_toggle_overview">Toggle Overview</string>
- <!-- Expanded Status Bar Header: Battery Charged [CHAR LIMIT=40] -->
- <string name="expanded_header_battery_charged">Charged</string>
-
- <!-- Expanded Status Bar Header: Charging, no known time [CHAR LIMIT=40] -->
- <string name="expanded_header_battery_charging">Charging</string>
-
- <!-- Expanded Status Bar Header: Charging, showing time left until charged [CHAR LIMIT=40] -->
- <string name="expanded_header_battery_charging_with_time"><xliff:g id="charging_time" example="2 hrs 25 min">%s</xliff:g> until full</string>
-
- <!-- Expanded Status Bar Header: Not charging [CHAR LIMIT=40] -->
- <string name="expanded_header_battery_not_charging">Not charging</string>
-
- <!-- Shows up when there is a user SSL CA Cert installed on the
- device. Indicates to the user that SSL traffic can be intercepted.
- If the text fits on one line (~14 chars), it should start with a
- linebreak to position it correctly. [CHAR LIMIT=45] -->
- <string name="ssl_ca_cert_warning">Network may\nbe monitored</string>
-
- <!-- Description of the unlock target in the Slide unlock screen. [CHAR LIMIT=NONE] -->
- <string name="description_target_search">Search</string>
- <!-- Description of the up direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] -->
- <string name="description_direction_up">Slide up for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string>
- <!-- Description of the left direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] -->
- <string name="description_direction_left">"Slide left for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string>
-
<!-- Zen mode: Priority only introduction message on first use -->
<string name="zen_priority_introduction">You won\'t be disturbed by sounds and vibrations, except from alarms, reminders, events, and callers you specify. You\'ll still hear anything you choose to play including music, videos, and games.</string>
@@ -1053,12 +755,6 @@
<!-- Zen mode: Total silence introduction message on first use (non-voice capable devices) -->
<string name="zen_silence_introduction">This blocks ALL sounds and vibrations, including from alarms, music, videos, and games.</string>
- <!-- Text for overflow card on Keyguard when there is not enough space for all notifications on Keyguard. [CHAR LIMIT=1] -->
- <string name="keyguard_more_overflow_text">+<xliff:g id="number_of_notifications" example="5">%d</xliff:g></string>
-
- <!-- An explanation for the visual speed bump in the notifications, which will appear when you click on it. [CHAR LIMIT=50] -->
- <string name="speed_bump_explanation">Less urgent notifications below</string>
-
<!-- Shows to explain the double tap interaction with notifications: After tapping a notification on Keyguard, this will explain users to tap again to launch a notification. [CHAR LIMIT=60] -->
<string name="notification_tap_again">Tap again to open</string>
@@ -1134,13 +830,10 @@
<string name="accessibility_multi_user_switch_switcher">Switch user</string>
<!-- Accessibility label for the button that opens the user switcher and announces the current user. -->
- <string name="accessibility_multi_user_switch_switcher_with_current">Switch user, current user <xliff:g id="current_user_name" example="John Doe">%s</xliff:g></string>
<!-- Accessibility label for the user icon on the lock screen. -->
- <string name="accessibility_multi_user_switch_inactive">Current user <xliff:g id="current_user_name" example="John Doe">%s</xliff:g></string>
<!-- Accessibility label for the button that opens the quick contact of the user. -->
- <string name="accessibility_multi_user_switch_quick_contact">Show profile</string>
<!-- Label for the adding a new user in the user switcher [CHAR LIMIT=35] -->
<string name="user_add_user">Add user</string>
@@ -1169,24 +862,6 @@
<!-- Notification when resuming an existing guest session: Action that continues with the current session [CHAR LIMIT=35] -->
<string name="guest_wipe_session_dontwipe">Yes, continue</string>
- <!-- Title of the notification shown to a new guest user [CHAR LIMIT=60] -->
- <string name="guest_notification_title">Guest user</string>
-
- <!-- Text of the notification shown to a new guest user [CHAR LIMIT=60] -->
- <string name="guest_notification_text">To delete apps and data, remove guest user</string>
-
- <!-- Remove action in the notification shown to a new guest user [CHAR LIMIT=30] -->
- <string name="guest_notification_remove_action">REMOVE GUEST</string>
-
- <!-- Title of the notification shown to logout the current user [CHAR LIMIT=60] -->
- <string name="user_logout_notification_title">Logout user</string>
-
- <!-- Text of the notification shown to logout the current user [CHAR LIMIT=60] -->
- <string name="user_logout_notification_text">Logout current user</string>
-
- <!-- Logout action in the notification shown to logout the current user [CHAR LIMIT=30] -->
- <string name="user_logout_notification_action">LOGOUT USER</string>
-
<!-- Title for add user confirmation dialog [CHAR LIMIT=30] -->
<string name="user_add_user_title" msgid="2108112641783146007">Add new user?</string>
@@ -1211,15 +886,6 @@
<!-- Label for button in confirmation dialog when exiting guest session [CHAR LIMIT=35] -->
<string name="user_remove_user_remove">Remove</string>
- <!-- Battery saver notification title. [CHAR LIMIT=60]-->
- <string name="battery_saver_notification_title">Battery Saver is on</string>
-
- <!-- Battery saver notification text. [CHAR LIMIT=60] -->
- <string name="battery_saver_notification_text">Reduces performance and background data</string>
-
- <!-- Battery saver notification action text. [CHAR LIMIT=60] -->
- <string name="battery_saver_notification_action_text">Turn off Battery Saver</string>
-
<!-- Media projection permission dialog warning text. [CHAR LIMIT=NONE] -->
<string name="media_projection_dialog_text"><xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages, and audio that you play.</string>
@@ -1233,7 +899,6 @@
<string name="media_projection_dialog_title">Start recording or casting with <xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g>?</string>
<!-- Media projection permission dialog permanent grant check box. [CHAR LIMIT=NONE] -->
- <string name="media_projection_remember_text">Don\'t show again</string>
<!-- The text to clear all notifications. [CHAR LIMIT=60] -->
<string name="clear_all_notifications_text">Clear all</string>
@@ -1268,15 +933,6 @@
<!-- Text which is shown in the notification shade when there are no notifications. [CHAR LIMIT=30] -->
<string name="empty_shade_text">No notifications</string>
- <!-- Footer profile owned text [CHAR LIMIT=50] -->
- <string name="profile_owned_footer">Profile may be monitored</string>
-
- <!-- Footer vpn present text [CHAR LIMIT=50] -->
- <string name="vpn_footer">Network may be monitored</string>
-
- <!-- Footer vpn present text [CHAR LIMIT=50] -->
- <string name="branded_vpn_footer">Network may be monitored</string>
-
<!-- Disclosure at the bottom of Quick Settings that indicates that parental controls are enabled. [CHAR LIMIT=100] -->
<string name="quick_settings_disclosure_parental_controls">This device is managed by your parent</string>
@@ -1337,12 +993,6 @@
<!-- Monitoring dialog title for device owned devices [CHAR LIMIT=35] -->
<string name="monitoring_title_device_owned">Device management</string>
- <!-- Monitoring dialog title for profile owned devices [CHAR LIMIT=35] -->
- <string name="monitoring_title_profile_owned">Profile monitoring</string>
-
- <!-- Monitoring dialog title for normal devices [CHAR LIMIT=35]-->
- <string name="monitoring_title">Network monitoring</string>
-
<!-- STOPSHIP Monitoring strings still need to be finalized and approved -->
<!-- Monitoring dialog subtitle for the section describing VPN [CHAR LIMIT=35]-->
<string name="monitoring_subtitle_vpn">VPN</string>
@@ -1353,12 +1003,6 @@
<!-- Monitoring dialog subtitle for the section describing certificate authorities [CHAR LIMIT=35]-->
<string name="monitoring_subtitle_ca_certificate">CA certificates</string>
- <!-- Monitoring dialog disable vpn button [CHAR LIMIT=30] -->
- <string name="disable_vpn">Disable VPN</string>
-
- <!-- Monitoring dialog disconnect vpn button [CHAR LIMIT=30] -->
- <string name="disconnect_vpn">Disconnect VPN</string>
-
<!-- Monitoring dialog label for button opening a page with more information on the admin's abilities [CHAR LIMIT=30] -->
<string name="monitoring_button_view_policies">View Policies</string>
@@ -1401,113 +1045,27 @@
<!-- Monitoring dialog: Description of an active VPN in the personal profile (as opposed to the work profile). [CHAR LIMIT=NONE]-->
<string name="monitoring_description_personal_profile_named_vpn">Your personal profile is connected to <xliff:g id="vpn_app" example="Foo VPN App">%1$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites.</string>
- <!-- Monitoring dialog: Header indicating that the device is managed by a Device Owner app [CHAR LIMIT=80] -->
- <string name="monitoring_description_do_header_generic">Your device is managed by <xliff:g id="device_owner_app" example="Google Mobile Management">%1$s</xliff:g>.</string>
-
- <!-- Monitoring dialog: Header indicating that the device is managed by a Device Owner app [CHAR LIMIT=60] -->
- <string name="monitoring_description_do_header_with_name"><xliff:g id="organization_name" example="Foo, Inc.">%1$s</xliff:g> uses <xliff:g id="device_owner_app" example="Google Mobile Management">%2$s</xliff:g> to manage your device.</string>
-
- <!-- Monitoring dialog: Part of text body explaining what a Device Owner app can do [CHAR LIMIT=130] -->
- <string name="monitoring_description_do_body">Your admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.</string>
-
- <!-- Monitoring dialog: Space that separates the body text and the "learn more" link that follows it. [CHAR LIMIT=5] -->
- <string name="monitoring_description_do_learn_more_separator">" "</string>
-
- <!-- Monitoring dialog: Link to learn more about what a Device Owner app can do [CHAR LIMIT=55] -->
- <string name="monitoring_description_do_learn_more">Learn more</string>
-
- <!-- Monitoring dialog: Part of text body explaining that a VPN is connected and what it can do, for devices managed by a Device Owner app [CHAR LIMIT=130] -->
- <string name="monitoring_description_do_body_vpn">You\'re connected to <xliff:g id="vpn_app">%1$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites.</string>
-
<!-- Monitoring dialog: Space that separates the VPN body text and the "Open VPN Settings" link that follows it. [CHAR LIMIT=5] -->
<string name="monitoring_description_vpn_settings_separator">" "</string>
<!-- Monitoring dialog: Link to open the VPN settings page [CHAR LIMIT=60] -->
<string name="monitoring_description_vpn_settings">Open VPN settings</string>
- <!-- Monitoring dialog: Space that separates the CA certs body text and the "Open trusted credentials" link that follows it. [CHAR LIMIT=5] -->
- <string name="monitoring_description_ca_cert_settings_separator">" "</string>
-
- <!-- Monitoring dialog: Link to open the settings page containing CA certificates [CHAR LIMIT=NONE] -->
- <string name="monitoring_description_ca_cert_settings">Open trusted credentials</string>
-
- <!-- Monitoring dialog: Network logging text [CHAR LIMIT=400] -->
- <string name="monitoring_description_network_logging">Your admin has turned on network logging, which monitors traffic on your device.\n\nFor more information, contact your admin.</string>
-
- <!-- Monitoring dialog VPN text [CHAR LIMIT=400] -->
- <string name="monitoring_description_vpn">You gave an app permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps, and websites.</string>
-
- <!-- Monitoring dialog VPN with profile owner text [CHAR LIMIT=400] -->
- <string name="monitoring_description_vpn_profile_owned">Your work profile is managed by <xliff:g id="organization">%1$s</xliff:g>.\n\nYour admin is capable of monitoring your network activity including emails, apps, and websites.\n\nFor more information, contact your admin.\n\nYou\'re also connected to a VPN, which can monitor your network activity.</string>
-
<!-- Dialog that a user can access via Quick Settings. [CHAR LIMIT=NONE]-->
<string name="monitoring_description_parental_controls">This device is managed by your parent. Your parent can see and manage information such as the apps you use, your location, and your screen time.</string>
-
<!-- Name for a generic legacy VPN connection [CHAR LIMIT=20] -->
<string name="legacy_vpn_name">VPN</string>
- <!-- Monitoring dialog text for single app (no profile or device owner) [CHAR LIMIT=400] -->
- <string name="monitoring_description_app">You\'re connected to
- <xliff:g id="application">%1$s</xliff:g>, which can monitor your network activity,
- including emails, apps, and websites.</string>
-
- <!-- Monitoring dialog text for single app (inside personal profile) [CHAR LIMIT=400] -->
- <string name="monitoring_description_app_personal">You\'re connected to <xliff:g id="application">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps, and websites.</string>
-
- <!-- Monitoring dialog text for single app (inside personal profile) [CHAR LIMIT=400] -->
- <string name="branded_monitoring_description_app_personal">You\'re connected to <xliff:g id="application">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps, and websites.</string>
-
- <!-- Monitoring dialog text for single app (inside work profile) [CHAR LIMIT=400] -->
- <string name="monitoring_description_app_work">Your work profile is managed by
- <xliff:g id="organization">%1$s</xliff:g>. The profile is connected to
- <xliff:g id="application">%2$s</xliff:g>, which can monitor your work network activity,
- including emails, apps, and websites.\n\nFor more information, contact your admin.</string>
-
- <!-- Monitoring dialog text for multiple apps (in personal and work profiles) [CHAR LIMIT=400] -->
- <string name="monitoring_description_app_personal_work">Your work profile is managed by
- <xliff:g id="organization">%1$s</xliff:g>. The profile is connected to
- <xliff:g id="application_work">%2$s</xliff:g>, which can monitor your work network activity,
- including emails, apps, and websites.\n\nYou\'re also connected to
- <xliff:g id="application_personal">%3$s</xliff:g>, which can monitor your personal network
- activity.</string>
-
<!-- Indication on the keyguard that appears when a trust agents unlocks the device. [CHAR LIMIT=40] -->
<string name="keyguard_indication_trust_unlocked">Kept unlocked by TrustAgent</string>
- <!-- Indication on the keyguard that appears when the user disables trust agents until the next time they unlock manually. [CHAR LIMIT=NONE] -->
- <string name="keyguard_indication_trust_disabled">Device will stay locked until you manually unlock</string>
-
- <!-- Indication on the keyguard that appears when trust agents unlocks the device and device is plugged in. [CHAR LIMIT=NONE] -->
- <string name="keyguard_indication_trust_unlocked_plugged_in"><xliff:g id="keyguard_indication" example="Kept unlocked by TrustAgent">%1$s</xliff:g>\n<xliff:g id="power_indication" example="Charging Slowly">%2$s</xliff:g></string>
-
- <!-- Title of notification educating the user about enabling notifications on the lockscreen. [CHAR LIMIT=40] -->
- <string name="hidden_notifications_title">Get notifications faster</string>
-
- <!-- Body of notification educating the user about enabling notifications on the lockscreen. [CHAR LIMIT=60] -->
- <string name="hidden_notifications_text">See them before you unlock</string>
-
- <!-- Cancel action for notification educating the user about enabling notifications on the lockscreen. [CHAR LIMIT=20] -->
- <string name="hidden_notifications_cancel">No thanks</string>
-
- <!-- continue action for notification educating the user about enabling notifications on the lockscreen. [CHAR LIMIT=20] -->
- <string name="hidden_notifications_setup">Set up</string>
-
<!-- Accessibility string for current zen mode and selected exit condition. A template that simply concatenates existing mode string and the current condition description. [CHAR LIMIT=20] -->
<string name="zen_mode_and_condition"><xliff:g id="zen_mode" example="Priority interruptions only">%1$s</xliff:g>. <xliff:g id="exit_condition" example="For one hour">%2$s</xliff:g></string>
- <!-- Button label for ending zen mode in the volume dialog -->
- <string name="volume_zen_end_now">Turn off now</string>
-
<!-- Content description for accessibility (not shown on the screen): volume dialog settings button. [CHAR LIMIT=NONE] -->
<string name="accessibility_volume_settings">Sound settings</string>
- <!-- Content description for accessibility (not shown on the screen): volume dialog expand button. [CHAR LIMIT=NONE] -->
- <string name="accessibility_volume_expand">Expand</string>
-
- <!-- Content description for accessibility (not shown on the screen): volume dialog collapse button. [CHAR LIMIT=NONE] -->
- <string name="accessibility_volume_collapse">Collapse</string>
-
<!-- Label for the odi caption initial tool tip. [CHAR LIMIT=28] -->
<string name="volume_odi_captions_tip">Automatically caption media</string>
@@ -1523,7 +1081,6 @@
<string name="volume_odi_captions_hint_disable">disable</string>
<!-- content description for audio output chooser [CHAR LIMIT=NONE]-->
- <string name="accessibility_output_chooser">Switch output device</string>
<!-- Screen pinning dialog title. -->
<string name="screen_pinning_title">App is pinned</string>
@@ -1555,13 +1112,10 @@
<!-- Hide quick settings tile confirmation title -->
- <string name="quick_settings_reset_confirmation_title">Hide <xliff:g id="tile_label" example="Hotspot">%1$s</xliff:g>?</string>
<!-- Hide quick settings tile confirmation message -->
- <string name="quick_settings_reset_confirmation_message">It will reappear the next time you turn it on in settings.</string>
<!-- Hide quick settings tile confirmation button -->
- <string name="quick_settings_reset_confirmation_button">Hide</string>
<!-- volume stream names. All nouns. -->
<string name="stream_voice_call">Call</string> <!-- STREAM_VOICE_CALL -->
@@ -1576,22 +1130,12 @@
<string name="stream_tts" translatable="false">Transmitted Through Speaker</string> <!-- STREAM_TTS -->
<string name="stream_accessibility">Accessibility</string> <!-- STREAM_ACCESSIBILITY -->
- <string name="ring_toggle_title">Calls</string>
<string name="volume_ringer_status_normal">Ring</string>
<string name="volume_ringer_status_vibrate">Vibrate</string>
<string name="volume_ringer_status_silent">Mute</string>
<!-- Shown in the header of quick settings to indicate to the user that their phone ringer is on vibrate. [CHAR_LIMIT=NONE] -->
- <string name="qs_status_phone_vibrate">Phone on vibrate</string>
<!-- Shown in the header of quick settings to indicate to the user that their phone ringer is on silent (muted). [CHAR_LIMIT=NONE] -->
- <string name="qs_status_phone_muted">Phone muted</string>
-
- <string name="volume_stream_muted" translatable="false">%s silent</string>
- <string name="volume_stream_vibrate" translatable="false">%s vibrate</string>
- <string name="volume_stream_suppressed" translatable="false">%1$s silent — %2$s</string>
- <string name="volume_stream_muted_dnd" translatable="false">%s silent — Total silence</string>
- <string name="volume_stream_limited_dnd" translatable="false">%s — Priority only</string>
- <string name="volume_stream_vibrate_dnd" translatable="false">%s vibrate — Priority only</string>
<string name="volume_stream_content_description_unmute">%1$s. Tap to unmute.</string>
<string name="volume_stream_content_description_vibrate">%1$s. Tap to set to vibrate. Accessibility services may be muted.</string>
@@ -1612,32 +1156,12 @@
<string name="volume_dialog_ringer_guidance_ring">Calls and notifications will ring (<xliff:g id="volume level" example="56">%1$s</xliff:g>)</string>
- <string name="output_title">Media output</string>
- <string name="output_calls_title">Phone call output</string>
- <string name="output_none_found">No devices found</string>
- <string name="output_none_found_service_off">No devices found. Try turning on <xliff:g id="service" example="Bluetooth">%1$s</xliff:g></string>
- <string name="output_service_bt">Bluetooth</string>
- <string name="output_service_wifi">Wi-Fi</string>
- <string name="output_service_bt_wifi">Bluetooth and Wi-Fi</string>
-
<!-- Name of special SystemUI debug settings -->
<string name="system_ui_tuner">System UI Tuner</string>
- <!-- Preference to show/hide embedded battery percentage [CHAR LIMIT=50] -->
- <string name="show_battery_percentage">Show embedded battery percentage</string>
-
- <!-- Summary for battery percentage preference [CHAR LIMIT=NONE] -->
- <string name="show_battery_percentage_summary">Show battery level percentage inside the status bar icon when not charging</string>
-
- <!-- Name of quick settings -->
- <string name="quick_settings">Quick Settings</string>
-
<!-- Name of status bar -->
<string name="status_bar">Status bar</string>
- <!-- Name of overview -->
- <string name="overview">Overview</string>
-
<!-- Name of System UI demo mode (mode with preset icons for screenshots) -->
<string name="demo_mode">System UI demo mode</string>
@@ -1661,7 +1185,6 @@
<!-- Label of the button at the bottom prompting user enter wallet app. [CHAR LIMIT=NONE] -->
<string name="wallet_app_button_label">Show all</string>
<!-- Label of the button underneath the card carousel prompting user unlock device. [CHAR LIMIT=NONE] -->
- <string name="wallet_action_button_label_unlock">Unlock to pay</string>
<!-- Secondary label of the quick access wallet tile if no card. [CHAR LIMIT=NONE] -->
<string name="wallet_secondary_label_no_card">Add a card</string>
<!-- Secondary label of the quick access wallet tile if wallet is still updating. [CHAR LIMIT=NONE] -->
@@ -1680,15 +1203,10 @@
<string name="status_bar_airplane">Airplane mode</string>
<!-- Description for adding a quick settings tile -->
- <string name="add_tile">Add tile</string>
<!-- Name of a quick settings tile controlled by broadcast -->
- <string name="broadcast_tile">Broadcast Tile</string>
<!-- For preview release. DO NOT TRANSLATE -->
- <string name="regrettable_lack_of_easter_egg">
- ¯\\_(ツ)_/¯
- </string>
<!-- Warning text when an alarm might be silenced by Do Not Disturb [CHAR LIMIT=NONE] -->
<string name="zen_alarm_warning_indef">You won\'t hear your next alarm <xliff:g id="when" example="at 7:00 AM">%1$s</xliff:g> unless you turn this off before then</string>
@@ -1732,29 +1250,7 @@
<!-- Dialog asking if the tuner should really be removed from settings [CHAR LIMIT=NONE]-->
<string name="remove_from_settings_prompt">Remove System UI Tuner from Settings and stop using all of its features?"</string>
- <!-- Displayed when user launches an app that was uninstalled [CHAR LIMIT=NONE] -->
- <string name="activity_not_found">Application is not installed on your device</string>
-
- <!-- Name of setting to show clock seconds [CHAR LIMIT=40] -->
- <string name="clock_seconds">Show clock seconds</string>
- <!-- Description of setting to show clock seconds [CHAR LIMIT=NONE] -->
- <string name="clock_seconds_desc">Show clock seconds in the status bar. May impact battery life.</string>
-
- <!-- Button that leads to page to rearrange quick settings tiles [CHAR LIMIT=60] -->
- <string name="qs_rearrange">Rearrange Quick Settings</string>
- <!-- Option to show brightness bar in quick settings [CHAR LIMIT=60] -->
- <string name="show_brightness">Show brightness in Quick Settings</string>
- <!-- Option to use new paging layout in quick settings [CHAR LIMIT=60] -->
- <string name="qs_paging" translatable="false">Use the new Quick Settings</string>
-
- <!-- Category in the System UI Tuner settings, where new/experimental
- settings are -->
- <string name="experimental">Experimental</string>
-
- <string name="qs_customize" translatable="false">Allow long-press customize in Quick Settings</string>
- <string name="qs_customize_info" translatable="false">Info</string>
<string name="qs_customize_remove" translatable="false">Remove</string>
- <string name="no_tiles_add" translatable="false">No tiles to add</string>
<!-- Dialog title asking if Bluetooth should be enabled [CHAR LIMIT=NONE] -->
<string name="enable_bluetooth_title">Turn on Bluetooth?</string>
@@ -1766,19 +1262,8 @@
<!-- Bluetooth enablement ok text [CHAR LIMIT=40] -->
<string name="enable_bluetooth_confirmation_ok">Turn on</string>
- <!-- [CHAR LIMIT=100] Notification importance option -->
- <string name="show_silently">Show notifications silently</string>
- <!-- [CHAR LIMIT=100] Notification importance option -->
- <string name="block">Block all notifications</string>
- <!-- [CHAR LIMIT=100] Notification importance option -->
- <string name="do_not_silence">Don\'t silence</string>
- <!-- [CHAR LIMIT=100] Notification importance option -->
- <string name="do_not_silence_block">Don\'t silence or block</string>
-
<!-- [CHAR LIMIT=NONE] Importance Tuner setting title -->
<string name="tuner_full_importance_settings">Power notification controls</string>
- <string name="tuner_full_importance_settings_on">On</string>
- <string name="tuner_full_importance_settings_off">Off</string>
<string name="power_notification_controls_description">With power notification controls, you can set an importance level from 0 to 5 for an app\'s notifications.
\n\n<b>Level 5</b>
\n- Show at the top of the notification list
@@ -1804,67 +1289,15 @@
\n- Block all notifications from the app
</string>
- <!-- Notification Inline Controls: Header for apps that are not yet using notification channels. -->
- <string name="notification_header_default_channel">Notifications</string>
-
- <!-- Notification Inline Controls: Shown when a channel's notifications are currently blocked -->
- <string name="notification_channel_disabled">You won\'t see these notifications anymore</string>
-
- <!-- Notification inline controls: Shown when a channel's notifications are minimized -->
- <string name="notification_channel_minimized">These notifications will be minimized</string>
-
- <!-- Notification inline controls: Shown when a channel's notifications are silenced [CHAR_LIMIT=100] -->
- <string name="notification_channel_silenced">These notifications will be shown silently</string>
-
- <!-- Notification inline controls: Shown when a channel's notifications are set to alert [CHAR_LIMIT=100] -->
- <string name="notification_channel_unsilenced">These notifications will alert you</string>
-
- <!-- Notification Inline controls: continue receiving notifications prompt, channel level -->
- <string name="inline_blocking_helper">You usually dismiss these notifications.
- \nKeep showing them?</string>
-
<!-- Notification Inline controls: button to dismiss the blocking helper [CHAR_LIMIT=20] -->
<string name="inline_done_button">Done</string>
<!-- Notification Inline controls: button to dismiss the blocking helper [CHAR_LIMIT=20] -->
<string name="inline_ok_button">Apply</string>
- <!-- Notification Inline controls: continue receiving notifications prompt, channel level -->
- <string name="inline_keep_showing">Keep showing these notifications?</string>
-
- <!-- Notification inline controls: block notifications button [CHAR_LIMIT=25] -->
- <string name="inline_stop_button">Stop notifications</string>
-
- <!-- Notification inline controls: button to deliver notifications silently from this channel [CHAR_LIMIT=30] -->
- <string name="inline_deliver_silently_button">Deliver Silently</string>
-
- <!-- Notification inline controls: button to block notifications from this channel [CHAR_LIMIT=20] -->
- <string name="inline_block_button">Block</string>
-
- <!-- Notification inline controls: keep getting notifications button [CHAR_LIMIT=25] -->
- <string name="inline_keep_button">Keep showing</string>
-
- <!-- Notification inline controls: minimize notifications button [CHAR_LIMIT=20] -->
- <string name="inline_minimize_button">Minimize</string>
-
- <!-- Notification inline controls: button to show notifications silently, without alerting the user [CHAR_LIMIT=35] -->
- <string name="inline_silent_button_silent">Silent</string>
-
- <!-- Notification inline controls: button to continue showing notifications silently [CHAR_LIMIT=35] -->
- <string name="inline_silent_button_stay_silent">Stay silent</string>
-
- <!-- Notification inline controls: button to make notifications alert the user [CHAR_LIMIT=35] -->
- <string name="inline_silent_button_alert">Alerting</string>
-
- <!-- Notification inline controls: button to continue alerting the user when notifications arrive [CHAR_LIMIT=35] -->
- <string name="inline_silent_button_keep_alerting">Keep alerting</string>
-
<!-- Notification inline controls: button to show block screen [CHAR_LIMIT=35] -->
<string name="inline_turn_off_notifications">Turn off notifications</string>
- <!-- Notification Inline controls: continue receiving notifications prompt, app level -->
- <string name="inline_keep_showing_app">Keep showing notifications from this app?</string>
-
<!-- [CHAR LIMIT=100] Notification Importance title -->
<string name="notification_silence_title">Silent</string>
@@ -1886,9 +1319,6 @@
<!-- [CHAR LIMIT=150] Conversation Notification Importance title: normal conversation level, with bubbling summary -->
<string name="notification_channel_summary_default_with_bubbles">May ring or vibrate based on phone settings. Conversations from <xliff:g id="app_name" example="YouTube">%1$s</xliff:g> bubble by default.</string>
- <!-- [CHAR LIMIT=150] Notification Importance title: bubble level summary -->
- <string name="notification_channel_summary_bubble">Keeps your attention with a floating shortcut to this content.</string>
-
<!-- [CHAR LIMIT=150] Notification Importance title: automatic importance level summary -->
<string name="notification_channel_summary_automatic">Have the system determine if this notification should make sound or vibration</string>
@@ -1910,9 +1340,6 @@
<string name="notification_channel_summary_priority_dnd">Shows at the top of conversation notifications and as a profile picture on lock screen, interrupts Do Not Disturb</string>
<string name="notification_channel_summary_priority_all">Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb</string>
- <!--[CHAR LIMIT=30] Linkable text to Settings app -->
- <string name="notification_conversation_channel_settings">Settings</string>
-
<!-- [CHAR LIMIT=150] Notification Importance title: important conversation level -->
<string name="notification_priority_title">Priority</string>
@@ -1935,22 +1362,12 @@
<string name="see_more_title">See more</string>
<!-- Notification Inline controls: describes what the app is doing in the background [CHAR_LIMIT=NONE] -->
- <string name="appops_camera">This app is using the camera.</string>
<!-- Notification Inline controls: describes what the app is doing in the background [CHAR_LIMIT=NONE] -->
- <string name="appops_microphone">This app is using the microphone.</string>
<!-- Notification Inline controls: describes what the app is doing in the background [CHAR_LIMIT=NONE] -->
- <string name="appops_overlay">This app is displaying over other apps on your screen.</string>
<!-- Notification Inline controls: describes what the app is doing in the background [CHAR_LIMIT=NONE] -->
- <string name="appops_camera_mic">This app is using the microphone and camera.</string>
<!-- Notification Inline controls: describes what the app is doing in the background [CHAR_LIMIT=NONE] -->
- <string name="appops_camera_overlay">This app is displaying over other apps on your screen and using the camera.</string>
<!-- Notification Inline controls: describes what the app is doing in the background [CHAR_LIMIT=NONE] -->
- <string name="appops_mic_overlay">This app is displaying over other apps on your screen and using the microphone.</string>
<!-- Notification Inline controls: describes what the app is doing in the background [CHAR_LIMIT=NONE] -->
- <string name="appops_camera_mic_overlay">This app is displaying over other apps on your screen and using the microphone and camera.</string>
-
- <string name="notification_appops_settings">Settings</string>
- <string name="notification_appops_ok">OK</string>
<!-- Notification Inline controls: describes how the notification was adjusted [CHAR_LIMIT=NONE] -->
<string name="feedback_alerted">This notification was automatically &lt;b>promoted to Default&lt;/b> by the system.</string>
@@ -1963,8 +1380,6 @@
<!-- Notification Inline controls: prompts the user for feedback [CHAR_LIMIT=NONE] -->
<string name="feedback_prompt">Let the developer know your feedback. Was this correct?</string>
<!-- Notification Inline controls: responds to user provided feedback [CHAR_LIMIT=NONE] -->
- <string name="feedback_response">Thanks for your feedback!</string>
- <string name="feedback_ok">OK</string>
<!-- Notification: Control panel: Accessibility description for expanded inline controls view, used
to control settings about notifications related to the current notification. -->
@@ -1974,31 +1389,12 @@
<string name="notification_channel_controls_closed_accessibility">Notification controls for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g> closed</string>
<!-- Notification: Control panel: Accessibility description for switch that is used to enable
or disable notifications from this channel -->
- <string name="notification_channel_switch_accessibility">Allow notifications from this channel</string>
<!-- Notification: Control panel: Label for button that launches notification settings. Used
when this app has only defined a single channel for notifications. -->
<string name="notification_more_settings">More settings</string>
<!-- Notification: Control panel: Label for a link that launches notification settings in the
app that sent the notification. -->
<string name="notification_app_settings">Customize</string>
- <!-- Notification: Control panel: Label for button that dismisses control panel. [CHAR LIMIT=NONE] -->
- <string name="notification_done">Done</string>
- <!-- Notification: inline controls: undo block button -->
- <string name="inline_undo">Undo</string>
- <!-- Notification: Conversation: control panel, label for button that demotes notification from conversation to normal notification -->
- <string name="demote">Mark this notification as not a conversation</string>
-
- <!-- [CHAR LIMIT=100] This conversation is marked as important -->
- <string name="notification_conversation_favorite">Important conversation</string>
-
- <!-- [CHAR LIMIT=100] This conversation is not marked as important -->
- <string name="notification_conversation_unfavorite">Not an important conversation</string>
-
- <!-- [CHAR LIMIT=100] This conversation is silenced (will not make sound or vibrate)-->
- <string name="notification_conversation_mute">Silenced</string>
-
- <!-- [CHAR LIMIT=100] This conversation is alerting (may make sound and/or vibrate)-->
- <string name="notification_conversation_unmute">Alerting</string>
<!-- [CHAR LIMIT=100] Show notification as bubble -->
<string name="notification_conversation_bubble">Show bubble</string>
@@ -2006,9 +1402,6 @@
<!-- [CHAR LIMIT=100] Turn off bubbles for notification -->
<string name="notification_conversation_unbubble">Remove bubbles</string>
- <!-- [CHAR LIMIT=100] Add this conversation to home screen -->
- <string name="notification_conversation_home_screen">Add to home screen</string>
-
<!-- Notification: Menu row: Content description for menu items. [CHAR LIMIT=NONE] -->
<string name="notification_menu_accessibility"><xliff:g id="app_name" example="YouTube">%1$s</xliff:g> <xliff:g id="menu_description" example="notification controls">%2$s</xliff:g></string>
@@ -2021,9 +1414,6 @@
<!-- Notification: Menu row: Label for the snooze action shown in local context menu. [CHAR LIMIT=NONE] -->
<string name="notification_menu_snooze_action">Remind me</string>
- <!-- Notification: Menu row: Label for the snooze action shown in local context menu. [CHAR LIMIT=NONE] -->
- <string name="notification_menu_settings_action">Settings</string>
-
<!-- Notification: Snooze panel: Snooze undo button label. [CHAR LIMIT=50]-->
<string name="snooze_undo">Undo</string>
@@ -2045,17 +1435,12 @@
<item quantity="other">%d minutes</item>
</plurals>
- <!-- Title of the battery settings detail panel [CHAR LIMIT=20] -->
- <string name="battery_panel_title">Battery usage</string>
-
<!-- Summary of battery saver not available [CHAR LIMIT=NONE] -->
- <string name="battery_detail_charging_summary">Battery Saver not available during charging</string>
<!-- Title of switch for battery saver [CHAR LIMIT=NONE] -->
<string name="battery_detail_switch_title">Battery Saver</string>
<!-- Summary of switch for battery saver [CHAR LIMIT=NONE] -->
- <string name="battery_detail_switch_summary">Reduces performance and background data</string>
<!-- Name used for certain Keyboard keys on gamepads, e.g. "Button L1". -->
<string name="keyboard_key_button_template">Button <xliff:g id="name">%1$s</xliff:g></string>
@@ -2141,13 +1526,9 @@
<!-- User visible title for the keyboard shortcut that takes the user to the music app. -->
<string name="keyboard_shortcut_group_applications_music">Music</string>
<!-- User visible title for the keyboard shortcut that takes the user to the YouTube app. -->
- <string name="keyboard_shortcut_group_applications_youtube">YouTube</string>
<!-- User visible title for the keyboard shortcut that takes the user to the calendar app. -->
<string name="keyboard_shortcut_group_applications_calendar">Calendar</string>
- <!-- SysUI Tuner: Option to show full do not disturb panel in volume [CHAR LIMIT=60] -->
- <string name="tuner_full_zen_title">Show with volume controls</string>
-
<!-- SysUI Tuner: Label for screen about do not disturb settings [CHAR LIMIT=60] -->
<string name="volume_and_do_not_disturb">Do Not Disturb</string>
@@ -2155,15 +1536,9 @@
not disturb [CHAR LIMIT=60] -->
<string name="volume_dnd_silent">Volume buttons shortcut</string>
- <!-- SysUI Tuner: Switch to control volume up behavior [CHAR LIMIT=60] -->
- <string name="volume_up_silent">Exit Do Not Disturb on volume up</string>
-
<!-- Name of the battery icon in status bar [CHAR LIMIT=30] -->
<string name="battery">Battery</string>
- <!-- Name of the clock in status bar [CHAR LIMIT=30] -->
- <string name="clock">Clock</string>
-
<!-- Name of the headset in status bar [CHAR LIMIT=30] -->
<string name="headset">Headset</string>
@@ -2184,7 +1559,6 @@
<string name="accessibility_data_saver_on">Data Saver is on</string>
<!-- Accessibility description for data saver being off [CHAR LIMIT=NONE] -->
- <string name="accessibility_data_saver_off">Data Saver is off</string>
<!-- Label for feature switch [CHAR LIMIT=30] -->
<string name="switch_bar_on">On</string>
@@ -2213,10 +1587,6 @@
<!-- SysUI Tuner: Setting for button type in nav bar [CHAR LIMIT=60] -->
<string name="right_nav_bar_button_type">Extra right button type</string>
-
- <!-- SysUI Tuner: Added to nav bar option to indicate it is the default [CHAR LIMIT=60] -->
- <string name="nav_bar_default"> (default)</string>
-
<!-- SysUI Tuner: Labels for different types of navigation bar buttons [CHAR LIMIT=60] -->
<string-array name="nav_bar_buttons">
<item>Clipboard</item>
@@ -2246,16 +1616,11 @@
<item>space;space;left,back,home,recent,right</item>
</string-array>
- <!-- SysUI Tuner: Name of Combination Menu / Keyboard Switcher button [CHAR LIMIT=30] -->
- <string name="menu_ime">Keyboard switcher</string>
<!-- SysUI Tuner: Save the current settings [CHAR LIMIT=30] -->
<string name="save">Save</string>
<!-- SysUI Tuner: Reset to default settings [CHAR LIMIT=30] -->
<string name="reset">Reset</string>
- <!-- SysUI Tuner: Adjust button width dialog title [CHAR LIMIT=60] -->
- <string name="adjust_button_width">Adjust button width</string>
-
<!-- SysUI Tuner: Nav bar button that holds the clipboard [CHAR LIMIT=30] -->
<string name="clipboard">Clipboard</string>
@@ -2358,7 +1723,6 @@
<string name="accessibility_quick_settings_collapse">Close quick settings.</string>
<!-- accessibility label for alarm icon [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_alarm_set">Alarm set.</string>
<!-- accessibility label for button to select user [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_user">Signed in as <xliff:g name="user" example="John">%s</xliff:g></string>
@@ -2373,7 +1737,6 @@
<string name="accessibility_quick_settings_open_details">Open details.</string>
<!-- accessibility label for quick settings items that are currently disabled. Must have a reason [CHAR LIMIT=NONE] -->
- <string name="accessibility_quick_settings_not_available">Unvailable due to <xliff:g name="reason" id="reason" example="Wifi not available">%s</xliff:g></string>
<!-- accessibility label for quick settings items that open a details page [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_open_settings">Open <xliff:g name="page" example="Bluetooth">%s</xliff:g> settings.</string>
@@ -2403,11 +1766,8 @@
<string name="tuner_lock_screen">Lock screen</string>
<!-- Tuner string -->
- <string name="change_theme_reboot" translatable="false">Changing the theme requires a restart.</string>
<!-- Tuner string -->
- <string name="theme" translatable="false">Theme</string>
<!-- Tuner string -->
- <string name="default_theme" translatable="false">Default</string>
<!-- Title for notification & dialog that the user's phone last shut down because it got too hot. [CHAR LIMIT=40] -->
<string name="thermal_shutdown_title">Phone turned off due to heat</string>
@@ -2543,15 +1903,6 @@
<!-- Prompt for when Do not disturb is on from automatic rule or app in QS [CHAR LIMIT=NONE] -->
<string name="qs_dnd_prompt_auto_rule_app">Do Not Disturb was turned on by an automatic rule or app.</string>
- <!-- Description of Do Not Disturb option in QS that ends at the specified time[CHAR LIMIT=20] -->
- <string name="qs_dnd_until">Until <xliff:g name="time">%s</xliff:g></string>
-
- <!-- Do Not Disturb button to keep the current settings [CHAR LIMIT=20] -->
- <string name="qs_dnd_keep">Keep</string>
-
- <!-- Do Not Disturb button to change the current settings [CHAR LIMIT=20] -->
- <string name="qs_dnd_replace">Replace</string>
-
<!-- Title of the "running foreground services" dialog. [CHAR LIMIT=NONE] -->
<string name="running_foreground_services_title">Apps running in background</string>
@@ -2593,8 +1944,6 @@
<string name="slice_permission_deny">Deny</string>
<!-- List of packages for which we don't want to show recents onboarding, add into overlay as needed. -->
- <string-array name="recents_onboarding_blacklisted_packages" translatable="false">
- </string-array>
<!-- The title of the notification to suggest enabling automatic battery saver. [CHAR LIMIT=NONE]-->
<string name="auto_saver_title">Tap to schedule Battery Saver</string>
@@ -2606,16 +1955,12 @@
<string name="no_auto_saver_action">No thanks</string>
<!-- The title of the dialog that tells that scheduled (i.e. automatic) battery saver has been turned on. [CHAR LIMIT=NONE]-->
- <string name="auto_saver_enabled_title">Battery Saver schedule turned on</string>
<!-- The content of the dialog that tells that scheduled (i.e. automatic) battery saver has been turned on. [CHAR LIMIT=NONE]-->
- <string name="auto_saver_enabled_text">Battery Saver will turn on automatically once battery goes below <xliff:g id="percentage">%d</xliff:g>%%.</string>
<!-- An action on the dialog that tells that scheduled (i.e. automatic) battery saver: open the battery saver setting. [CHAR LIMIT=NONE]-->
- <string name="open_saver_setting_action">Settings</string>
<!-- An action on the dialog that tells that scheduled (i.e. automatic) battery saver: user acknowledges and closes the dialog. [CHAR LIMIT=NONE]-->
- <string name="auto_saver_okay_action">Got it</string>
<!-- URl of the webpage that explains battery saver. -->
<string name="help_uri_battery_saver_learn_more_link_target" translatable="false"></string>
@@ -2625,7 +1970,6 @@
<string name="heap_dump_tile_name">Dump SysUI Heap</string>
<!-- Content description for ongoing privacy chip. Use with a single app [CHAR LIMIT=NONE]-->
- <string name="ongoing_privacy_chip_content_single_app"><xliff:g id="app" example="Example App">%1$s</xliff:g> is using your <xliff:g id="types_list" example="camera, location">%2$s</xliff:g>.</string>
<!-- Content description for ongoing privacy chip. Use with multiple apps [CHAR LIMIT=NONE]-->
<string name="ongoing_privacy_chip_content_multiple_apps">Applications are using your <xliff:g id="types_list" example="camera, location">%s</xliff:g>.</string>
@@ -2660,24 +2004,9 @@
<!-- Text for microphone app op [CHAR LIMIT=20]-->
<string name="privacy_type_microphone">microphone</string>
- <!-- Text for the quick setting tile for sensor privacy [CHAR LIMIT=30] -->
- <string name="sensor_privacy_mode">Sensors off</string>
-
- <!-- Name for device services grouping system uid apps in Ongoing Privacy Dialog [CHAR_LIMIT=NONE] -->
- <string name="device_services">Device Services</string>
-
<!-- What to show on the ambient display player when song doesn't have a title. [CHAR LIMIT=20] -->
<string name="music_controls_no_title">No title</string>
- <!-- Action in accessibility menu to move the stack of bubbles [CHAR LIMIT=20] -->
- <string name="bubble_accessibility_action_move">Move</string>
-
- <!-- Notification content text when the system navigation mode changes as a result of changing the default launcher [CHAR LIMIT=NONE] -->
- <string name="notification_content_system_nav_changed">System navigation updated. To make changes, go to Settings.</string>
-
- <!-- Notification content text when switching to a default launcher that supports gesture navigation [CHAR LIMIT=NONE] -->
- <string name="notification_content_gesture_nav_available">Go to Settings to update system navigation</string>
-
<!-- Title of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=25] -->
<string name="inattentive_sleep_warning_title">Standby</string>
@@ -2710,8 +2039,6 @@
<!-- Accessibility floating menu strings -->
<!-- Message for the accessibility floating button migration tooltip. It shows when the user use gestural navigation then upgrade their system. It will tell the user the accessibility gesture had been replaced by accessibility floating button. [CHAR LIMIT=100] -->
<string name="accessibility_floating_button_migration_tooltip">Accessibility button replaced the accessibility gesture\n\n<annotation id="link">View settings</annotation></string>
- <!-- Message for the accessibility floating button settings tooltip. It shows when the user use gestural navigation then upgrade their system. It will tell the user to have another option to switch from the accessibility gesture to a button. [CHAR LIMIT=100] -->
- <string name="accessibility_floating_button_switch_migration_tooltip">You can switch from the accessibility gesture to a button\n\n<annotation id="link">Settings</annotation></string>
<!-- Message for the accessibility floating button docking tooltip. It shows when the user first time drag the button. It will tell the user about docking behavior. [CHAR LIMIT=70] -->
<string name="accessibility_floating_button_docking_tooltip">Move button to the edge to hide it temporarily</string>
<!-- Action in accessibility menu to move the accessibility floating button to the top left of the screen. [CHAR LIMIT=30] -->
@@ -2786,9 +2113,6 @@
<string name="controls_dialog_ok">Add</string>
<!-- Controls dialog message. Indicates app that suggested this control [CHAR LIMIT=NONE] -->
<string name="controls_dialog_message">Suggested by <xliff:g id="app" example="System UI">%s</xliff:g></string>
- <!-- Controls dialog confirmation [CHAR LIMIT=30] -->
- <string name="controls_dialog_confirmation">Controls updated</string>
-
<!-- Controls tile secondary label when device is locked and user does not want access to controls from lockscreen [CHAR LIMIT=20] -->
<string name="controls_tile_locked">Device locked</string>
@@ -2798,14 +2122,10 @@
<string name="controls_pin_verify">Verify <xliff:g id="device" example="Backdoor lock">%s</xliff:g></string>
<!-- Controls PIN entry dialog, title when 1st attempt failed [CHAR LIMIT=30] -->
<string name="controls_pin_wrong">Wrong PIN</string>
- <!-- Controls PIN entry dialog, waiting to verify [CHAR LIMIT=30] -->
- <string name="controls_pin_verifying">Verifying\u2026</string>
<!-- Controls PIN entry dialog, text hint [CHAR LIMIT=30] -->
<string name="controls_pin_instructions">Enter PIN</string>
<!-- Controls PIN entry dialog, text hint, retry [CHAR LIMIT=30] -->
<string name="controls_pin_instructions_retry">Try another PIN</string>
- <!-- Controls confirmation dialog, waiting to confirm [CHAR LIMIT=30] -->
- <string name="controls_confirmation_confirming">Confirming\u2026</string>
<!-- Controls confirmation dialog, user prompt [CHAR LIMIT=NONE] -->
<string name="controls_confirmation_message">Confirm change for <xliff:g id="device" example="Backdoor lock">%s</xliff:g></string>
@@ -2844,9 +2164,6 @@
<!-- Error message indicating that a control timed out while waiting for an update [CHAR_LIMIT=30] -->
<string name="controls_error_timeout">Inactive, check app</string>
- <!-- Error message indicating that an unspecified error occurred while getting the status, and
- a retry will be attempted [CHAR LIMIT=30] -->
- <string name="controls_error_retryable">Error, retrying\u2026</string>
<!-- Error message indicating that the control is no longer available in the application [CHAR LIMIT=30] -->
<string name="controls_error_removed">Not found</string>
<!-- Title for dialog indicating that the control is no longer available in the application [CHAR LIMIT=30] -->
@@ -2859,11 +2176,6 @@
<string name="controls_error_generic">Can\u2019t load status</string>
<!-- Error message indicating that a control action failed [CHAR_LIMIT=30] -->
<string name="controls_error_failed">Error, try again</string>
- <!-- Stateless control message informing the user that a routine has started [CHAR_LIMIT=30] -->
- <string name="controls_in_progress">In progress</string>
- <!-- Tooltip informing user where the recently added controls are [CHAR_LIMIT=100] -->
- <string name="controls_added_tooltip">Open Quick Settings to see new controls</string>
-
<!-- Controls menu, add [CHAR_LIMIT=30] -->
<string name="controls_menu_add">Add controls</string>
<!-- Controls menu, edit [CHAR_LIMIT=30] -->
@@ -2878,7 +2190,7 @@
<!-- Summary for media output group with the active device count [CHAR LIMIT=NONE] -->
<string name="media_output_dialog_multiple_devices"><xliff:g id="count" example="2">%1$d</xliff:g> devices selected</string>
<!-- Summary for disconnected status [CHAR LIMIT=50] -->
- <string name="media_output_dialog_disconnected"><xliff:g id="device_name" example="My device">%1$s</xliff:g> (disconnected)</string>
+ <string name="media_output_dialog_disconnected">(disconnected)</string>
<!-- Summary for connecting error message [CHAR LIMIT=NONE] -->
<string name="media_output_dialog_connect_failed">Couldn\'t connect. Try again.</string>
<!-- Title for pairing item [CHAR LIMIT=60] -->
@@ -2901,8 +2213,6 @@
<string name="priority_conversations">Priority conversations</string>
<!--Text header for recent conversation tiles available to be added to the home screen [CHAR LIMIT=100] -->
<string name="recent_conversations">Recent conversations</string>
- <!-- Text for button dismissing configuration activity with no conversations [CHAR LIMIT=20] -->
- <string name="okay">Okay</string>
<!-- Timestamp for notification with exact time in days plural [CHAR LIMIT=25] -->
<string name="days_timestamp"><xliff:g id="duration" example="5">%1$s</xliff:g> days ago</string>
<!-- Timestamp for notification from one week ago[CHAR LIMIT=25] -->
@@ -2976,8 +2286,6 @@
<!-- Accessibility label for fingerprint sensor [CHAR LIMIT=NONE] -->
<string name="accessibility_fingerprint_label">Fingerprint sensor</string>
- <!-- Accessibility label for disabled udfps sensor [CHAR LIMIT=NONE] -->
- <string name="accessibility_udfps_disabled_button">Fingerprint sensor disabled</string>
<!-- Accessibility action for tapping on an affordance that will bring up the user's
pin/pattern/password bouncer (ie: "Double tap to authenticate") [CHAR LIMIT=NONE] -->
<string name="accessibility_authenticate_hint">authenticate</string>
@@ -3012,8 +2320,6 @@
<string name="all_network_unavailable">No networks available</string>
<!-- Provider Model: Panel title text for turning on the Wi-Fi networks. [CHAR LIMIT=40] -->
<string name="turn_on_wifi">Wi\u2011Fi</string>
- <!-- Provider Model: Title for detail page of wifi network [CHAR LIMIT=30] -->
- <string name="pref_title_network_details" msgid="7329759534269363308">"Network details"</string>
<!-- Provider Model: Panel subtitle for tapping a network to connect to internet. [CHAR LIMIT=60] -->
<string name="tap_a_network_to_connect">Tap a network to connect</string>
<!-- Provider Model: Panel subtitle for unlocking screen to view networks. [CHAR LIMIT=60] -->
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index 649e80ecc396..1b96ad626251 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -18,8 +18,6 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Title and subtitle for AudioRecordingIndicator -->
- <string name="mic_active">Microphone Active</string>
- <string name="app_accessed_mic">%1$s accessed your microphone</string>
<string name="notification_vpn_connected">VPN is connected</string>
<string name="notification_vpn_disconnected">VPN is disconnected</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index ff299eae8cf2..94d10decd269 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -16,30 +16,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<!-- NOTE: Adding the androidprv: namespace to this file will break the studio build. -->
- <style name="ClearAllButtonDefaultMargins">
- <item name="android:layout_marginStart">0dp</item>
- <item name="android:layout_marginTop">0dp</item>
- <item name="android:layout_marginEnd">0dp</item>
- <item name="android:layout_marginBottom">0dp</item>
- </style>
-
- <style name="PipPhoneOverlayControlTheme" parent="@android:style/Theme.Material">
- <item name="android:windowIsTranslucent">true</item>
- <item name="android:windowNoTitle">true</item>
- <item name="android:windowContentOverlay">@null</item>
- <item name="android:windowBackground">@android:color/transparent</item>
- <item name="android:colorBackgroundCacheHint">@null</item>
- <item name="android:statusBarColor">@*android:color/transparent</item>
- <item name="android:windowAnimationStyle">@style/Animation.PipPhoneOverlayControl</item>
- </style>
-
- <style name="Animation.PipPhoneOverlayControl" parent="@android:style/Animation">
- <item name="android:activityOpenEnterAnimation">@anim/forced_resizable_enter</item>
-
- <!-- If the target stack doesn't have focus, we do a task to front animation. -->
- <item name="android:taskToFrontEnterAnimation">@anim/forced_resizable_enter</item>
- <item name="android:activityCloseExitAnimation">@anim/forced_resizable_exit</item>
- </style>
<!-- HybridNotification themes and styles -->
@@ -65,17 +41,6 @@
</style>
- <style name="TextAppearance.StatusBar.HeadsUp"
- parent="@*android:style/TextAppearance.StatusBar">
- </style>
-
- <style name="TextAppearance.StatusBar.SystemPanel"
- parent="@*android:style/TextAppearance.StatusBar">
- <item name="android:textAppearance">?android:attr/textAppearance</item>
- <item name="android:textStyle">normal</item>
- <item name="android:textColor">#FF808080</item>
- </style>
-
<style name="TextAppearance.StatusBar.Clock" parent="@*android:style/TextAppearance.StatusBar.Icon">
<item name="android:textSize">@dimen/status_bar_clock_size</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
@@ -172,11 +137,6 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
- <style name="TextAppearance.QS.Subhead">
- <item name="android:textSize">14sp</item>
- <item name="android:textColor">@color/qs_subhead</item>
- </style>
-
<style name="TextAppearance.QS.SegmentedButton">
<item name="android:textSize">16sp</item>
<item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
@@ -211,16 +171,7 @@
<item name="android:textColor">?android:attr/textColorSecondary</item>
</style>
- <style name="TextAppearance.QS.UserSwitcher.Activated">
- <item name="android:fontWeight">700</item>
- <item name="android:textStyle">bold</item>
- </style>
-
<!-- This is hard coded to be sans-serif-condensed to match the icons -->
- <style name="TextAppearance.RATBadge" parent="@style/TextAppearance.QS.TileLabel.Secondary">
- <item name="android:fontFamily">sans-serif-condensed</item>
- <item name="android:textSize">@dimen/celltile_rat_type_size</item>
- </style>
<style name="TextAppearance.QS.Status">
<item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
@@ -247,10 +198,6 @@
<item name="android:textColor">?android:attr/textColorSecondary</item>
</style>
- <style name="TextAppearance.DeviceManagementDialog">
- <item name="android:textColor">?android:attr/textColorPrimary</item>
- </style>
-
<style name="TextAppearance.DeviceManagementDialog.Title" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle"/>
<style name="TextAppearance.AuthCredential">
@@ -266,8 +213,6 @@
<item name="android:paddingTop">12dp</item>
<item name="android:paddingHorizontal">24dp</item>
<item name="android:textSize">24sp</item>
- <item name="android:singleLine">true</item>
- <item name="android:ellipsize">marquee</item>
</style>
<style name="TextAppearance.AuthCredential.Subtitle">
@@ -275,8 +220,6 @@
<item name="android:paddingTop">8dp</item>
<item name="android:paddingHorizontal">24dp</item>
<item name="android:textSize">16sp</item>
- <item name="android:singleLine">true</item>
- <item name="android:ellipsize">marquee</item>
</style>
<style name="TextAppearance.AuthCredential.Description">
@@ -284,8 +227,6 @@
<item name="android:paddingTop">8dp</item>
<item name="android:paddingHorizontal">24dp</item>
<item name="android:textSize">14sp</item>
- <item name="android:singleLine">true</item>
- <item name="android:ellipsize">marquee</item>
</style>
<style name="TextAppearance.AuthCredential.Error">
@@ -318,11 +259,6 @@
<style name="Animation" />
- <style name="Animation.ShirtPocketPanel">
- <item name="android:windowEnterAnimation">@*android:anim/grow_fade_in_from_bottom</item>
- <item name="android:windowExitAnimation">@*android:anim/shrink_fade_out_from_bottom</item>
- </style>
-
<style name="Animation.NavigationBarFadeIn">
<item name="android:windowEnterAnimation">@anim/navbar_fade_in</item>
<item name="android:windowExitAnimation">@null</item>
@@ -332,8 +268,6 @@
</style>
<!-- Standard animations for hiding and showing the status bar. -->
- <style name="Animation.StatusBar">
- </style>
<style name="Theme.SystemUI" parent="@*android:style/Theme.DeviceDefault.SystemUI">
<item name="lightIconTheme">@style/DualToneLightTheme</item>
@@ -419,6 +353,9 @@
<style name="Theme.SystemUI.Dialog" parent="@android:style/Theme.DeviceDefault.Light.Dialog">
<item name="android:buttonCornerRadius">28dp</item>
+ <item name="android:buttonBarPositiveButtonStyle">@style/Widget.QSDialog.Button</item>
+ <item name="android:buttonBarNegativeButtonStyle">@style/Widget.QSDialog.Button.BorderButton</item>
+ <item name="android:buttonBarNeutralButtonStyle">@style/Widget.QSDialog.Button.BorderButton</item>
</style>
<style name="Theme.SystemUI.Dialog.Alert" parent="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
@@ -441,11 +378,6 @@
<item name="android:gravity">center</item>
</style>
- <style name="SearchPanelCircle">
- <item name="android:layout_width">match_parent</item>
- <item name="android:layout_height">match_parent</item>
- </style>
-
<style name="UserDetailView">
<item name="numColumns">3</item>
</style>
@@ -506,11 +438,6 @@
<item name="android:textColor">?android:attr/textColorSecondary</item>
</style>
- <style name="TextAppearance.Volume.Header.Secondary">
- <item name="android:textSize">12sp</item>
- <item name="android:textColor">?android:attr/textColorTertiary</item>
- </style>
-
<style name="VolumeButtons" parent="@android:style/Widget.Material.Button.Borderless">
<item name="android:background">@drawable/btn_borderless_rect</item>
</style>
@@ -536,15 +463,6 @@
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
</style>
- <style name="TextAppearance.NotificationInfo.Secondary">
- <item name="android:textSize">14sp</item>
- <item name="android:alpha">0.62</item>
- </style>
-
- <style name="TextAppearance.NotificationInfo.Title">
- <item name="android:textStyle">bold</item>
- </style>
-
<style name="TextAppearance.NotificationInfo.Button">
<item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
<item name="android:textSize">14sp</item>
@@ -949,6 +867,7 @@
<item name="android:lineHeight">20sp</item>
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
<item name="android:stateListAnimator">@null</item>
+ <item name="android:layout_marginHorizontal">4dp</item>
</style>
<style name="Widget.QSDialog.Button.BorderButton">
@@ -956,10 +875,6 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
- <style name="Theme.SystemUI.Dialog.Internet">
- <item name="android:windowBackground">@drawable/internet_dialog_background</item>
- </style>
-
<style name="MainSwitch.Settingslib" parent="@android:style/Theme.DeviceDefault">
<item name="android:switchMinWidth">@dimen/settingslib_min_switch_width</item>
</style>
@@ -984,12 +899,15 @@
<style name="InternetDialog.Network">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">88dp</item>
+ <item name="android:layout_marginStart">@dimen/internet_dialog_network_layout_margin</item>
<item name="android:layout_marginEnd">@dimen/internet_dialog_network_layout_margin</item>
+ <item name="android:layout_gravity">center_vertical|start</item>
<item name="android:paddingStart">22dp</item>
<item name="android:paddingEnd">22dp</item>
<item name="android:orientation">horizontal</item>
<item name="android:focusable">true</item>
<item name="android:clickable">true</item>
+ <item name="android:background">?android:attr/selectableItemBackground</item>
</style>
<style name="InternetDialog.NetworkTitle">
diff --git a/packages/SystemUI/res/xml/combined_qs_header_scene.xml b/packages/SystemUI/res/xml/combined_qs_header_scene.xml
new file mode 100644
index 000000000000..d61e4a95bb68
--- /dev/null
+++ b/packages/SystemUI/res/xml/combined_qs_header_scene.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<MotionScene
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <Transition
+ android:id="@+id/header_transition"
+ app:constraintSetEnd="@id/qs_header_constraint"
+ app:constraintSetStart="@id/qqs_header_constraint">
+ <KeyFrameSet>
+ <KeyPosition
+ app:keyPositionType="pathRelative"
+ app:percentX="0"
+ app:framePosition="50"
+ app:motionTarget="@id/date" />
+ </KeyFrameSet>
+ </Transition>
+
+ <Transition
+ android:id="@+id/split_header_transition"
+ app:constraintSetStart="@id/split_header_constraint"
+ app:constraintSetEnd="@id/split_header_constraint"/>
+
+ <!--
+ Placeholder ConstraintSet. They are populated in the controller for this class.
+ This is needed because there's no easy way to just refer to a `ConstraintSet` file. The
+ options are either a layout file or inline the ConstraintSets.
+ -->
+ <ConstraintSet android:id="@id/qqs_header_constraint"/>
+
+ <ConstraintSet android:id="@id/qs_header_constraint"/>
+
+ <ConstraintSet android:id="@id/split_header_constraint" />
+
+</MotionScene>
diff --git a/packages/SystemUI/res/xml/media_collapsed.xml b/packages/SystemUI/res/xml/media_collapsed.xml
index c3510b61e68a..12e446f53634 100644
--- a/packages/SystemUI/res/xml/media_collapsed.xml
+++ b/packages/SystemUI/res/xml/media_collapsed.xml
@@ -58,7 +58,7 @@
<!-- Song name -->
<Constraint
android:id="@+id/header_title"
- android:layout_width="0dp"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/qs_media_info_margin"
android:layout_marginEnd="@dimen/qs_center_guideline_padding"
@@ -71,7 +71,7 @@
<!-- Artist name -->
<Constraint
android:id="@+id/header_artist"
- android:layout_width="0dp"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constrainedWidth="true"
android:layout_marginTop="@dimen/qs_media_info_spacing"
diff --git a/packages/SystemUI/res/xml/qqs_header.xml b/packages/SystemUI/res/xml/qqs_header.xml
new file mode 100644
index 000000000000..3d7b549fc54b
--- /dev/null
+++ b/packages/SystemUI/res/xml/qqs_header.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<ConstraintSet
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/qqs_header_constraint"
+>
+
+ <Constraint
+ android:id="@+id/clock">
+ <Layout
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/date"
+ app:layout_constraintHorizontal_bias="0"
+ app:layout_constraintHorizontal_chainStyle="packed"
+ />
+ </Constraint>
+
+ <Constraint
+ android:id="@+id/date">
+ <Layout
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ app:layout_constraintStart_toEndOf="@id/clock"
+ app:layout_constraintEnd_toStartOf="@id/carrier_group"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintHorizontal_bias="0"
+ />
+ </Constraint>
+
+ <Constraint
+ android:id="@+id/carrier_group">
+ <CustomAttribute
+ app:attributeName="alpha"
+ app:customFloatValue="0"
+ />
+ </Constraint>
+
+
+
+</ConstraintSet> \ No newline at end of file
diff --git a/packages/SystemUI/res/xml/qs_header.xml b/packages/SystemUI/res/xml/qs_header.xml
new file mode 100644
index 000000000000..6a0ab866966c
--- /dev/null
+++ b/packages/SystemUI/res/xml/qs_header.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<ConstraintSet
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/qs_header_constraint"
+>
+
+ <Constraint
+ android:id="@+id/clock">
+ <Layout
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/date"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/carrier_group"
+ app:layout_constraintHorizontal_bias="0"
+ />
+ </Constraint>
+
+ <Constraint
+ android:id="@+id/date">
+ <Layout
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/clock"
+ app:layout_constraintHorizontal_bias="0"
+ />
+ <Motion
+ app:motionStagger="0.5"
+ />
+ </Constraint>
+
+ <Constraint
+ android:id="@+id/carrier_group">
+ <CustomAttribute
+ app:attributeName="alpha"
+ app:customFloatValue="1"
+ />
+ </Constraint>
+
+
+</ConstraintSet> \ No newline at end of file
diff --git a/packages/SystemUI/res/xml/split_header.xml b/packages/SystemUI/res/xml/split_header.xml
new file mode 100644
index 000000000000..44d42a05cd46
--- /dev/null
+++ b/packages/SystemUI/res/xml/split_header.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<ConstraintSet
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/split_header_constraint">
+
+ <Constraint
+ android:id="@+id/clock">
+ <Layout
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/date"
+ />
+ </Constraint>
+
+ <Constraint
+ android:id="@+id/date">
+ <Layout
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ app:layout_constraintStart_toEndOf="@id/clock"
+ app:layout_constraintEnd_toStartOf="@id/carrier_group"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintHorizontal_bias="0"
+ />
+ </Constraint>
+
+ <Constraint
+ android:id="@+id/carrier_group">
+ <PropertySet
+ android:alpha="1"
+ app:customFloatValue="1"
+ />
+ </Constraint>
+
+
+</ConstraintSet> \ No newline at end of file
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index 4880b124fcdb..d172006d986d 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -45,10 +45,37 @@ android_library {
":wm_shell-aidls",
":wm_shell_util-sources",
],
-
static_libs: [
"PluginCoreLib",
"androidx.dynamicanimation_dynamicanimation",
+ "androidx.concurrent_concurrent-futures",
+ ],
+ java_version: "1.8",
+ min_sdk_version: "current",
+}
+
+java_library {
+ name: "SystemUI-flag-types",
+ srcs: [
+ "src/com/android/systemui/flags/Flag.kt",
+ ],
+ include_srcs: true,
+ static_kotlin_stdlib: false,
+ java_version: "1.8",
+ min_sdk_version: "current",
+}
+
+java_library {
+ name: "SystemUIFlagsLib",
+ srcs: [
+ "src/com/android/systemui/flags/**/*.kt",
+ ],
+ static_kotlin_stdlib: false,
+ libs: [
+ "androidx.concurrent_concurrent-futures",
+ ],
+ static_libs: [
+ "SystemUI-flag-types",
],
java_version: "1.8",
min_sdk_version: "current",
diff --git a/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt b/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
new file mode 100644
index 000000000000..9574101b466c
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
@@ -0,0 +1,183 @@
+/*
+ * 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 android.os.Parcel
+import android.os.Parcelable
+
+interface Flag<T> : Parcelable {
+ val id: Int
+ val default: T
+ val resourceOverride: Int
+
+ override fun describeContents() = 0
+
+ fun hasResourceOverride(): Boolean {
+ return resourceOverride != -1
+ }
+}
+
+// Consider using the "parcelize" kotlin library.
+
+data class BooleanFlag @JvmOverloads constructor(
+ override val id: Int,
+ override val default: Boolean = false,
+ override val resourceOverride: Int = -1
+) : Flag<Boolean> {
+
+ companion object {
+ @JvmField
+ val CREATOR = object : Parcelable.Creator<BooleanFlag> {
+ override fun createFromParcel(parcel: Parcel) = BooleanFlag(parcel)
+ override fun newArray(size: Int) = arrayOfNulls<BooleanFlag>(size)
+ }
+ }
+
+ private constructor(parcel: Parcel) : this(
+ id = parcel.readInt(),
+ default = parcel.readBoolean()
+ )
+
+ override fun writeToParcel(parcel: Parcel, flags: Int) {
+ parcel.writeInt(id)
+ parcel.writeBoolean(default)
+ }
+}
+
+data class StringFlag @JvmOverloads constructor(
+ override val id: Int,
+ override val default: String = "",
+ override val resourceOverride: Int = -1
+) : Flag<String> {
+ companion object {
+ @JvmField
+ val CREATOR = object : Parcelable.Creator<StringFlag> {
+ override fun createFromParcel(parcel: Parcel) = StringFlag(parcel)
+ override fun newArray(size: Int) = arrayOfNulls<StringFlag>(size)
+ }
+ }
+
+ private constructor(parcel: Parcel) : this(
+ id = parcel.readInt(),
+ default = parcel.readString() ?: ""
+ )
+
+ override fun writeToParcel(parcel: Parcel, flags: Int) {
+ parcel.writeInt(id)
+ parcel.writeString(default)
+ }
+}
+
+data class IntFlag @JvmOverloads constructor(
+ override val id: Int,
+ override val default: Int = 0,
+ override val resourceOverride: Int = -1
+) : Flag<Int> {
+
+ companion object {
+ @JvmField
+ val CREATOR = object : Parcelable.Creator<IntFlag> {
+ override fun createFromParcel(parcel: Parcel) = IntFlag(parcel)
+ override fun newArray(size: Int) = arrayOfNulls<IntFlag>(size)
+ }
+ }
+
+ private constructor(parcel: Parcel) : this(
+ id = parcel.readInt(),
+ default = parcel.readInt()
+ )
+
+ override fun writeToParcel(parcel: Parcel, flags: Int) {
+ parcel.writeInt(id)
+ parcel.writeInt(default)
+ }
+}
+
+data class LongFlag @JvmOverloads constructor(
+ override val id: Int,
+ override val default: Long = 0,
+ override val resourceOverride: Int = -1
+) : Flag<Long> {
+
+ companion object {
+ @JvmField
+ val CREATOR = object : Parcelable.Creator<LongFlag> {
+ override fun createFromParcel(parcel: Parcel) = LongFlag(parcel)
+ override fun newArray(size: Int) = arrayOfNulls<LongFlag>(size)
+ }
+ }
+
+ private constructor(parcel: Parcel) : this(
+ id = parcel.readInt(),
+ default = parcel.readLong()
+ )
+
+ override fun writeToParcel(parcel: Parcel, flags: Int) {
+ parcel.writeInt(id)
+ parcel.writeLong(default)
+ }
+}
+
+data class FloatFlag @JvmOverloads constructor(
+ override val id: Int,
+ override val default: Float = 0f,
+ override val resourceOverride: Int = -1
+) : Flag<Float> {
+
+ companion object {
+ @JvmField
+ val CREATOR = object : Parcelable.Creator<FloatFlag> {
+ override fun createFromParcel(parcel: Parcel) = FloatFlag(parcel)
+ override fun newArray(size: Int) = arrayOfNulls<FloatFlag>(size)
+ }
+ }
+
+ private constructor(parcel: Parcel) : this(
+ id = parcel.readInt(),
+ default = parcel.readFloat()
+ )
+
+ override fun writeToParcel(parcel: Parcel, flags: Int) {
+ parcel.writeInt(id)
+ parcel.writeFloat(default)
+ }
+}
+
+data class DoubleFlag @JvmOverloads constructor(
+ override val id: Int,
+ override val default: Double = 0.0,
+ override val resourceOverride: Int = -1
+) : Flag<Double> {
+
+ companion object {
+ @JvmField
+ val CREATOR = object : Parcelable.Creator<DoubleFlag> {
+ override fun createFromParcel(parcel: Parcel) = DoubleFlag(parcel)
+ override fun newArray(size: Int) = arrayOfNulls<DoubleFlag>(size)
+ }
+ }
+
+ private constructor(parcel: Parcel) : this(
+ id = parcel.readInt(),
+ default = parcel.readDouble()
+ )
+
+ override fun writeToParcel(parcel: Parcel, flags: Int) {
+ parcel.writeInt(id)
+ parcel.writeDouble(default)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt b/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt
new file mode 100644
index 000000000000..1dc555e300b4
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt
@@ -0,0 +1,172 @@
+/*
+ * 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 android.app.Activity
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.database.ContentObserver
+import android.net.Uri
+import android.os.Bundle
+import android.os.Handler
+import android.provider.Settings
+import androidx.concurrent.futures.CallbackToFutureAdapter
+import com.google.common.util.concurrent.ListenableFuture
+import org.json.JSONException
+import org.json.JSONObject
+
+class FlagManager constructor(
+ private val context: Context,
+ private val handler: Handler
+) : FlagReader {
+ companion object {
+ const val RECEIVING_PACKAGE = "com.android.systemui"
+ const val ACTION_SET_FLAG = "com.android.systemui.action.SET_FLAG"
+ const val ACTION_GET_FLAGS = "com.android.systemui.action.GET_FLAGS"
+ const val FLAGS_PERMISSION = "com.android.systemui.permission.FLAGS"
+ const val FIELD_ID = "id"
+ const val FIELD_VALUE = "value"
+ const val FIELD_TYPE = "type"
+ const val FIELD_FLAGS = "flags"
+ const val TYPE_BOOLEAN = "boolean"
+ private const val SETTINGS_PREFIX = "systemui/flags"
+ }
+
+ private val listeners: MutableSet<FlagReader.Listener> = mutableSetOf()
+ private val settingsObserver: ContentObserver = SettingsObserver()
+
+ fun getFlagsFuture(): ListenableFuture<Collection<Flag<*>>> {
+ val intent = Intent(ACTION_GET_FLAGS)
+ intent.setPackage(RECEIVING_PACKAGE)
+
+ return CallbackToFutureAdapter.getFuture {
+ completer: CallbackToFutureAdapter.Completer<Any?> ->
+ context.sendOrderedBroadcast(intent, null,
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ val extras: Bundle? = getResultExtras(false)
+ val listOfFlags: java.util.ArrayList<Flag<*>>? =
+ extras?.getParcelableArrayList(FIELD_FLAGS)
+ if (listOfFlags != null) {
+ completer.set(listOfFlags)
+ } else {
+ completer.setException(NoFlagResultsException())
+ }
+ }
+ }, null, Activity.RESULT_OK, "extra data", null)
+ "QueryingFlags"
+ } as ListenableFuture<Collection<Flag<*>>>
+ }
+
+ fun setFlagValue(id: Int, enabled: Boolean) {
+ val intent = createIntent(id)
+ intent.putExtra(FIELD_VALUE, enabled)
+
+ context.sendBroadcast(intent)
+ }
+
+ fun eraseFlag(id: Int) {
+ val intent = createIntent(id)
+
+ context.sendBroadcast(intent)
+ }
+
+ override fun isEnabled(id: Int, def: Boolean): Boolean {
+ return isEnabled(id) ?: def
+ }
+
+ /** Returns the stored value or null if not set. */
+ fun isEnabled(id: Int): Boolean? {
+ val data: String = Settings.Secure.getString(
+ context.contentResolver, keyToSettingsPrefix(id))
+ if (data.isEmpty()) {
+ return null
+ }
+ val json: JSONObject
+ try {
+ json = JSONObject(data)
+ return if (!assertType(json, TYPE_BOOLEAN)) {
+ null
+ } else json.getBoolean(FIELD_VALUE)
+ } catch (e: JSONException) {
+ throw InvalidFlagStorageException()
+ }
+ }
+
+ override fun addListener(listener: FlagReader.Listener) {
+ synchronized(listeners) {
+ val registerNeeded = listeners.isEmpty()
+ listeners.add(listener)
+ if (registerNeeded) {
+ context.contentResolver.registerContentObserver(
+ Settings.Secure.getUriFor(SETTINGS_PREFIX), true, settingsObserver)
+ }
+ }
+ }
+
+ override fun removeListener(listener: FlagReader.Listener) {
+ synchronized(listeners) {
+ val isRegistered = !listeners.isEmpty()
+ listeners.remove(listener)
+ if (isRegistered && listeners.isEmpty()) {
+ context.contentResolver.unregisterContentObserver(settingsObserver)
+ }
+ }
+ }
+
+ private fun createIntent(id: Int): Intent {
+ val intent = Intent(ACTION_SET_FLAG)
+ intent.setPackage(RECEIVING_PACKAGE)
+ intent.putExtra(FIELD_ID, id)
+
+ return intent
+ }
+
+ fun keyToSettingsPrefix(key: Int): String {
+ return SETTINGS_PREFIX + "/" + key
+ }
+
+ private fun assertType(json: JSONObject, type: String): Boolean {
+ return try {
+ json.getString(FIELD_TYPE) == TYPE_BOOLEAN
+ } catch (e: JSONException) {
+ false
+ }
+ }
+
+ inner class SettingsObserver : ContentObserver(handler) {
+ override fun onChange(selfChange: Boolean, uri: Uri?) {
+ if (uri == null) {
+ return
+ }
+ val parts = uri.pathSegments
+ val idStr = parts[parts.size - 1]
+ try {
+ val id = idStr.toInt()
+ listeners.forEach { l -> l.onFlagChanged(id) }
+ } catch (e: NumberFormatException) {
+ // no-op
+ }
+ }
+ }
+}
+
+class InvalidFlagStorageException : Exception("Data found but is invalid")
+
+class NoFlagResultsException : Exception(
+ "SystemUI failed to communicate its flags back successfully") \ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/flags/FlagReader.kt b/packages/SystemUI/shared/src/com/android/systemui/flags/FlagReader.kt
new file mode 100644
index 000000000000..91a391272be7
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/flags/FlagReader.kt
@@ -0,0 +1,43 @@
+/*
+ * 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
+
+/**
+ * Plugin for loading flag values
+ */
+interface FlagReader {
+ /** Returns a boolean value for the given flag. */
+ fun isEnabled(flag: BooleanFlag): Boolean {
+ return flag.default
+ }
+
+ /** Returns a boolean value for the given flag. */
+ fun isEnabled(id: Int, def: Boolean): Boolean {
+ return def
+ }
+
+ /** Add a listener to be alerted when any flag changes. */
+ fun addListener(listener: Listener) {}
+
+ /** Remove a listener to be alerted when any flag changes. */
+ fun removeListener(listener: Listener) {}
+
+ /** A simple listener to be alerted when a flag changes. */
+ fun interface Listener {
+ /** */
+ fun onFlagChanged(id: Int)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java b/packages/SystemUI/shared/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java
index e3e2367aeef8..07ad0c8a5120 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java
@@ -33,9 +33,10 @@ import android.view.RenderNodeAnimator;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
-import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
+import androidx.annotation.DimenRes;
+import androidx.annotation.Keep;
import java.util.ArrayList;
import java.util.HashSet;
@@ -47,6 +48,8 @@ public class KeyButtonRipple extends Drawable {
private static final float GLOW_MAX_ALPHA_DARK = 0.1f;
private static final int ANIMATION_DURATION_SCALE = 350;
private static final int ANIMATION_DURATION_FADE = 450;
+ private static final Interpolator ALPHA_OUT_INTERPOLATOR =
+ new PathInterpolator(0f, 0f, 0.8f, 1f);
private Paint mRipplePaint;
private CanvasProperty<Float> mLeftProp;
@@ -86,8 +89,8 @@ public class KeyButtonRipple extends Drawable {
private Type mType = Type.ROUNDED_RECT;
- public KeyButtonRipple(Context ctx, View targetView) {
- mMaxWidth = ctx.getResources().getDimensionPixelSize(R.dimen.key_button_ripple_max_width);
+ public KeyButtonRipple(Context ctx, View targetView, @DimenRes int maxWidthResource) {
+ mMaxWidth = ctx.getResources().getDimensionPixelSize(maxWidthResource);
mTargetView = targetView;
}
@@ -184,19 +187,27 @@ public class KeyButtonRipple extends Drawable {
}
}
+ /** Gets the glow alpha, used by {@link android.animation.ObjectAnimator} via reflection. */
+ @Keep
public float getGlowAlpha() {
return mGlowAlpha;
}
+ /** Sets the glow alpha, used by {@link android.animation.ObjectAnimator} via reflection. */
+ @Keep
public void setGlowAlpha(float x) {
mGlowAlpha = x;
invalidateSelf();
}
+ /** Gets the glow scale, used by {@link android.animation.ObjectAnimator} via reflection. */
+ @Keep
public float getGlowScale() {
return mGlowScale;
}
+ /** Sets the glow scale, used by {@link android.animation.ObjectAnimator} via reflection. */
+ @Keep
public void setGlowScale(float x) {
mGlowScale = x;
invalidateSelf();
@@ -326,7 +337,7 @@ public class KeyButtonRipple extends Drawable {
private void exitSoftware() {
ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(this, "glowAlpha", mGlowAlpha, 0f);
- alphaAnimator.setInterpolator(Interpolators.ALPHA_OUT);
+ alphaAnimator.setInterpolator(ALPHA_OUT_INTERPOLATOR);
alphaAnimator.setDuration(ANIMATION_DURATION_FADE);
alphaAnimator.addListener(mAnimatorListener);
alphaAnimator.start();
@@ -449,7 +460,7 @@ public class KeyButtonRipple extends Drawable {
final RenderNodeAnimator opacityAnim = new RenderNodeAnimator(mPaintProp,
RenderNodeAnimator.PAINT_ALPHA, 0);
opacityAnim.setDuration(ANIMATION_DURATION_FADE);
- opacityAnim.setInterpolator(Interpolators.ALPHA_OUT);
+ opacityAnim.setInterpolator(ALPHA_OUT_INTERPOLATOR);
opacityAnim.addListener(mAnimatorListener);
opacityAnim.addListener(mExitHwTraceAnimator);
opacityAnim.setTarget(mTargetView);
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 5b7e500c4630..be15c700818c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -150,5 +150,10 @@ interface ISystemUiProxy {
*/
oneway void notifyTaskbarAutohideSuspend(boolean suspend) = 48;
- // Next id = 49
+ /**
+ * Notifies SystemUI to invoke IME Switcher.
+ */
+ void onImeSwitcherPressed() = 49;
+
+ // Next id = 50
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
index e9e9b2421d4a..3128ffdbc67b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
@@ -23,21 +23,19 @@ import android.app.ActivityManager.TaskDescription;
import android.app.TaskInfo;
import android.content.ComponentName;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.ViewDebug;
-import com.android.systemui.shared.recents.utilities.Utilities;
+import androidx.annotation.Nullable;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.Objects;
/**
* A task in the recent tasks list.
+ * TODO: Move this into Launcher or see if we can remove now
*/
public class Task {
@@ -201,8 +199,8 @@ public class Task {
* The icon is the task description icon (if provided), which falls back to the activity icon,
* which can then fall back to the application icon.
*/
- public Drawable icon;
- public ThumbnailData thumbnail;
+ @Nullable public Drawable icon;
+ @Nullable public ThumbnailData thumbnail;
@ViewDebug.ExportedProperty(category="recents")
@Deprecated
public String title;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
index 6594d5f51af3..2f2876d2e9f3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
@@ -22,7 +22,6 @@ import static android.graphics.Bitmap.Config.ARGB_8888;
import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_UNDEFINED;
-import android.window.TaskSnapshot;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Point;
@@ -30,6 +29,9 @@ import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.util.Log;
import android.view.WindowInsetsController.Appearance;
+import android.window.TaskSnapshot;
+
+import java.util.HashMap;
/**
* Data for a single thumbnail.
@@ -80,6 +82,18 @@ public class ThumbnailData {
return thumbnail;
}
+ public static HashMap<Integer, ThumbnailData> wrap(int[] taskIds, TaskSnapshot[] snapshots) {
+ HashMap<Integer, ThumbnailData> temp = new HashMap<>();
+ if (taskIds == null || snapshots == null || taskIds.length != snapshots.length) {
+ return temp;
+ }
+
+ for (int i = snapshots.length - 1; i >= 0; i--) {
+ temp.put(taskIds[i], new ThumbnailData(snapshots[i]));
+ }
+ return temp;
+ }
+
public ThumbnailData(TaskSnapshot snapshot) {
thumbnail = makeThumbnail(snapshot);
insets = new Rect(snapshot.getContentInsets());
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButton.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java
index 46057952e079..cbf739732361 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButton.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java
@@ -14,12 +14,17 @@
* limitations under the License.
*/
-package com.android.systemui.navigationbar.gestural;
+package com.android.systemui.shared.rotation;
+import android.annotation.DimenRes;
+import android.annotation.IdRes;
+import android.annotation.LayoutRes;
+import android.annotation.StringRes;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.Color;
import android.graphics.PixelFormat;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -27,28 +32,25 @@ import android.view.WindowManager;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.FrameLayout;
-import com.android.systemui.R;
-import com.android.systemui.navigationbar.RotationButton;
-import com.android.systemui.navigationbar.RotationButtonController;
-import com.android.systemui.navigationbar.buttons.KeyButtonDrawable;
-import com.android.systemui.navigationbar.buttons.KeyButtonView;
-import com.android.systemui.navigationbar.gestural.FloatingRotationButtonPositionCalculator.Position;
+import androidx.core.view.OneShotPreDrawListener;
+
+import com.android.systemui.shared.R;
+import com.android.systemui.shared.rotation.FloatingRotationButtonPositionCalculator.Position;
/**
* Containing logic for the rotation button on the physical left bottom corner of the screen.
*/
public class FloatingRotationButton implements RotationButton {
- private static final float BACKGROUND_ALPHA = 0.92f;
private static final int MARGIN_ANIMATION_DURATION_MILLIS = 300;
private final WindowManager mWindowManager;
private final ViewGroup mKeyButtonContainer;
- private final KeyButtonView mKeyButtonView;
+ private final FloatingRotationButtonView mKeyButtonView;
private final int mContainerSize;
- private KeyButtonDrawable mKeyButtonDrawable;
+ private AnimatedVectorDrawable mAnimatedDrawable;
private boolean mIsShowing;
private boolean mCanShow = true;
private int mDisplayRotation;
@@ -62,28 +64,33 @@ public class FloatingRotationButton implements RotationButton {
private RotationButtonUpdatesCallback mUpdatesCallback;
private Position mPosition;
- public FloatingRotationButton(Context context) {
+ public FloatingRotationButton(Context context, @StringRes int contentDescription,
+ @LayoutRes int layout, @IdRes int keyButtonId, @DimenRes int minMargin,
+ @DimenRes int roundedContentPadding, @DimenRes int taskbarLeftMargin,
+ @DimenRes int taskbarBottomMargin, @DimenRes int buttonDiameter,
+ @DimenRes int rippleMaxWidth) {
mWindowManager = context.getSystemService(WindowManager.class);
- mKeyButtonContainer = (ViewGroup) LayoutInflater.from(context).inflate(
- R.layout.rotate_suggestion, null);
- mKeyButtonView = mKeyButtonContainer.findViewById(R.id.rotate_suggestion);
+ mKeyButtonContainer = (ViewGroup) LayoutInflater.from(context).inflate(layout, null);
+ mKeyButtonView = mKeyButtonContainer.findViewById(keyButtonId);
mKeyButtonView.setVisibility(View.VISIBLE);
+ mKeyButtonView.setContentDescription(context.getString(contentDescription));
+ mKeyButtonView.setRipple(rippleMaxWidth);
Resources res = context.getResources();
int defaultMargin = Math.max(
- res.getDimensionPixelSize(R.dimen.floating_rotation_button_min_margin),
- res.getDimensionPixelSize(R.dimen.rounded_corner_content_padding));
+ res.getDimensionPixelSize(minMargin),
+ res.getDimensionPixelSize(roundedContentPadding));
int taskbarMarginLeft =
- res.getDimensionPixelSize(R.dimen.floating_rotation_button_taskbar_left_margin);
+ res.getDimensionPixelSize(taskbarLeftMargin);
int taskbarMarginBottom =
- res.getDimensionPixelSize(R.dimen.floating_rotation_button_taskbar_bottom_margin);
+ res.getDimensionPixelSize(taskbarBottomMargin);
mPositionCalculator = new FloatingRotationButtonPositionCalculator(defaultMargin,
taskbarMarginLeft, taskbarMarginBottom);
- final int diameter = res.getDimensionPixelSize(R.dimen.floating_rotation_button_diameter);
+ final int diameter = res.getDimensionPixelSize(buttonDiameter);
mContainerSize = diameter + Math.max(defaultMargin, Math.max(taskbarMarginLeft,
taskbarMarginBottom));
}
@@ -113,6 +120,10 @@ public class FloatingRotationButton implements RotationButton {
mIsShowing = true;
int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+
+ // TODO(b/200103245): add new window type that has z-index above
+ // TYPE_NAVIGATION_BAR_PANEL as currently it could be below the taskbar which has
+ // the same window type
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
mContainerSize,
mContainerSize,
@@ -134,14 +145,18 @@ public class FloatingRotationButton implements RotationButton {
updateTranslation(mPosition, /* animate */ false);
mWindowManager.addView(mKeyButtonContainer, lp);
- if (mKeyButtonDrawable != null && mKeyButtonDrawable.canAnimate()) {
- mKeyButtonDrawable.resetAnimation();
- mKeyButtonDrawable.startAnimation();
+ if (mAnimatedDrawable != null) {
+ mAnimatedDrawable.reset();
+ mAnimatedDrawable.start();
}
- if (mUpdatesCallback != null) {
- mUpdatesCallback.onVisibilityChanged(true);
- }
+ // Notify about visibility only after first traversal so we can properly calculate
+ // the touch region for the button
+ OneShotPreDrawListener.add(mKeyButtonView, () -> {
+ if (mIsShowing && mUpdatesCallback != null) {
+ mUpdatesCallback.onVisibilityChanged(true);
+ }
+ });
return true;
}
@@ -166,12 +181,10 @@ public class FloatingRotationButton implements RotationButton {
@Override
public void updateIcon(int lightIconColor, int darkIconColor) {
- Color ovalBackgroundColor = Color.valueOf(Color.red(darkIconColor),
- Color.green(darkIconColor), Color.blue(darkIconColor), BACKGROUND_ALPHA);
- mKeyButtonDrawable = KeyButtonDrawable.create(mRotationButtonController.getContext(),
- lightIconColor, darkIconColor, mRotationButtonController.getIconResId(),
- false /* shadow */, ovalBackgroundColor);
- mKeyButtonView.setImageDrawable(mKeyButtonDrawable);
+ mAnimatedDrawable = (AnimatedVectorDrawable) mKeyButtonView.getContext()
+ .getDrawable(mRotationButtonController.getIconResId());
+ mKeyButtonView.setImageDrawable(mAnimatedDrawable);
+ mKeyButtonView.setColors(lightIconColor, darkIconColor);
}
@Override
@@ -185,8 +198,8 @@ public class FloatingRotationButton implements RotationButton {
}
@Override
- public KeyButtonDrawable getImageDrawable() {
- return mKeyButtonDrawable;
+ public Drawable getImageDrawable() {
+ return mAnimatedDrawable;
}
@Override
@@ -202,6 +215,7 @@ public class FloatingRotationButton implements RotationButton {
}
}
+ @Override
public void onTaskbarStateChanged(boolean taskbarVisible, boolean taskbarStashed) {
mIsTaskbarVisible = taskbarVisible;
mIsTaskbarStashed = taskbarStashed;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculator.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonPositionCalculator.kt
index 3ce51ad331c5..ec3c073dc68d 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculator.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonPositionCalculator.kt
@@ -1,4 +1,4 @@
-package com.android.systemui.navigationbar.gestural
+package com.android.systemui.shared.rotation
import android.view.Gravity
import android.view.Surface
@@ -7,7 +7,7 @@ import android.view.Surface
* Calculates gravity and translation that is necessary to display
* the button in the correct position based on the current state
*/
-internal class FloatingRotationButtonPositionCalculator(
+class FloatingRotationButtonPositionCalculator(
private val defaultMargin: Int,
private val taskbarMarginLeft: Int,
private val taskbarMarginBottom: Int
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonView.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonView.java
new file mode 100644
index 000000000000..c5f8fc15b3b7
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonView.java
@@ -0,0 +1,86 @@
+/*
+ * 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.shared.rotation;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.annotation.DimenRes;
+
+import com.android.systemui.navigationbar.buttons.KeyButtonRipple;
+
+public class FloatingRotationButtonView extends ImageView {
+
+ private static final float BACKGROUND_ALPHA = 0.92f;
+
+ private KeyButtonRipple mRipple;
+ private final Paint mOvalBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+
+ public FloatingRotationButtonView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public FloatingRotationButtonView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ setClickable(true);
+
+ setWillNotDraw(false);
+ forceHasOverlappingRendering(false);
+ }
+
+ public void setRipple(@DimenRes int rippleMaxWidthResource) {
+ mRipple = new KeyButtonRipple(getContext(), this, rippleMaxWidthResource);
+ setBackground(mRipple);
+ }
+
+ @Override
+ protected void onWindowVisibilityChanged(int visibility) {
+ super.onWindowVisibilityChanged(visibility);
+ if (visibility != View.VISIBLE) {
+ jumpDrawablesToCurrentState();
+ }
+ }
+
+ public void setColors(int lightColor, int darkColor) {
+ getDrawable().setColorFilter(new PorterDuffColorFilter(lightColor, PorterDuff.Mode.SRC_IN));
+
+ final int ovalBackgroundColor = Color.valueOf(Color.red(darkColor),
+ Color.green(darkColor), Color.blue(darkColor), BACKGROUND_ALPHA).toArgb();
+
+ mOvalBgPaint.setColor(ovalBackgroundColor);
+ mRipple.setType(KeyButtonRipple.Type.OVAL);
+ }
+
+ public void setDarkIntensity(float darkIntensity) {
+ mRipple.setDarkIntensity(darkIntensity);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ int d = Math.min(getWidth(), getHeight());
+ canvas.drawOval(0, 0, d, d, mOvalBgPaint);
+ super.draw(canvas);
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButton.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButton.java
new file mode 100644
index 000000000000..89f71ebf3dce
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButton.java
@@ -0,0 +1,59 @@
+/*
+ * 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.shared.rotation;
+
+import android.graphics.drawable.Drawable;
+import android.view.View;
+
+/**
+ * Interface of a rotation button that interacts {@link RotationButtonController}.
+ * This interface exists because of the two different styles of rotation button in Sysui,
+ * one in contextual for 3 button nav and a floating rotation button for gestural.
+ */
+public interface RotationButton {
+ default void setRotationButtonController(RotationButtonController rotationButtonController) { }
+ default void setUpdatesCallback(RotationButtonUpdatesCallback updatesCallback) { }
+
+ default View getCurrentView() {
+ return null;
+ }
+ default boolean show() { return false; }
+ default boolean hide() { return false; }
+ default boolean isVisible() {
+ return false;
+ }
+ default void setCanShowRotationButton(boolean canShow) {}
+ default void onTaskbarStateChanged(boolean taskbarVisible, boolean taskbarStashed) {}
+ default void updateIcon(int lightIconColor, int darkIconColor) { }
+ default void setOnClickListener(View.OnClickListener onClickListener) { }
+ default void setOnHoverListener(View.OnHoverListener onHoverListener) { }
+ default Drawable getImageDrawable() {
+ return null;
+ }
+ default void setDarkIntensity(float darkIntensity) { }
+ default boolean acceptRotationProposal() {
+ return getCurrentView() != null;
+ }
+
+ /**
+ * Callback for updates provided by a rotation button
+ */
+ interface RotationButtonUpdatesCallback {
+ default void onVisibilityChanged(boolean isVisible) {};
+ default void onPositionChanged() {};
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
index 0f5c03a2a596..2dbd5dee76aa 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui.navigationbar;
+package com.android.systemui.shared.rotation;
+
+import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.internal.view.RotationPolicy.NATURAL_ROTATION;
@@ -23,48 +25,51 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
+import android.annotation.SuppressLint;
import android.app.StatusBarManager;
import android.content.ContentResolver;
import android.content.Context;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.Log;
-import android.view.IRotationWatcher.Stub;
+import android.view.IRotationWatcher;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.view.WindowInsetsController;
-import android.view.WindowInsetsController.Behavior;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
-import com.android.systemui.navigationbar.RotationButton.RotationButtonUpdatesCallback;
-import com.android.systemui.navigationbar.buttons.KeyButtonDrawable;
+import com.android.internal.view.RotationPolicy;
+import com.android.systemui.shared.rotation.RotationButton.RotationButtonUpdatesCallback;
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.shared.recents.utilities.ViewRippler;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
-import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
-import com.android.systemui.statusbar.policy.RotationLockController;
import java.util.Optional;
import java.util.function.Consumer;
+import java.util.function.Supplier;
-/** Contains logic that deals with showing a rotate suggestion button with animation. */
+/**
+ * Contains logic that deals with showing a rotate suggestion button with animation.
+ */
public class RotationButtonController {
private static final String TAG = "StatusBar/RotationButtonController";
private static final int BUTTON_FADE_IN_OUT_DURATION_MS = 100;
private static final int NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS = 20000;
+ private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
private static final int NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION = 3;
@@ -72,6 +77,7 @@ public class RotationButtonController {
private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
private final UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
private final ViewRippler mViewRippler = new ViewRippler();
+ private final Supplier<Integer> mWindowRotationProvider;
private RotationButton mRotationButton;
private boolean mIsRecentsAnimationRunning;
@@ -79,17 +85,30 @@ public class RotationButtonController {
private int mLastRotationSuggestion;
private boolean mPendingRotationSuggestion;
private boolean mHoveringRotationSuggestion;
- private RotationLockController mRotationLockController;
- private AccessibilityManagerWrapper mAccessibilityManagerWrapper;
- private TaskStackListenerImpl mTaskStackListener;
+ private final AccessibilityManager mAccessibilityManager;
+ private final TaskStackListenerImpl mTaskStackListener;
private Consumer<Integer> mRotWatcherListener;
+
private boolean mListenersRegistered = false;
private boolean mIsNavigationBarShowing;
- private @Behavior int mBehavior = WindowInsetsController.BEHAVIOR_DEFAULT;
+ @SuppressLint("InlinedApi")
+ private @WindowInsetsController.Behavior
+ int mBehavior = WindowInsetsController.BEHAVIOR_DEFAULT;
private boolean mSkipOverrideUserLockPrefsOnce;
- private int mLightIconColor;
- private int mDarkIconColor;
- private int mIconResId = R.drawable.ic_sysbar_rotate_button_ccw_start_90;
+ private final int mLightIconColor;
+ private final int mDarkIconColor;
+
+ @DrawableRes
+ private final int mIconCcwStart0ResId;
+ @DrawableRes
+ private final int mIconCcwStart90ResId;
+ @DrawableRes
+ private final int mIconCwStart0ResId;
+ @DrawableRes
+ private final int mIconCwStart90ResId;
+
+ @DrawableRes
+ private int mIconResId;
private final Runnable mRemoveRotationProposal =
() -> setRotateSuggestionButtonState(false /* visible */);
@@ -97,19 +116,20 @@ public class RotationButtonController {
() -> mPendingRotationSuggestion = false;
private Animator mRotateHideAnimator;
- private final Stub mRotationWatcher = new Stub() {
+
+ private final IRotationWatcher.Stub mRotationWatcher = new IRotationWatcher.Stub() {
@Override
- public void onRotationChanged(final int rotation) throws RemoteException {
+ public void onRotationChanged(final int rotation) {
// We need this to be scheduled as early as possible to beat the redrawing of
// window in response to the orientation change.
mMainThreadHandler.postAtFrontOfQueue(() -> {
// If the screen rotation changes while locked, potentially update lock to flow with
// new screen rotation and hide any showing suggestions.
- if (mRotationLockController.isRotationLocked()) {
+ if (isRotationLocked()) {
if (shouldOverrideUserLockPrefs(rotation)) {
setRotationLockedAtAngle(rotation);
}
- setRotateSuggestionButtonState(false /* visible */, true /* hideImmediately */);
+ setRotateSuggestionButtonState(false /* visible */, true /* forced */);
}
if (mRotWatcherListener != null) {
@@ -121,27 +141,39 @@ public class RotationButtonController {
/**
* Determines if rotation suggestions disabled2 flag exists in flag
+ *
* @param disable2Flags see if rotation suggestion flag exists in this flag
* @return whether flag exists
*/
- static boolean hasDisable2RotateSuggestionFlag(int disable2Flags) {
+ public static boolean hasDisable2RotateSuggestionFlag(int disable2Flags) {
return (disable2Flags & StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS) != 0;
}
- RotationButtonController(Context context, @ColorInt int lightIconColor,
- @ColorInt int darkIconColor) {
+ public RotationButtonController(Context context,
+ @ColorInt int lightIconColor, @ColorInt int darkIconColor,
+ @DrawableRes int iconCcwStart0ResId,
+ @DrawableRes int iconCcwStart90ResId,
+ @DrawableRes int iconCwStart0ResId,
+ @DrawableRes int iconCwStart90ResId,
+ Supplier<Integer> windowRotationProvider) {
+
mContext = context;
mLightIconColor = lightIconColor;
mDarkIconColor = darkIconColor;
- mIsNavigationBarShowing = true;
- mRotationLockController = Dependency.get(RotationLockController.class);
- mAccessibilityManagerWrapper = Dependency.get(AccessibilityManagerWrapper.class);
+ mIconCcwStart0ResId = iconCcwStart0ResId;
+ mIconCcwStart90ResId = iconCcwStart90ResId;
+ mIconCwStart0ResId = iconCwStart0ResId;
+ mIconCwStart90ResId = iconCwStart90ResId;
+ mIconResId = mIconCcwStart90ResId;
+
+ mAccessibilityManager = AccessibilityManager.getInstance(context);
mTaskStackListener = new TaskStackListenerImpl();
+ mWindowRotationProvider = windowRotationProvider;
}
- void setRotationButton(RotationButton rotationButton,
- RotationButtonUpdatesCallback updatesCallback) {
+ public void setRotationButton(RotationButton rotationButton,
+ RotationButtonUpdatesCallback updatesCallback) {
mRotationButton = rotationButton;
mRotationButton.setRotationButtonController(this);
mRotationButton.setOnClickListener(this::onRotateSuggestionClick);
@@ -149,7 +181,24 @@ public class RotationButtonController {
mRotationButton.setUpdatesCallback(updatesCallback);
}
- void registerListeners() {
+ public Context getContext() {
+ return mContext;
+ }
+
+ public void init() {
+ registerListeners();
+ if (mContext.getDisplay().getDisplayId() != DEFAULT_DISPLAY) {
+ // Currently there is no accelerometer sensor on non-default display, disable fixed
+ // rotation for non-default display
+ onDisable2FlagChanged(StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS);
+ }
+ }
+
+ public void onDestroy() {
+ unregisterListeners();
+ }
+
+ public void registerListeners() {
if (mListenersRegistered) {
return;
}
@@ -157,18 +206,19 @@ public class RotationButtonController {
mListenersRegistered = true;
try {
WindowManagerGlobal.getWindowManagerService()
- .watchRotation(mRotationWatcher, mContext.getDisplay().getDisplayId());
+ .watchRotation(mRotationWatcher, DEFAULT_DISPLAY);
} catch (IllegalArgumentException e) {
mListenersRegistered = false;
Log.w(TAG, "RegisterListeners for the display failed");
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ Log.e(TAG, "RegisterListeners caught a RemoteException", e);
+ return;
}
TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
}
- void unregisterListeners() {
+ public void unregisterListeners() {
if (!mListenersRegistered) {
return;
}
@@ -177,34 +227,31 @@ public class RotationButtonController {
try {
WindowManagerGlobal.getWindowManagerService().removeRotationWatcher(mRotationWatcher);
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ Log.e(TAG, "UnregisterListeners caught a RemoteException", e);
+ return;
}
TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
}
- void setRotationCallback(Consumer<Integer> watcher) {
+ public void setRotationCallback(Consumer<Integer> watcher) {
mRotWatcherListener = watcher;
}
- void setRotationLockedAtAngle(int rotationSuggestion) {
- mRotationLockController.setRotationLockedAtAngle(true /* locked */, rotationSuggestion);
+ public void setRotationLockedAtAngle(int rotationSuggestion) {
+ RotationPolicy.setRotationLockAtAngle(mContext, true, rotationSuggestion);
}
public boolean isRotationLocked() {
- return mRotationLockController.isRotationLocked();
+ return RotationPolicy.isRotationLocked(mContext);
}
- void setRotateSuggestionButtonState(boolean visible) {
- setRotateSuggestionButtonState(visible, false /* hideImmediately */);
+ public void setRotateSuggestionButtonState(boolean visible) {
+ setRotateSuggestionButtonState(visible, false /* force */);
}
- /**
- * Change the visibility of rotate suggestion button. If {@code hideImmediately} is true,
- * it doesn't wait until the completion of the running animation.
- */
- void setRotateSuggestionButtonState(final boolean visible, final boolean hideImmediately) {
- // At any point the the button can become invisible because an a11y service became active.
+ void setRotateSuggestionButtonState(final boolean visible, final boolean force) {
+ // At any point the button can become invisible because an a11y service became active.
// Similarly, a call to make the button visible may be rejected because an a11y service is
// active. Must account for this.
// Rerun a show animation to indicate change but don't rerun a hide animation
@@ -213,7 +260,7 @@ public class RotationButtonController {
final View view = mRotationButton.getCurrentView();
if (view == null) return;
- final KeyButtonDrawable currentDrawable = mRotationButton.getImageDrawable();
+ final Drawable currentDrawable = mRotationButton.getImageDrawable();
if (currentDrawable == null) return;
// Clear any pending suggestion flag as it has either been nullified or is being shown
@@ -232,11 +279,13 @@ public class RotationButtonController {
view.setAlpha(1f);
// Run the rotate icon's animation if it has one
- if (currentDrawable.canAnimate()) {
- currentDrawable.resetAnimation();
- currentDrawable.startAnimation();
+ if (currentDrawable instanceof AnimatedVectorDrawable) {
+ ((AnimatedVectorDrawable) currentDrawable).reset();
+ ((AnimatedVectorDrawable) currentDrawable).start();
}
+ // TODO(b/187754252): No idea why this doesn't work. If we remove the "false"
+ // we see the animation show the pressed state... but it only shows the first time.
if (!isRotateSuggestionIntroduced()) mViewRippler.start(view);
// Set visibility unless a11y service is active.
@@ -244,7 +293,7 @@ public class RotationButtonController {
} else { // Hide
mViewRippler.stop(); // Prevent any pending ripples, force hide or not
- if (hideImmediately) {
+ if (force) {
// If a hide animator is running stop it and make invisible
if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) {
mRotateHideAnimator.pause();
@@ -258,7 +307,7 @@ public class RotationButtonController {
ObjectAnimator fadeOut = ObjectAnimator.ofFloat(view, "alpha", 0f);
fadeOut.setDuration(BUTTON_FADE_IN_OUT_DURATION_MS);
- fadeOut.setInterpolator(Interpolators.LINEAR);
+ fadeOut.setInterpolator(LINEAR_INTERPOLATOR);
fadeOut.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -271,29 +320,34 @@ public class RotationButtonController {
}
}
- void setRecentsAnimationRunning(boolean running) {
+ public void setDarkIntensity(float darkIntensity) {
+ mRotationButton.setDarkIntensity(darkIntensity);
+ }
+
+ public void setRecentsAnimationRunning(boolean running) {
mIsRecentsAnimationRunning = running;
updateRotationButtonStateInOverview();
}
- void setHomeRotationEnabled(boolean enabled) {
+ public void setHomeRotationEnabled(boolean enabled) {
mHomeRotationEnabled = enabled;
updateRotationButtonStateInOverview();
}
private void updateRotationButtonStateInOverview() {
if (mIsRecentsAnimationRunning && !mHomeRotationEnabled) {
- setRotateSuggestionButtonState(false, true /* hideImmediately */ );
+ setRotateSuggestionButtonState(false, true /* hideImmediately */);
}
}
- void setDarkIntensity(float darkIntensity) {
- mRotationButton.setDarkIntensity(darkIntensity);
- }
+ public void onRotationProposal(int rotation, boolean isValid) {
+ int windowRotation = mWindowRotationProvider.get();
+
+ if (!mRotationButton.acceptRotationProposal()) {
+ return;
+ }
- void onRotationProposal(int rotation, int windowRotation, boolean isValid) {
- if (!mRotationButton.acceptRotationProposal() || (!mHomeRotationEnabled
- && mIsRecentsAnimationRunning)) {
+ if (!mHomeRotationEnabled && mIsRecentsAnimationRunning) {
return;
}
@@ -316,13 +370,9 @@ public class RotationButtonController {
mLastRotationSuggestion = rotation; // Remember rotation for click
final boolean rotationCCW = Utilities.isRotationAnimationCCW(windowRotation, rotation);
if (windowRotation == Surface.ROTATION_0 || windowRotation == Surface.ROTATION_180) {
- mIconResId = rotationCCW
- ? R.drawable.ic_sysbar_rotate_button_ccw_start_90
- : R.drawable.ic_sysbar_rotate_button_cw_start_90;
+ mIconResId = rotationCCW ? mIconCcwStart0ResId : mIconCwStart0ResId;
} else { // 90 or 270
- mIconResId = rotationCCW
- ? R.drawable.ic_sysbar_rotate_button_ccw_start_0
- : R.drawable.ic_sysbar_rotate_button_ccw_start_0;
+ mIconResId = rotationCCW ? mIconCcwStart90ResId : mIconCwStart90ResId;
}
mRotationButton.updateIcon(mLightIconColor, mDarkIconColor);
@@ -339,56 +389,66 @@ public class RotationButtonController {
}
}
- void onDisable2FlagChanged(int state2) {
+ public void onDisable2FlagChanged(int state2) {
final boolean rotateSuggestionsDisabled = hasDisable2RotateSuggestionFlag(state2);
if (rotateSuggestionsDisabled) onRotationSuggestionsDisabled();
}
- void onNavigationBarWindowVisibilityChange(boolean showing) {
- if (mIsNavigationBarShowing != showing) {
- mIsNavigationBarShowing = showing;
- showPendingRotationButtonIfNeeded();
+ public void onBehaviorChanged(int displayId, @WindowInsetsController.Behavior int behavior) {
+ if (DEFAULT_DISPLAY != displayId) {
+ return;
}
- }
- void onBehaviorChanged(@Behavior int behavior) {
if (mBehavior != behavior) {
mBehavior = behavior;
showPendingRotationButtonIfNeeded();
}
}
+ public void onNavigationBarWindowVisibilityChange(boolean showing) {
+ if (mIsNavigationBarShowing != showing) {
+ mIsNavigationBarShowing = showing;
+ showPendingRotationButtonIfNeeded();
+ }
+ }
+
+ public void onTaskbarStateChange(boolean visible, boolean stashed) {
+ getRotationButton().onTaskbarStateChanged(visible, stashed);
+ }
+
private void showPendingRotationButtonIfNeeded() {
if (canShowRotationButton() && mPendingRotationSuggestion) {
showAndLogRotationSuggestion();
}
}
- /** Return true when either the nav bar is visible or it's in visual immersive mode. */
+ /**
+ * Return true when either the task bar is visible or it's in visual immersive mode.
+ */
+ @SuppressLint("InlinedApi")
private boolean canShowRotationButton() {
return mIsNavigationBarShowing || mBehavior == WindowInsetsController.BEHAVIOR_DEFAULT;
}
- public Context getContext() {
- return mContext;
- }
-
- RotationButton getRotationButton() {
- return mRotationButton;
- }
-
- public @DrawableRes int getIconResId() {
+ @DrawableRes
+ public int getIconResId() {
return mIconResId;
}
- public @ColorInt int getLightIconColor() {
+ @ColorInt
+ public int getLightIconColor() {
return mLightIconColor;
}
- public @ColorInt int getDarkIconColor() {
+ @ColorInt
+ public int getDarkIconColor() {
return mDarkIconColor;
}
+ public RotationButton getRotationButton() {
+ return mRotationButton;
+ }
+
private void onRotateSuggestionClick(View v) {
mUiEventLogger.log(RotationButtonEvent.ROTATION_SUGGESTION_ACCEPTED);
incrementNumAcceptedRotationSuggestionsIfNeeded();
@@ -420,7 +480,7 @@ public class RotationButtonController {
* avoid losing original user rotation when display rotation is changed by entering the fixed
* orientation overview.
*/
- void setSkipOverrideUserLockPrefsOnce() {
+ public void setSkipOverrideUserLockPrefsOnce() {
mSkipOverrideUserLockPrefsOnce = true;
}
@@ -451,7 +511,7 @@ public class RotationButtonController {
}
private int computeRotationProposalTimeout() {
- return mAccessibilityManagerWrapper.getRecommendedTimeoutMillis(
+ return mAccessibilityManager.getRecommendedTimeoutMillis(
mHoveringRotationSuggestion ? 16000 : 5000,
AccessibilityManager.FLAG_CONTENT_CONTROLS);
}
@@ -513,11 +573,15 @@ public class RotationButtonController {
ROTATION_SUGGESTION_ACCEPTED(207);
private final int mId;
+
RotationButtonEvent(int id) {
mId = id;
}
- @Override public int getId() {
+
+ @Override
+ public int getId() {
return mId;
}
}
}
+
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 9164137feb41..38eded878014 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -28,7 +28,6 @@ import android.app.ActivityClient;
import android.app.ActivityManager;
import android.app.ActivityManager.RecentTaskInfo;
import android.app.ActivityManager.RunningTaskInfo;
-import android.window.TaskSnapshot;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.AppGlobals;
@@ -50,6 +49,7 @@ import android.util.Log;
import android.view.IRecentsAnimationController;
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationTarget;
+import android.window.TaskSnapshot;
import com.android.internal.app.IVoiceInteractionManagerService;
import com.android.systemui.shared.recents.model.Task;
@@ -189,14 +189,19 @@ public class ActivityManagerWrapper {
}
@Override
- public void onAnimationCanceled(TaskSnapshot taskSnapshot) {
+ public void onAnimationCanceled(int[] taskIds, TaskSnapshot[] taskSnapshots) {
animationHandler.onAnimationCanceled(
- taskSnapshot != null ? new ThumbnailData(taskSnapshot) : null);
+ ThumbnailData.wrap(taskIds, taskSnapshots));
}
@Override
- public void onTaskAppeared(RemoteAnimationTarget app) {
- animationHandler.onTaskAppeared(new RemoteAnimationTargetCompat(app));
+ public void onTasksAppeared(RemoteAnimationTarget[] apps) {
+ final RemoteAnimationTargetCompat[] compats =
+ new RemoteAnimationTargetCompat[apps.length];
+ for (int i = 0; i < apps.length; ++i) {
+ compats[i] = new RemoteAnimationTargetCompat(apps[i]);
+ }
+ animationHandler.onTasksAppeared(compats);
}
};
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index d447b485f33b..d182399239cc 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -57,6 +57,8 @@ public class QuickStepContract {
"extra_shell_starting_window";
// See ISmartspaceTransitionController.aidl
public static final String KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER = "smartspace_transition";
+ // See IRecentTasks.aidl
+ public static final String KEY_EXTRA_RECENT_TASKS = "recent_tasks";
public static final String NAV_BAR_MODE_2BUTTON_OVERLAY =
WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index 8e65560f7c73..13f1db4a0831 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -39,12 +39,14 @@ public class RecentsAnimationControllerCompat {
public ThumbnailData screenshotTask(int taskId) {
try {
- TaskSnapshot snapshot = mAnimationController.screenshotTask(taskId);
- return snapshot != null ? new ThumbnailData(snapshot) : new ThumbnailData();
+ final TaskSnapshot snapshot = mAnimationController.screenshotTask(taskId);
+ if (snapshot != null) {
+ return new ThumbnailData(snapshot);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Failed to screenshot task", e);
- return new ThumbnailData();
}
+ return new ThumbnailData();
}
public void setInputConsumerEnabled(boolean enabled) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
index c4cd192212a0..48f1b76c1d50 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
@@ -20,6 +20,8 @@ import android.graphics.Rect;
import com.android.systemui.shared.recents.model.ThumbnailData;
+import java.util.HashMap;
+
public interface RecentsAnimationListener {
/**
* Called when the animation into Recents can start. This call is made on the binder thread.
@@ -31,11 +33,11 @@ public interface RecentsAnimationListener {
/**
* Called when the animation into Recents was canceled. This call is made on the binder thread.
*/
- void onAnimationCanceled(ThumbnailData thumbnailData);
+ void onAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas);
/**
* Called when the task of an activity that has been started while the recents animation
* was running becomes ready for control.
*/
- void onTaskAppeared(RemoteAnimationTargetCompat app);
+ void onTasksAppeared(RemoteAnimationTargetCompat[] app);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
index dcc4ea119376..7729a7532f8f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
@@ -26,6 +26,7 @@ import static android.view.WindowManager.TransitionOldType;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import android.annotation.SuppressLint;
+import android.app.IApplicationThread;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArrayMap;
@@ -51,10 +52,10 @@ public class RemoteAnimationAdapterCompat {
private final RemoteTransitionCompat mRemoteTransition;
public RemoteAnimationAdapterCompat(RemoteAnimationRunnerCompat runner, long duration,
- long statusBarTransitionDelay) {
+ long statusBarTransitionDelay, IApplicationThread appThread) {
mWrapped = new RemoteAnimationAdapter(wrapRemoteAnimationRunner(runner), duration,
statusBarTransitionDelay);
- mRemoteTransition = buildRemoteTransition(runner);
+ mRemoteTransition = buildRemoteTransition(runner, appThread);
}
RemoteAnimationAdapter getWrapped() {
@@ -62,9 +63,10 @@ public class RemoteAnimationAdapterCompat {
}
/** Helper to just build a remote transition. Use this if the legacy adapter isn't needed. */
- public static RemoteTransitionCompat buildRemoteTransition(RemoteAnimationRunnerCompat runner) {
+ public static RemoteTransitionCompat buildRemoteTransition(RemoteAnimationRunnerCompat runner,
+ IApplicationThread appThread) {
return new RemoteTransitionCompat(
- new RemoteTransition(wrapRemoteTransition(runner)));
+ new RemoteTransition(wrapRemoteTransition(runner), appThread));
}
public RemoteTransitionCompat getRemoteTransition() {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index 9ec95a3c992d..954cf9fd81a8 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -30,6 +30,7 @@ import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
+import android.app.IApplicationThread;
import android.content.ComponentName;
import android.graphics.Rect;
import android.os.IBinder;
@@ -52,6 +53,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DataClass;
import com.android.systemui.shared.recents.model.ThumbnailData;
+import java.util.ArrayList;
import java.util.concurrent.Executor;
/**
@@ -72,7 +74,7 @@ public class RemoteTransitionCompat implements Parcelable {
}
public RemoteTransitionCompat(@NonNull RemoteTransitionRunner runner,
- @NonNull Executor executor) {
+ @NonNull Executor executor, @Nullable IApplicationThread appThread) {
IRemoteTransition remote = new IRemoteTransition.Stub() {
@Override
public void startAnimation(IBinder transition, TransitionInfo info,
@@ -103,12 +105,12 @@ public class RemoteTransitionCompat implements Parcelable {
finishAdapter));
}
};
- mTransition = new RemoteTransition(remote);
+ mTransition = new RemoteTransition(remote, appThread);
}
/** Constructor specifically for recents animation */
public RemoteTransitionCompat(RecentsAnimationListener recents,
- RecentsAnimationControllerCompat controller) {
+ RecentsAnimationControllerCompat controller, IApplicationThread appThread) {
IRemoteTransition remote = new IRemoteTransition.Stub() {
final RecentsControllerWrap mRecentsSession = new RecentsControllerWrap();
IBinder mToken = null;
@@ -126,7 +128,7 @@ public class RemoteTransitionCompat implements Parcelable {
mToken = transition;
// This transition is for opening recents, so recents is on-top. We want to draw
// the current going-away task on top of recents, though, so move it to front
- WindowContainerToken pausingTask = null;
+ final ArrayList<WindowContainerToken> pausingTasks = new ArrayList<>();
WindowContainerToken pipTask = null;
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
@@ -137,7 +139,8 @@ public class RemoteTransitionCompat implements Parcelable {
if (taskInfo == null) {
continue;
}
- pausingTask = taskInfo.token;
+ // Add to front since we are iterating backwards.
+ pausingTasks.add(0, taskInfo.token);
if (taskInfo.pictureInPictureParams != null
&& taskInfo.pictureInPictureParams.isAutoEnterEnabled()) {
pipTask = taskInfo.token;
@@ -149,7 +152,7 @@ public class RemoteTransitionCompat implements Parcelable {
t.setAlpha(wallpapers[i].leash.mSurfaceControl, 1);
}
t.apply();
- mRecentsSession.setup(controller, info, finishedCallback, pausingTask, pipTask,
+ mRecentsSession.setup(controller, info, finishedCallback, pausingTasks, pipTask,
leashMap, mToken);
recents.onAnimationStart(mRecentsSession, apps, wallpapers, new Rect(0, 0, 0, 0),
new Rect());
@@ -168,7 +171,7 @@ public class RemoteTransitionCompat implements Parcelable {
}
}
};
- mTransition = new RemoteTransition(remote);
+ mTransition = new RemoteTransition(remote, appThread);
}
/** Adds a filter check that restricts this remote transition to home open transitions. */
@@ -197,18 +200,18 @@ public class RemoteTransitionCompat implements Parcelable {
static class RecentsControllerWrap extends RecentsAnimationControllerCompat {
private RecentsAnimationControllerCompat mWrapped = null;
private IRemoteTransitionFinishedCallback mFinishCB = null;
- private WindowContainerToken mPausingTask = null;
+ private ArrayList<WindowContainerToken> mPausingTasks = null;
private WindowContainerToken mPipTask = null;
private TransitionInfo mInfo = null;
- private SurfaceControl mOpeningLeash = null;
+ private ArrayList<SurfaceControl> mOpeningLeashes = null;
private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null;
private PictureInPictureSurfaceTransaction mPipTransaction = null;
private IBinder mTransition = null;
void setup(RecentsAnimationControllerCompat wrapped, TransitionInfo info,
- IRemoteTransitionFinishedCallback finishCB, WindowContainerToken pausingTask,
- WindowContainerToken pipTask, ArrayMap<SurfaceControl, SurfaceControl> leashMap,
- IBinder transition) {
+ IRemoteTransitionFinishedCallback finishCB,
+ ArrayList<WindowContainerToken> pausingTasks, WindowContainerToken pipTask,
+ ArrayMap<SurfaceControl, SurfaceControl> leashMap, IBinder transition) {
if (mInfo != null) {
throw new IllegalStateException("Trying to run a new recents animation while"
+ " recents is already active.");
@@ -216,7 +219,7 @@ public class RemoteTransitionCompat implements Parcelable {
mWrapped = wrapped;
mInfo = info;
mFinishCB = finishCB;
- mPausingTask = pausingTask;
+ mPausingTasks = pausingTasks;
mPipTask = pipTask;
mLeashMap = leashMap;
mTransition = transition;
@@ -225,36 +228,57 @@ public class RemoteTransitionCompat implements Parcelable {
@SuppressLint("NewApi")
boolean merge(TransitionInfo info, SurfaceControl.Transaction t,
RecentsAnimationListener recents) {
- TransitionInfo.Change openingTask = null;
+ ArrayList<TransitionInfo.Change> openingTasks = null;
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
if (change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) {
if (change.getTaskInfo() != null) {
- if (openingTask != null) {
- Log.w(TAG, " Expecting to merge a task-open, but got >1 opening "
- + "tasks");
+ if (openingTasks == null) {
+ openingTasks = new ArrayList<>();
}
- openingTask = change;
+ openingTasks.add(change);
}
}
}
- if (openingTask == null) return false;
- mOpeningLeash = openingTask.getLeash();
- if (openingTask.getContainer().equals(mPausingTask)) {
- // In this case, we are "returning" to the already running app, so just consume
+ if (openingTasks == null) return false;
+ int pauseMatches = 0;
+ for (int i = 0; i < openingTasks.size(); ++i) {
+ if (mPausingTasks.contains(openingTasks.get(i).getContainer())) {
+ ++pauseMatches;
+ }
+ if (openingTasks.get(i).getContainer().equals(mPausingTasks.get(i))) {
+ // In this case, we are "returning" to an already running app, so just consume
+ // the merge and do nothing.
+ }
+ }
+ if (pauseMatches > 0) {
+ if (pauseMatches != mPausingTasks.size()) {
+ // We are not really "returning" properly... something went wrong.
+ throw new IllegalStateException("\"Concelling\" a recents transitions by "
+ + "unpausing " + pauseMatches + " apps after pausing "
+ + mPausingTasks.size() + " apps.");
+ }
+ // In this case, we are "returning" to an already running app, so just consume
// the merge and do nothing.
return true;
}
- // We are receiving a new opening task, so convert to onTaskAppeared.
final int layer = mInfo.getChanges().size() * 3;
- final RemoteAnimationTargetCompat target = new RemoteAnimationTargetCompat(
- openingTask, layer, mInfo, t);
- mLeashMap.put(mOpeningLeash, target.leash.mSurfaceControl);
- t.reparent(target.leash.mSurfaceControl, mInfo.getRootLeash());
- t.setLayer(target.leash.mSurfaceControl, layer);
- t.hide(target.leash.mSurfaceControl);
- t.apply();
- recents.onTaskAppeared(target);
+ mOpeningLeashes = new ArrayList<>();
+ final RemoteAnimationTargetCompat[] targets =
+ new RemoteAnimationTargetCompat[openingTasks.size()];
+ for (int i = 0; i < openingTasks.size(); ++i) {
+ mOpeningLeashes.add(openingTasks.get(i).getLeash());
+ // We are receiving new opening tasks, so convert to onTasksAppeared.
+ final RemoteAnimationTargetCompat target = new RemoteAnimationTargetCompat(
+ openingTasks.get(i), layer, mInfo, t);
+ mLeashMap.put(mOpeningLeashes.get(i), target.leash.mSurfaceControl);
+ t.reparent(target.leash.mSurfaceControl, mInfo.getRootLeash());
+ t.setLayer(target.leash.mSurfaceControl, layer);
+ t.hide(target.leash.mSurfaceControl);
+ t.apply();
+ targets[i] = target;
+ }
+ recents.onTasksAppeared(targets);
return true;
}
@@ -291,21 +315,26 @@ public class RemoteTransitionCompat implements Parcelable {
}
if (mWrapped != null) mWrapped.finish(toHome, sendUserLeaveHint);
try {
- if (!toHome && mPausingTask != null && mOpeningLeash == null) {
+ if (!toHome && mPausingTasks != null && mOpeningLeashes == null) {
// The gesture went back to opening the app rather than continuing with
// recents, so end the transition by moving the app back to the top (and also
// re-showing it's task).
final WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.reorder(mPausingTask, true /* onTop */);
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- t.show(mInfo.getChange(mPausingTask).getLeash());
+ for (int i = mPausingTasks.size() - 1; i >= 0; ++i) {
+ // reverse order so that index 0 ends up on top
+ wct.reorder(mPausingTasks.get(i), true /* onTop */);
+ t.show(mInfo.getChange(mPausingTasks.get(i)).getLeash());
+ }
mFinishCB.onTransitionFinished(wct, t);
} else {
- if (mOpeningLeash != null) {
+ if (mOpeningLeashes != null) {
// TODO: the launcher animation should handle this
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- t.show(mOpeningLeash);
- t.setAlpha(mOpeningLeash, 1.f);
+ for (int i = 0; i < mOpeningLeashes.size(); ++i) {
+ t.show(mOpeningLeashes.get(i));
+ t.setAlpha(mOpeningLeashes.get(i), 1.f);
+ }
t.apply();
}
if (mPipTask != null && mPipTransaction != null) {
@@ -338,9 +367,9 @@ public class RemoteTransitionCompat implements Parcelable {
// Reset all members.
mWrapped = null;
mFinishCB = null;
- mPausingTask = null;
+ mPausingTasks = null;
mInfo = null;
- mOpeningLeash = null;
+ mOpeningLeashes = null;
mLeashMap = null;
mTransition = null;
}
diff --git a/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java b/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java
index 5b6845fcdb4f..acfa3c84a4ba 100644
--- a/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java
+++ b/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java
@@ -16,18 +16,35 @@
package com.android.systemui.flags;
+import static com.android.systemui.flags.FlagManager.ACTION_GET_FLAGS;
+import static com.android.systemui.flags.FlagManager.ACTION_SET_FLAG;
+import static com.android.systemui.flags.FlagManager.FIELD_FLAGS;
+import static com.android.systemui.flags.FlagManager.FIELD_ID;
+import static com.android.systemui.flags.FlagManager.FIELD_VALUE;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Resources;
import android.os.Bundle;
import android.util.Log;
+import androidx.annotation.BoolRes;
+import androidx.annotation.NonNull;
+
+import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.util.settings.SecureSettings;
import org.json.JSONException;
import org.json.JSONObject;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@@ -43,59 +60,73 @@ import javax.inject.Inject;
* To restore a flag back to its default, leave the `--ez value <0|1>` off of the command.
*/
@SysUISingleton
-public class FeatureFlagManager implements FlagReader, FlagWriter {
+public class FeatureFlagManager implements FlagReader, FlagWriter, Dumpable {
private static final String TAG = "SysUIFlags";
- private static final String SYSPROP_PREFIX = "persist.systemui.flag_";
- private static final String FIELD_TYPE = "type";
- private static final String FIELD_ID = "id";
- private static final String FIELD_VALUE = "value";
- private static final String TYPE_BOOLEAN = "boolean";
- private static final String ACTION_SET_FLAG = "com.android.systemui.action.SET_FLAG";
- private static final String FLAGS_PERMISSION = "com.android.systemui.permission.FLAGS";
- private final SystemPropertiesHelper mSystemPropertiesHelper;
-
+ private final FlagManager mFlagManager;
+ private final SecureSettings mSecureSettings;
+ private final Resources mResources;
private final Map<Integer, Boolean> mBooleanFlagCache = new HashMap<>();
@Inject
- public FeatureFlagManager(SystemPropertiesHelper systemPropertiesHelper, Context context) {
- mSystemPropertiesHelper = systemPropertiesHelper;
-
- IntentFilter filter = new IntentFilter(ACTION_SET_FLAG);
- context.registerReceiver(mReceiver, filter, FLAGS_PERMISSION, null);
+ public FeatureFlagManager(
+ FlagManager flagManager,
+ Context context,
+ SecureSettings secureSettings,
+ @Main Resources resources,
+ DumpManager dumpManager) {
+ mFlagManager = flagManager;
+ mSecureSettings = secureSettings;
+ mResources = resources;
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_SET_FLAG);
+ filter.addAction(ACTION_GET_FLAGS);
+ context.registerReceiver(mReceiver, filter, null, null);
+ dumpManager.registerDumpable(TAG, this);
}
- /** Return a {@link BooleanFlag}'s value. */
- public boolean isEnabled(int id, boolean defaultValue) {
+ @Override
+ public boolean isEnabled(BooleanFlag flag) {
+ int id = flag.getId();
if (!mBooleanFlagCache.containsKey(id)) {
- Boolean result = isEnabledInternal(id);
- mBooleanFlagCache.put(id, result == null ? defaultValue : result);
+ boolean def = flag.getDefault();
+ if (flag.hasResourceOverride()) {
+ try {
+ def = isEnabledInOverlay(flag.getResourceOverride());
+ } catch (Resources.NotFoundException e) {
+ // no-op
+ }
+ }
+
+ mBooleanFlagCache.put(id, isEnabled(id, def));
}
return mBooleanFlagCache.get(id);
}
+ /** Return a {@link BooleanFlag}'s value. */
+ @Override
+ public boolean isEnabled(int id, boolean defaultValue) {
+ Boolean result = isEnabledInternal(id);
+ return result == null ? defaultValue : result;
+ }
+
/** Returns the stored value or null if not set. */
private Boolean isEnabledInternal(int id) {
- String data = mSystemPropertiesHelper.get(keyToSysPropKey(id));
- if (data.isEmpty()) {
- return null;
- }
- JSONObject json;
try {
- json = new JSONObject(data);
- if (!assertType(json, TYPE_BOOLEAN)) {
- return null;
- }
-
- return json.getBoolean(FIELD_VALUE);
- } catch (JSONException e) {
- eraseInternal(id); // Don't restart SystemUI in this case.
+ return mFlagManager.isEnabled(id);
+ } catch (Exception e) {
+ eraseInternal(id);
}
return null;
}
+ private boolean isEnabledInOverlay(@BoolRes int resId) {
+ return mResources.getBoolean(resId);
+ }
+
/** Set whether a given {@link BooleanFlag} is enabled or not. */
+ @Override
public void setEnabled(int id, boolean value) {
Boolean currentValue = isEnabledInternal(id);
if (currentValue != null && currentValue == value) {
@@ -104,9 +135,9 @@ public class FeatureFlagManager implements FlagReader, FlagWriter {
JSONObject json = new JSONObject();
try {
- json.put(FIELD_TYPE, TYPE_BOOLEAN);
+ json.put(FlagManager.FIELD_TYPE, FlagManager.TYPE_BOOLEAN);
json.put(FIELD_VALUE, value);
- mSystemPropertiesHelper.set(keyToSysPropKey(id), json.toString());
+ mSecureSettings.putString(mFlagManager.keyToSettingsPrefix(id), json.toString());
Log.i(TAG, "Set id " + id + " to " + value);
restartSystemUI();
} catch (JSONException e) {
@@ -123,13 +154,19 @@ public class FeatureFlagManager implements FlagReader, FlagWriter {
/** Works just like {@link #eraseFlag(int)} except that it doesn't restart SystemUI. */
private void eraseInternal(int id) {
// We can't actually "erase" things from sysprops, but we can set them to empty!
- mSystemPropertiesHelper.set(keyToSysPropKey(id), "");
+ mSecureSettings.putString(mFlagManager.keyToSettingsPrefix(id), "");
Log.i(TAG, "Erase id " + id);
}
- public void addListener(Listener run) {}
+ @Override
+ public void addListener(Listener run) {
+ mFlagManager.addListener(run);
+ }
- public void removeListener(Listener run) {}
+ @Override
+ public void removeListener(Listener run) {
+ mFlagManager.removeListener(run);
+ }
private void restartSystemUI() {
Log.i(TAG, "Restarting SystemUI");
@@ -137,18 +174,6 @@ public class FeatureFlagManager implements FlagReader, FlagWriter {
System.exit(0);
}
- private static String keyToSysPropKey(int key) {
- return SYSPROP_PREFIX + key;
- }
-
- private static boolean assertType(JSONObject json, String type) {
- try {
- return json.getString(FIELD_TYPE).equals(TYPE_BOOLEAN);
- } catch (JSONException e) {
- return false;
- }
- }
-
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -156,9 +181,15 @@ public class FeatureFlagManager implements FlagReader, FlagWriter {
if (action == null) {
return;
}
-
if (ACTION_SET_FLAG.equals(action)) {
handleSetFlag(intent.getExtras());
+ } else if (ACTION_GET_FLAGS.equals(action)) {
+ Map<Integer, Flag<?>> knownFlagMap = Flags.collectFlags();
+ ArrayList<Flag<?>> flags = new ArrayList<>(knownFlagMap.values());
+ Bundle extras = getResultExtras(true);
+ if (extras != null) {
+ extras.putParcelableArrayList(FIELD_FLAGS, flags);
+ }
}
}
@@ -186,4 +217,17 @@ public class FeatureFlagManager implements FlagReader, FlagWriter {
}
}
};
+
+ @Override
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.println("can override: true");
+ ArrayList<String> flagStrings = new ArrayList<>(mBooleanFlagCache.size());
+ for (Map.Entry<Integer, Boolean> entry : mBooleanFlagCache.entrySet()) {
+ flagStrings.add(" sysui_flag_" + entry.getKey() + ": " + entry.getValue());
+ }
+ flagStrings.sort(String.CASE_INSENSITIVE_ORDER);
+ for (String flagString : flagStrings) {
+ pw.println(flagString);
+ }
+ }
}
diff --git a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
new file mode 100644
index 000000000000..bee4d7d3b411
--- /dev/null
+++ b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
@@ -0,0 +1,35 @@
+/*
+ * 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 android.content.Context
+import android.os.Handler
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.util.settings.SettingsUtilModule
+import dagger.Module
+import dagger.Provides
+
+@Module(includes = [
+ SettingsUtilModule::class
+])
+object FlagsModule {
+ @JvmStatic
+ @Provides
+ fun provideFlagManager(context: Context, @Main handler: Handler): FlagManager {
+ return FlagManager(context, handler)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src-release/com/android/systemui/flags/FeatureFlagManager.java b/packages/SystemUI/src-release/com/android/systemui/flags/FeatureFlagManager.java
new file mode 100644
index 000000000000..0934b32a71e4
--- /dev/null
+++ b/packages/SystemUI/src-release/com/android/systemui/flags/FeatureFlagManager.java
@@ -0,0 +1,74 @@
+/*
+ * 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 android.util.SparseBooleanArray;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.Dumpable;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dump.DumpManager;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+import javax.inject.Inject;
+
+/**
+ * Default implementation of the a Flag manager that returns default values for release builds
+ *
+ * There's a version of this file in src-debug which allows overriding, and has documentation about
+ * how to set flags.
+ */
+@SysUISingleton
+public class FeatureFlagManager implements FlagReader, FlagWriter, Dumpable {
+ SparseBooleanArray mAccessedFlags = new SparseBooleanArray();
+ @Inject
+ public FeatureFlagManager(DumpManager dumpManager) {
+ dumpManager.registerDumpable("SysUIFlags", this);
+ }
+
+ @Override
+ public void addListener(Listener run) {}
+
+ @Override
+ public void removeListener(Listener run) {}
+
+ @Override
+ public boolean isEnabled(BooleanFlag flag) {
+ return isEnabled(flag.getId(), flag.getDefault());
+ }
+
+ @Override
+ public boolean isEnabled(int key, boolean defaultValue) {
+ mAccessedFlags.append(key, defaultValue);
+ return defaultValue;
+ }
+ @Override
+ public void setEnabled(int key, boolean value) {}
+
+ @Override
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.println("can override: false");
+ int size = mAccessedFlags.size();
+ for (int i = 0; i < size; i++) {
+ pw.println(" sysui_flag_" + mAccessedFlags.keyAt(i)
+ + ": " + mAccessedFlags.valueAt(i));
+ }
+ }
+}
diff --git a/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt b/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt
new file mode 100644
index 000000000000..7647135bd7fd
--- /dev/null
+++ b/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt
@@ -0,0 +1,22 @@
+/*
+ * 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 dagger.Module
+
+@Module
+object FlagsModule \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
index a383cab94c36..ac463ebc1c97 100644
--- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
@@ -31,7 +31,6 @@ import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.ViewController;
@@ -49,7 +48,6 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie
private final StatusBarStateController mStatusBarStateController;
private final BroadcastDispatcher mBroadcastDispatcher;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final KeyguardBypassController mBypassController;
private final BatteryController mBatteryController;
private final int mDozingColor = Color.WHITE;
private int mLockScreenColor;
@@ -71,14 +69,12 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie
BroadcastDispatcher broadcastDispatcher,
BatteryController batteryController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- KeyguardBypassController bypassController,
@Main Resources resources
) {
super(view);
mStatusBarStateController = statusBarStateController;
mBroadcastDispatcher = broadcastDispatcher;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mBypassController = bypassController;
mBatteryController = batteryController;
mBurmeseNumerals = mBurmeseNf.format(FORMAT_NUMBER);
diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java
index ef3104a21708..2a0c2855c3b2 100644
--- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java
+++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java
@@ -27,7 +27,6 @@ import android.util.AttributeSet;
import android.widget.TextView;
import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
import java.util.Calendar;
import java.util.Locale;
@@ -111,6 +110,28 @@ public class AnimatableClockView extends TextView {
super.onDetachedFromWindow();
}
+ int getDozingWeight() {
+ if (useBoldedVersion()) {
+ return mDozingWeight + 100;
+ }
+ return mDozingWeight;
+ }
+
+ int getLockScreenWeight() {
+ if (useBoldedVersion()) {
+ return mLockScreenWeight + 100;
+ }
+ return mLockScreenWeight;
+ }
+
+ /**
+ * Whether to use a bolded version based on the user specified fontWeightAdjustment.
+ */
+ boolean useBoldedVersion() {
+ // "Bold text" fontWeightAdjustment is 300.
+ return getResources().getConfiguration().fontWeightAdjustment > 100;
+ }
+
void refreshTime() {
mTime.setTimeInMillis(System.currentTimeMillis());
setText(DateFormat.format(mFormat, mTime));
@@ -162,7 +183,7 @@ public class AnimatableClockView extends TextView {
}
setTextStyle(
- mDozingWeight,
+ getDozingWeight(),
-1 /* text size, no update */,
mLockScreenColor,
false /* animate */,
@@ -171,7 +192,7 @@ public class AnimatableClockView extends TextView {
null /* onAnimationEnd */);
setTextStyle(
- mLockScreenWeight,
+ getLockScreenWeight(),
-1 /* text size, no update */,
mLockScreenColor,
true, /* animate */
@@ -180,35 +201,22 @@ public class AnimatableClockView extends TextView {
null /* onAnimationEnd */);
}
- void animateDisappear() {
- if (mTextAnimator == null) {
- return;
- }
-
- setTextStyle(
- 0 /* weight */,
- -1 /* text size, no update */,
- null /* color, no update */,
- true /* animate */,
- KeyguardBypassController.BYPASS_FADE_DURATION /* duration */,
- 0 /* delay */,
- null /* onAnimationEnd */);
- }
-
void animateCharge(DozeStateGetter dozeStateGetter) {
if (mTextAnimator == null || mTextAnimator.isRunning()) {
// Skip charge animation if dozing animation is already playing.
return;
}
Runnable startAnimPhase2 = () -> setTextStyle(
- dozeStateGetter.isDozing() ? mDozingWeight : mLockScreenWeight/* weight */,
+ dozeStateGetter.isDozing() ? getDozingWeight() : getLockScreenWeight() /* weight */,
-1,
null,
true /* animate */,
CHARGE_ANIM_DURATION_PHASE_1,
0 /* delay */,
null /* onAnimationEnd */);
- setTextStyle(dozeStateGetter.isDozing() ? mLockScreenWeight : mDozingWeight/* weight */,
+ setTextStyle(dozeStateGetter.isDozing()
+ ? getLockScreenWeight()
+ : getDozingWeight()/* weight */,
-1,
null,
true /* animate */,
@@ -218,7 +226,7 @@ public class AnimatableClockView extends TextView {
}
void animateDoze(boolean isDozing, boolean animate) {
- setTextStyle(isDozing ? mDozingWeight : mLockScreenWeight /* weight */,
+ setTextStyle(isDozing ? getDozingWeight() : getLockScreenWeight() /* weight */,
-1,
isDozing ? mDozingColor : mLockScreenColor,
animate,
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
index cfef6cb399ed..907943a9203d 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
@@ -261,8 +261,10 @@ public class CarrierTextManager {
mCarrierTextCallback = callback;
if (mNetworkSupported.get()) {
// Keyguard update monitor expects callbacks from main thread
- mMainExecutor.execute(() -> mKeyguardUpdateMonitor.registerCallback(mCallback));
- mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
+ mMainExecutor.execute(() -> {
+ mKeyguardUpdateMonitor.registerCallback(mCallback);
+ mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
+ });
mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mPhoneStateListener);
} else {
// Don't listen and clear out the text when the device isn't a phone.
@@ -272,8 +274,10 @@ public class CarrierTextManager {
}
} else {
mCarrierTextCallback = null;
- mMainExecutor.execute(() -> mKeyguardUpdateMonitor.removeCallback(mCallback));
- mWakefulnessLifecycle.removeObserver(mWakefulnessObserver);
+ mMainExecutor.execute(() -> {
+ mKeyguardUpdateMonitor.removeCallback(mCallback);
+ mWakefulnessLifecycle.removeObserver(mWakefulnessObserver);
+ });
mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mPhoneStateListener);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 1931c0a1645c..905495d369a0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -167,7 +167,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mBroadcastDispatcher,
mBatteryController,
mKeyguardUpdateMonitor,
- mBypassController,
mResources);
mClockViewController.init();
@@ -178,7 +177,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mBroadcastDispatcher,
mBatteryController,
mKeyguardUpdateMonitor,
- mBypassController,
mResources);
mLargeClockViewController.init();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
new file mode 100644
index 000000000000..cb25e1a2a40e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
@@ -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.keyguard
+
+import android.content.Context
+import android.view.View
+import android.view.ViewGroup
+import com.android.systemui.R
+import com.android.systemui.unfold.SysUIUnfoldScope
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
+import javax.inject.Inject
+
+/**
+ * Translates items away/towards the hinge when the device is opened/closed. This is controlled by
+ * the set of ids, which also dictact which direction to move and when, via a filter function.
+ */
+@SysUIUnfoldScope
+class KeyguardUnfoldTransition @Inject constructor(
+ val context: Context,
+ val unfoldProgressProvider: NaturalRotationUnfoldProgressProvider
+) {
+
+ companion object {
+ final val LEFT = -1
+ final val RIGHT = 1
+ }
+
+ private val filterSplitShadeOnly = { !statusViewCentered }
+ private val filterNever = { true }
+
+ private val ids = setOf(
+ Triple(R.id.keyguard_status_area, LEFT, filterNever),
+ Triple(R.id.controls_button, LEFT, filterNever),
+ Triple(R.id.lockscreen_clock_view_large, LEFT, filterSplitShadeOnly),
+ Triple(R.id.lockscreen_clock_view, LEFT, filterNever),
+ Triple(R.id.notification_stack_scroller, RIGHT, filterSplitShadeOnly),
+ Triple(R.id.wallet_button, RIGHT, filterNever)
+ )
+ private var parent: ViewGroup? = null
+ private var views = listOf<Triple<View, Int, () -> Boolean>>()
+ private var xTranslationMax = 0f
+
+ /**
+ * Certain views only need to move if they are not currently centered
+ */
+ var statusViewCentered = false
+
+ init {
+ unfoldProgressProvider.addCallback(
+ object : TransitionProgressListener {
+ override fun onTransitionStarted() {
+ findViews()
+ }
+
+ override fun onTransitionProgress(progress: Float) {
+ translateViews(progress)
+ }
+
+ override fun onTransitionFinished() {
+ translateViews(1f)
+ }
+ }
+ )
+ }
+
+ /**
+ * Relies on the [parent] to locate views to translate
+ */
+ fun setup(parent: ViewGroup) {
+ this.parent = parent
+ xTranslationMax = context.resources.getDimensionPixelSize(
+ R.dimen.keyguard_unfold_translation_x).toFloat()
+ }
+
+ /**
+ * Manually translate views based on set direction. At the moment
+ * [UnfoldMoveFromCenterAnimator] exists but moves all views a dynamic distance
+ * from their mid-point. This code instead will only ever translate by a fixed amount.
+ */
+ private fun translateViews(progress: Float) {
+ val xTrans = progress * xTranslationMax - xTranslationMax
+ views.forEach {
+ (view, direction, pred) -> if (pred()) {
+ view.setTranslationX(xTrans * direction)
+ }
+ }
+ }
+
+ private fun findViews() {
+ parent?.let { p ->
+ views = ids.mapNotNull {
+ (id, direction, pred) -> p.findViewById<View>(id)?.let {
+ Triple(it, direction, pred)
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index a41a49799c2d..d27bc675ecb8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -102,7 +102,6 @@ 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;
@@ -323,7 +322,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private boolean mLockIconPressed;
private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private final Executor mBackgroundExecutor;
- private int mLockScreenMode;
/**
* Short delay before restarting fingerprint authentication after a successful try. This should
@@ -1736,11 +1734,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
DumpManager dumpManager,
RingerModeTracker ringerModeTracker,
@Background Executor backgroundExecutor,
+ @Main Executor mainExecutor,
StatusBarStateController statusBarStateController,
LockPatternUtils lockPatternUtils,
AuthController authController,
TelephonyListenerManager telephonyListenerManager,
- FeatureFlags featureFlags,
InteractionJankMonitor interactionJankMonitor,
LatencyTracker latencyTracker) {
mContext = context;
@@ -1966,6 +1964,17 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mBiometricManager.registerEnabledOnKeyguardCallback(mBiometricEnabledCallback);
}
+ // in case authenticators aren't registered yet at this point:
+ mAuthController.addCallback(new AuthController.Callback() {
+ @Override
+ public void onAllAuthenticatorsRegistered() {
+ }
+
+ @Override
+ public void onEnrollmentsChanged() {
+ mainExecutor.execute(() -> updateBiometricListeningState());
+ }
+ });
updateBiometricListeningState();
if (mFpm != null) {
mFpm.addLockoutResetCallback(mFingerprintLockoutResetCallback);
@@ -2035,17 +2044,17 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
/**
- * @return true if there's at least one udfps enrolled
+ * @return true if there's at least one udfps enrolled for the current user.
*/
public boolean isUdfpsEnrolled() {
return mIsUdfpsEnrolled;
}
/**
- * @return if udfps is available on this device. will return true even if the user hasn't
- * enrolled udfps.
+ * @return true if udfps HW is supported on this device. Can return true even if the user has
+ * not enrolled udfps. This may be false if called before onAllAuthenticatorsRegistered.
*/
- public boolean isUdfpsAvailable() {
+ public boolean isUdfpsSupported() {
return mAuthController.getUdfpsProps() != null
&& !mAuthController.getUdfpsProps().isEmpty();
}
@@ -2092,9 +2101,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
return;
}
- // TODO: Add support for multiple fingerprint sensors, b/173730729
updateUdfpsEnrolled(getCurrentUser());
- final boolean shouldListenForFingerprint = shouldListenForFingerprint(isUdfpsEnrolled());
+ final boolean shouldListenForFingerprint = shouldListenForFingerprint(isUdfpsSupported());
final boolean runningOrRestarting = mFingerprintRunningState == BIOMETRIC_STATE_RUNNING
|| mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING;
if (runningOrRestarting && !shouldListenForFingerprint) {
@@ -2399,7 +2407,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
} else {
mFpm.authenticate(null /* crypto */, mFingerprintCancelSignal,
mFingerprintAuthenticationCallback, null /* handler */,
- FingerprintManager.SENSOR_ID_ANY, userId);
+ FingerprintManager.SENSOR_ID_ANY, userId, 0 /* flags */);
}
setFingerprintRunningState(BIOMETRIC_STATE_RUNNING);
}
@@ -2982,7 +2990,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
/**
* Register to receive notifications about general keyguard information
- * (see {@link InfoCallback}.
+ * (see {@link KeyguardUpdateMonitorCallback}.
*
* @param callback The callback to register
*/
@@ -3380,11 +3388,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
+ " expected=" + (shouldListenForFingerprint(isUdfpsEnrolled()) ? 1 : 0));
pw.println(" strongAuthFlags=" + Integer.toHexString(strongAuthFlags));
pw.println(" trustManaged=" + getUserTrustIsManaged(userId));
- pw.println(" udfpsEnrolled=" + isUdfpsEnrolled());
pw.println(" mFingerprintLockedOut=" + mFingerprintLockedOut);
pw.println(" mFingerprintLockedOutPermanent=" + mFingerprintLockedOutPermanent);
pw.println(" enabledByUser=" + mBiometricEnabledForUser.get(userId));
- if (isUdfpsEnrolled()) {
+ if (isUdfpsSupported()) {
+ pw.println(" udfpsEnrolled=" + isUdfpsEnrolled());
pw.println(" shouldListenForUdfps=" + shouldListenForFingerprint(true));
pw.println(" bouncerVisible=" + mBouncer);
pw.println(" mStatusBarState="
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
index db729da9c8bf..fcf1b2c9500a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
@@ -20,11 +20,14 @@ import android.os.Bundle;
import android.view.View;
import android.view.ViewRootImpl;
+import androidx.annotation.Nullable;
+
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
/**
* Interface to control Keyguard View. It should be implemented by KeyguardViewManagers, which
@@ -184,14 +187,10 @@ public interface KeyguardViewController {
/**
* Registers the StatusBar to which this Keyguard View is mounted.
- * @param statusBar
- * @param notificationPanelViewController
- * @param biometricUnlockController
- * @param notificationContainer
- * @param bypassController
*/
void registerStatusBar(StatusBar statusBar,
NotificationPanelViewController notificationPanelViewController,
+ @Nullable PanelExpansionStateManager panelExpansionStateManager,
BiometricUnlockController biometricUnlockController,
View notificationContainer,
KeyguardBypassController bypassController);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
index e115c342c4fe..b77db8f97ccb 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
@@ -121,6 +121,13 @@ public class KeyguardVisibilityHelper {
.setStartDelay(delay);
}
animator.start();
+ } else if (mUnlockedScreenOffAnimationController.shouldAnimateInKeyguard()) {
+ mKeyguardViewVisibilityAnimating = true;
+
+ // Ask the screen off animation controller to animate the keyguard visibility for us
+ // since it may need to be cancelled due to keyguard lifecycle events.
+ mUnlockedScreenOffAnimationController.animateInKeyguard(
+ mView, mAnimateKeyguardStatusViewVisibleEndRunnable);
} else if (mLastOccludedState && !isOccluded) {
// An activity was displayed over the lock screen, and has now gone away
mView.setVisibility(View.VISIBLE);
@@ -132,13 +139,6 @@ public class KeyguardVisibilityHelper {
.alpha(1f)
.withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable)
.start();
- } else if (mUnlockedScreenOffAnimationController.shouldAnimateInKeyguard()) {
- mKeyguardViewVisibilityAnimating = true;
-
- // Ask the screen off animation controller to animate the keyguard visibility for us
- // since it may need to be cancelled due to keyguard lifecycle events.
- mUnlockedScreenOffAnimationController.animateInKeyguard(
- mView, mAnimateKeyguardStatusViewVisibleEndRunnable);
} else {
mView.setVisibility(View.VISIBLE);
mView.setAlpha(1f);
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 3c80a186a4a7..88476398e09d 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -43,6 +43,7 @@ import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -85,7 +86,6 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
private static final float sDefaultDensity =
(float) DisplayMetrics.DENSITY_DEVICE_STABLE / (float) DisplayMetrics.DENSITY_DEFAULT;
private static final int sLockIconRadiusPx = (int) (sDefaultDensity * 36);
- private static final float sDistAboveKgBottomAreaPx = sDefaultDensity * 12;
private static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES =
new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
@@ -126,7 +126,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
private boolean mUdfpsSupported;
private float mHeightPixels;
private float mWidthPixels;
- private int mBottomPadding; // in pixels
+ private int mBottomPaddingPx;
private boolean mShowUnlockIcon;
private boolean mShowLockIcon;
@@ -347,11 +347,11 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
}
private void updateConfiguration() {
- final DisplayMetrics metrics = mView.getContext().getResources().getDisplayMetrics();
- mWidthPixels = metrics.widthPixels;
- mHeightPixels = metrics.heightPixels;
- mBottomPadding = mView.getContext().getResources().getDimensionPixelSize(
- R.dimen.lock_icon_margin_bottom);
+ WindowManager windowManager = getContext().getSystemService(WindowManager.class);
+ Rect bounds = windowManager.getCurrentWindowMetrics().getBounds();
+ mWidthPixels = bounds.right;
+ mHeightPixels = bounds.bottom;
+ mBottomPaddingPx = getResources().getDimensionPixelSize(R.dimen.lock_icon_margin_bottom);
mUnlockedLabel = mView.getContext().getResources().getString(
R.string.accessibility_unlock_button);
@@ -370,8 +370,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
} else {
mView.setCenterLocation(
new PointF(mWidthPixels / 2,
- mHeightPixels - mBottomPadding - sDistAboveKgBottomAreaPx
- - sLockIconRadiusPx), sLockIconRadiusPx);
+ mHeightPixels - mBottomPaddingPx - sLockIconRadiusPx),
+ sLockIconRadiusPx);
}
mView.getHitRect(mSensorTouchLocation);
@@ -435,7 +435,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
boolean wasUdfpsSupported = mUdfpsSupported;
boolean wasUdfpsEnrolled = mUdfpsEnrolled;
- mUdfpsSupported = mAuthController.getUdfpsSensorLocation() != null;
+ mUdfpsSupported = mKeyguardUpdateMonitor.isUdfpsSupported();
mView.setUseBackground(mUdfpsSupported);
mUdfpsEnrolled = mKeyguardUpdateMonitor.isUdfpsEnrolled();
@@ -695,11 +695,20 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() {
@Override
public void onAllAuthenticatorsRegistered() {
- // must be called from the main thread since it may update the views
- mExecutor.execute(() -> {
- updateIsUdfpsEnrolled();
- updateConfiguration();
- });
+ updateUdfpsConfig();
+ }
+
+ @Override
+ public void onEnrollmentsChanged() {
+ updateUdfpsConfig();
}
};
+
+ private void updateUdfpsConfig() {
+ // must be called from the main thread since it may update the views
+ mExecutor.execute(() -> {
+ updateIsUdfpsEnrolled();
+ updateConfiguration();
+ });
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 4e4034a28cb0..925fc5c3e268 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -105,7 +105,6 @@ import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.phone.StatusBarWindowController;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
@@ -129,6 +128,7 @@ import com.android.systemui.statusbar.policy.SmartReplyConstants;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.systemui.telephony.TelephonyListenerManager;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.tuner.TunablePadding.TunablePaddingService;
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 80c3616f693e..e566ccb49e3b 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -534,6 +534,9 @@ public class ScreenDecorations extends SystemUI implements Tunable {
lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS
| WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+ // FLAG_SLIPPERY can only be set by trusted overlays
+ lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+
if (!DEBUG_SCREENSHOT_ROUNDED_CORNERS) {
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index c64f416f9672..e96e924d557f 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -30,7 +30,9 @@ import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.dagger.WMComponent;
import com.android.systemui.navigationbar.gestural.BackGestureTfClassifierProvider;
import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider;
+import com.android.wm.shell.transition.ShellTransitions;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.recents.RecentTasks;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
@@ -119,7 +121,8 @@ public class SystemUIFactory {
.setTransitions(mWMComponent.getTransitions())
.setStartingSurface(mWMComponent.getStartingSurface())
.setDisplayAreaHelper(mWMComponent.getDisplayAreaHelper())
- .setTaskSurfaceHelper(mWMComponent.getTaskSurfaceHelper());
+ .setTaskSurfaceHelper(mWMComponent.getTaskSurfaceHelper())
+ .setRecentTasks(mWMComponent.getRecentTasks());
} else {
// TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
// is separating this logic into newly creating SystemUITestsFactory.
@@ -133,10 +136,11 @@ public class SystemUIFactory {
.setShellCommandHandler(Optional.ofNullable(null))
.setAppPairs(Optional.ofNullable(null))
.setTaskViewFactory(Optional.ofNullable(null))
- .setTransitions(Transitions.createEmptyForTesting())
+ .setTransitions(new ShellTransitions() {})
.setDisplayAreaHelper(Optional.ofNullable(null))
.setStartingSurface(Optional.ofNullable(null))
- .setTaskSurfaceHelper(Optional.ofNullable(null));
+ .setTaskSurfaceHelper(Optional.ofNullable(null))
+ .setRecentTasks(Optional.ofNullable(null));
}
mSysUIComponent = builder.build();
if (mInitializeComponents) {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
index 59d9aff2ef46..d2703f5e73a2 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
@@ -22,6 +22,7 @@ import static android.util.MathUtils.sq;
import static android.view.WindowInsets.Type.displayCutout;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.systemBars;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
import static java.util.Objects.requireNonNull;
@@ -659,6 +660,7 @@ public class AccessibilityFloatingMenuView extends FrameLayout
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
PixelFormat.TRANSLUCENT);
params.receiveInsetsIgnoringZOrder = true;
+ params.privateFlags |= PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
params.windowAnimations = android.R.style.Animation_Translucent;
params.gravity = Gravity.START | Gravity.TOP;
params.x = (mAlignment == Alignment.RIGHT) ? getMaxWindowX() : getMinWindowX();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index f4b446b50c9e..1226dca1f306 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -142,6 +142,10 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
mUdfpsEnrolledForUser.put(userId, hasEnrollments);
}
}
+
+ for (Callback cb : mCallbacks) {
+ cb.onEnrollmentsChanged();
+ }
}
};
@@ -844,5 +848,11 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
* registered before this call, this callback will never be triggered.
*/
void onAllAuthenticatorsRegistered();
+
+ /**
+ * Called when UDFPS enrollments have changed. This is called after boot and on changes to
+ * enrollment.
+ */
+ void onEnrollmentsChanged();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index 8b04bf59658a..90a1e5e64daf 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -16,6 +16,8 @@
package com.android.systemui.biometrics
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.PointF
@@ -29,7 +31,9 @@ import com.android.settingslib.Utils
import com.android.systemui.R
import com.android.systemui.animation.Interpolators
import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.CircleReveal
+import com.android.systemui.statusbar.LiftReveal
import com.android.systemui.statusbar.LightRevealEffect
import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.commandline.Command
@@ -41,13 +45,10 @@ import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarS
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.ViewController
+import com.android.systemui.util.leak.RotationUtils
import java.io.PrintWriter
import javax.inject.Inject
import javax.inject.Provider
-import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.util.leak.RotationUtils
-
-private const val WAKE_AND_UNLOCK_FADE_DURATION = 180L
/***
* Controls the ripple effect that shows when authentication is successful.
@@ -141,11 +142,12 @@ class AuthRippleController @Inject constructor(
private fun showUnlockedRipple() {
notificationShadeWindowController.setForcePluginOpen(true, this)
- val useCircleReveal = circleReveal != null && biometricUnlockController.isWakeAndUnlock
val lightRevealScrim = statusBar.lightRevealScrim
- if (useCircleReveal) {
- lightRevealScrim?.revealEffect = circleReveal!!
- startLightRevealScrimOnKeyguardFadingAway = true
+ if (statusBarStateController.isDozing || biometricUnlockController.isWakeAndUnlock) {
+ circleReveal?.let {
+ lightRevealScrim?.revealEffect = it
+ startLightRevealScrimOnKeyguardFadingAway = true
+ }
}
mView.startUnlockedRipple(
@@ -160,19 +162,29 @@ class AuthRippleController @Inject constructor(
if (keyguardStateController.isKeyguardFadingAway) {
val lightRevealScrim = statusBar.lightRevealScrim
if (startLightRevealScrimOnKeyguardFadingAway && lightRevealScrim != null) {
- val revealAnimator = ValueAnimator.ofFloat(.1f, 1f).apply {
+ ValueAnimator.ofFloat(.1f, 1f).apply {
interpolator = Interpolators.LINEAR_OUT_SLOW_IN
duration = RIPPLE_ANIMATION_DURATION
startDelay = keyguardStateController.keyguardFadingAwayDelay
addUpdateListener { animator ->
if (lightRevealScrim.revealEffect != circleReveal) {
- // if the something else took over the reveal, let's do nothing.
+ // if something else took over the reveal, let's do nothing.
return@addUpdateListener
}
lightRevealScrim.revealAmount = animator.animatedValue as Float
}
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ // Reset light reveal scrim to the default, so the StatusBar
+ // can handle any subsequent light reveal changes
+ // (ie: from dozing changes)
+ if (lightRevealScrim.revealEffect == circleReveal) {
+ lightRevealScrim.revealEffect = LiftReveal
+ }
+ }
+ })
+ start()
}
- revealAnimator.start()
startLightRevealScrimOnKeyguardFadingAway = false
}
}
@@ -292,10 +304,16 @@ class AuthRippleController @Inject constructor(
}
}
- private val authControllerCallback = AuthController.Callback {
- updateSensorLocation()
- updateUdfpsDependentParams()
- }
+ private val authControllerCallback =
+ object : AuthController.Callback {
+ override fun onAllAuthenticatorsRegistered() {
+ updateSensorLocation()
+ updateUdfpsDependentParams()
+ }
+
+ override fun onEnrollmentsChanged() {
+ }
+ }
private fun updateUdfpsDependentParams() {
authController.udfpsProps?.let {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt
index b7398d86c16e..7bb4708443e9 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt
@@ -15,6 +15,9 @@
*/
package com.android.systemui.biometrics
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.app.ActivityTaskManager
import android.content.Context
import android.graphics.PixelFormat
import android.graphics.PorterDuff
@@ -22,6 +25,7 @@ import android.graphics.PorterDuffColorFilter
import android.graphics.Rect
import android.hardware.biometrics.BiometricOverlayConstants
import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
import android.hardware.display.DisplayManager
import android.hardware.fingerprint.FingerprintManager
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
@@ -33,6 +37,8 @@ import android.view.Gravity
import android.view.LayoutInflater
import android.view.Surface
import android.view.View
+import android.view.ViewPropertyAnimator
+import android.view.WindowInsets
import android.view.WindowManager
import androidx.annotation.RawRes
import com.airbnb.lottie.LottieAnimationView
@@ -42,6 +48,7 @@ import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.recents.OverviewProxyService
import com.android.systemui.util.concurrency.DelayableExecutor
import javax.inject.Inject
@@ -56,9 +63,11 @@ class SidefpsController @Inject constructor(
private val layoutInflater: LayoutInflater,
fingerprintManager: FingerprintManager?,
private val windowManager: WindowManager,
- @Main mainExecutor: DelayableExecutor,
+ private val activityTaskManager: ActivityTaskManager,
+ overviewProxyService: OverviewProxyService,
displayManager: DisplayManager,
- @Main handler: Handler
+ @Main mainExecutor: DelayableExecutor,
+ @Main private val handler: Handler
) {
@VisibleForTesting
val sensorProps: FingerprintSensorPropertiesInternal = fingerprintManager
@@ -74,15 +83,33 @@ class SidefpsController @Inject constructor(
BiometricDisplayListener.SensorType.SideFingerprint(sensorProps)
) { onOrientationChanged() }
+ @VisibleForTesting
+ val overviewProxyListener = object : OverviewProxyService.OverviewProxyListener {
+ override fun onTaskbarStatusUpdated(visible: Boolean, stashed: Boolean) {
+ overlayView?.let { view ->
+ handler.postDelayed({ updateOverlayVisibility(view) }, 500)
+ }
+ }
+ }
+
+ private val animationDuration =
+ context.resources.getInteger(android.R.integer.config_mediumAnimTime).toLong()
+
+ private var overlayHideAnimator: ViewPropertyAnimator? = null
+
private var overlayView: View? = null
set(value) {
field?.let { oldView ->
windowManager.removeView(oldView)
orientationListener.disable()
}
+ overlayHideAnimator?.cancel()
+ overlayHideAnimator = null
+
field = value
field?.let { newView ->
windowManager.addView(newView, overlayViewParams)
+ updateOverlayVisibility(newView)
orientationListener.enable()
}
}
@@ -90,11 +117,8 @@ class SidefpsController @Inject constructor(
private val overlayViewParams = WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
- WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
- WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
+ WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
+ Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS,
PixelFormat.TRANSLUCENT
).apply {
title = TAG
@@ -109,7 +133,7 @@ class SidefpsController @Inject constructor(
override fun show(
sensorId: Int,
@BiometricOverlayConstants.ShowReason reason: Int
- ) = if (reason.isReasonToShow()) doShow() else hide(sensorId)
+ ) = if (reason.isReasonToShow(activityTaskManager)) doShow() else hide(sensorId)
private fun doShow() = mainExecutor.execute {
if (overlayView == null) {
@@ -121,6 +145,7 @@ class SidefpsController @Inject constructor(
override fun hide(sensorId: Int) = mainExecutor.execute { overlayView = null }
})
+ overviewProxyService.addCallback(overviewProxyListener)
}
private fun onOrientationChanged() {
@@ -176,14 +201,49 @@ class SidefpsController @Inject constructor(
overlayViewParams.x = x
overlayViewParams.y = y
}
+
+ private fun updateOverlayVisibility(view: View) {
+ if (view != overlayView) {
+ return
+ }
+
+ // hide after a few seconds if the sensor is oriented down and there are
+ // large overlapping system bars
+ if ((context.display?.rotation == Surface.ROTATION_270) &&
+ windowManager.currentWindowMetrics.windowInsets.hasBigNavigationBar()) {
+ overlayHideAnimator = view.animate()
+ .alpha(0f)
+ .setStartDelay(3_000)
+ .setDuration(animationDuration)
+ .setListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ view.visibility = View.GONE
+ overlayHideAnimator = null
+ }
+ })
+ } else {
+ overlayHideAnimator?.cancel()
+ overlayHideAnimator = null
+ view.alpha = 1f
+ view.visibility = View.VISIBLE
+ }
+ }
}
@BiometricOverlayConstants.ShowReason
-private fun Int.isReasonToShow(): Boolean = when (this) {
+private fun Int.isReasonToShow(activityTaskManager: ActivityTaskManager): Boolean = when (this) {
REASON_AUTH_KEYGUARD -> false
+ REASON_AUTH_SETTINGS -> when (activityTaskManager.topClass()) {
+ // TODO(b/186176653): exclude fingerprint overlays from this list view
+ "com.android.settings.biometrics.fingerprint.FingerprintSettings" -> false
+ else -> true
+ }
else -> true
}
+private fun ActivityTaskManager.topClass(): String =
+ getTasks(1).firstOrNull()?.topActivity?.className ?: ""
+
@RawRes
private fun Display.asSideFpsAnimation(): Int = when (rotation) {
Surface.ROTATION_0 -> R.raw.sfps_pulse
@@ -200,6 +260,9 @@ private fun Display.asSideFpsAnimationRotation(): Float = when (rotation) {
private fun Display.isPortrait(): Boolean =
rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180
+private fun WindowInsets.hasBigNavigationBar(): Boolean =
+ getInsets(WindowInsets.Type.navigationBars()).bottom >= 70
+
private fun LottieAnimationView.addOverlayDynamicColor(context: Context) {
fun update() {
val c = context.getColor(R.color.biometric_dialog_accent)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
index a2e55c0f76e2..94743407f03d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
@@ -23,12 +23,12 @@ import android.graphics.RectF;
import com.android.systemui.Dumpable;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.util.ViewController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.Optional;
/**
* Handles:
@@ -43,7 +43,7 @@ import java.util.Optional;
abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView>
extends ViewController<T> implements Dumpable {
@NonNull final StatusBarStateController mStatusBarStateController;
- @NonNull final Optional<StatusBar> mStatusBarOptional;
+ @NonNull final PanelExpansionStateManager mPanelExpansionStateManager;
@NonNull final DumpManager mDumpManger;
boolean mNotificationShadeExpanded;
@@ -51,11 +51,11 @@ abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView>
protected UdfpsAnimationViewController(
T view,
@NonNull StatusBarStateController statusBarStateController,
- @NonNull Optional<StatusBar> statusBarOptional,
+ @NonNull PanelExpansionStateManager panelExpansionStateManager,
@NonNull DumpManager dumpManager) {
super(view);
mStatusBarStateController = statusBarStateController;
- mStatusBarOptional = statusBarOptional;
+ mPanelExpansionStateManager = panelExpansionStateManager;
mDumpManger = dumpManager;
}
@@ -63,17 +63,13 @@ abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView>
@Override
protected void onViewAttached() {
- mStatusBarOptional.ifPresent(
- statusBar -> statusBar.addExpansionChangedListener(
- mStatusBarExpansionChangedListener));
+ mPanelExpansionStateManager.addExpansionListener(mPanelExpansionListener);
mDumpManger.registerDumpable(getDumpTag(), this);
}
@Override
protected void onViewDetached() {
- mStatusBarOptional.ifPresent(
- statusBar -> statusBar.removeExpansionChangedListener(
- mStatusBarExpansionChangedListener));
+ mPanelExpansionStateManager.removeExpansionListener(mPanelExpansionListener);
mDumpManger.unregisterDumpable(getDumpTag());
}
@@ -182,13 +178,13 @@ abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView>
*/
void onTouchOutsideView() { }
- private final StatusBar.ExpansionChangedListener mStatusBarExpansionChangedListener =
- new StatusBar.ExpansionChangedListener() {
- @Override
- public void onExpansionChanged(float expansion, boolean expanded) {
- mNotificationShadeExpanded = expanded;
- mView.onExpansionChanged(expansion, expanded);
- updatePauseAuth();
- }
- };
+ private final PanelExpansionListener mPanelExpansionListener = new PanelExpansionListener() {
+ @Override
+ public void onPanelExpansionChanged(
+ float fraction, boolean expanded, boolean tracking) {
+ mNotificationShadeExpanded = expanded;
+ mView.onExpansionChanged(fraction, expanded);
+ updatePauseAuth();
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java
index 85955e1b5d56..894b29583cc9 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.java
@@ -20,9 +20,7 @@ import android.annotation.NonNull;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.phone.StatusBar;
-
-import java.util.Optional;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
/**
* Class that coordinates non-HBM animations for biometric prompt.
@@ -31,9 +29,9 @@ class UdfpsBpViewController extends UdfpsAnimationViewController<UdfpsBpView> {
protected UdfpsBpViewController(
@NonNull UdfpsBpView view,
@NonNull StatusBarStateController statusBarStateController,
- @NonNull Optional<StatusBar> statusBarOptional,
+ @NonNull PanelExpansionStateManager panelExpansionStateManager,
@NonNull DumpManager dumpManager) {
- super(view, statusBarStateController, statusBarOptional, dumpManager);
+ super(view, statusBarStateController, panelExpansionStateManager, dumpManager);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 3a3f22a4fda8..de45766af47d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -69,9 +69,9 @@ import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -112,7 +112,7 @@ public class UdfpsController implements DozeReceiver {
@NonNull private final LayoutInflater mInflater;
private final WindowManager mWindowManager;
private final DelayableExecutor mFgExecutor;
- @NonNull private final Optional<StatusBar> mStatusBarOptional;
+ @NonNull private final PanelExpansionStateManager mPanelExpansionStateManager;
@NonNull private final StatusBarStateController mStatusBarStateController;
@NonNull private final KeyguardStateController mKeyguardStateController;
@NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager;
@@ -521,7 +521,7 @@ public class UdfpsController implements DozeReceiver {
@NonNull WindowManager windowManager,
@NonNull StatusBarStateController statusBarStateController,
@Main DelayableExecutor fgExecutor,
- @NonNull Optional<StatusBar> statusBarOptional,
+ @NonNull PanelExpansionStateManager panelExpansionStateManager,
@NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager,
@NonNull DumpManager dumpManager,
@NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -550,7 +550,7 @@ public class UdfpsController implements DozeReceiver {
mFingerprintManager = checkNotNull(fingerprintManager);
mWindowManager = windowManager;
mFgExecutor = fgExecutor;
- mStatusBarOptional = statusBarOptional;
+ mPanelExpansionStateManager = panelExpansionStateManager;
mStatusBarStateController = statusBarStateController;
mKeyguardStateController = keyguardStateController;
mKeyguardViewManager = statusBarKeyguardViewManager;
@@ -583,7 +583,7 @@ public class UdfpsController implements DozeReceiver {
mCoreLayoutParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
- getCoreLayoutParamFlags(),
+ 0 /* flags set in computeLayoutParams() */,
PixelFormat.TRANSLUCENT);
mCoreLayoutParams.setTitle(TAG);
mCoreLayoutParams.setFitInsetsTypes(0);
@@ -616,13 +616,6 @@ public class UdfpsController implements DozeReceiver {
}
}
- private int getCoreLayoutParamFlags() {
- return WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
- }
-
@Nullable
private FingerprintSensorPropertiesInternal findFirstUdfps() {
for (FingerprintSensorPropertiesInternal props :
@@ -685,7 +678,8 @@ public class UdfpsController implements DozeReceiver {
final int paddingX = animation != null ? animation.getPaddingX() : 0;
final int paddingY = animation != null ? animation.getPaddingY() : 0;
- mCoreLayoutParams.flags = getCoreLayoutParamFlags();
+ mCoreLayoutParams.flags = Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
if (animation != null && animation.listenForTouchesOutsideView()) {
mCoreLayoutParams.flags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
}
@@ -767,10 +761,12 @@ public class UdfpsController implements DozeReceiver {
mOnFingerDown = false;
mView.setSensorProperties(mSensorProps);
mView.setHbmProvider(mHbmProvider);
- UdfpsAnimationViewController animation = inflateUdfpsAnimation(reason);
+ UdfpsAnimationViewController<?> animation = inflateUdfpsAnimation(reason);
mAttemptedToDismissKeyguard = false;
- animation.init();
- mView.setAnimationViewController(animation);
+ if (animation != null) {
+ animation.init();
+ mView.setAnimationViewController(animation);
+ }
mOrientationListener.enable();
// This view overlaps the sensor area, so prevent it from being selectable
@@ -793,7 +789,8 @@ public class UdfpsController implements DozeReceiver {
}
}
- private UdfpsAnimationViewController inflateUdfpsAnimation(int reason) {
+ @Nullable
+ private UdfpsAnimationViewController<?> inflateUdfpsAnimation(int reason) {
switch (reason) {
case BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR:
case BiometricOverlayConstants.REASON_ENROLL_ENROLLING:
@@ -805,7 +802,7 @@ public class UdfpsController implements DozeReceiver {
enrollView,
mServerRequest.mEnrollHelper,
mStatusBarStateController,
- mStatusBarOptional,
+ mPanelExpansionStateManager,
mDumpManager
);
case BiometricOverlayConstants.REASON_AUTH_KEYGUARD:
@@ -815,7 +812,7 @@ public class UdfpsController implements DozeReceiver {
return new UdfpsKeyguardViewController(
keyguardView,
mStatusBarStateController,
- mStatusBarOptional,
+ mPanelExpansionStateManager,
mKeyguardViewManager,
mKeyguardUpdateMonitor,
mDumpManager,
@@ -833,21 +830,22 @@ public class UdfpsController implements DozeReceiver {
return new UdfpsBpViewController(
bpView,
mStatusBarStateController,
- mStatusBarOptional,
+ mPanelExpansionStateManager,
mDumpManager
);
case BiometricOverlayConstants.REASON_AUTH_OTHER:
+ case BiometricOverlayConstants.REASON_AUTH_SETTINGS:
UdfpsFpmOtherView authOtherView = (UdfpsFpmOtherView)
mInflater.inflate(R.layout.udfps_fpm_other_view, null);
mView.addView(authOtherView);
return new UdfpsFpmOtherViewController(
authOtherView,
mStatusBarStateController,
- mStatusBarOptional,
+ mPanelExpansionStateManager,
mDumpManager
);
default:
- Log.d(TAG, "Animation for reason " + reason + " not supported yet");
+ Log.e(TAG, "Animation for reason " + reason + " not supported yet");
return null;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
index 2034ff35be70..1f01fc5a4b3d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
@@ -115,7 +115,8 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
mBlueFill.setColor(context.getColor(R.color.udfps_moving_target_fill));
mBlueFill.setStyle(Paint.Style.FILL);
- mMovingTargetFpIcon = context.getResources().getDrawable(R.drawable.ic_fingerprint, null);
+ mMovingTargetFpIcon = context.getResources()
+ .getDrawable(R.drawable.ic_kg_fingerprint, null);
mMovingTargetFpIcon.setTint(Color.WHITE);
mMovingTargetFpIcon.mutate();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
index b2a54097539d..79c7e66d40f7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
@@ -16,17 +16,22 @@
package com.android.systemui.biometrics;
+import android.animation.ValueAnimator;
import android.content.Context;
+import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
+import android.graphics.Paint;
import android.graphics.drawable.Drawable;
-import android.util.Log;
+import android.util.TypedValue;
+import android.view.animation.Interpolator;
+import android.view.animation.OvershootInterpolator;
+import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import java.util.ArrayList;
-import java.util.List;
+import com.android.systemui.R;
/**
* UDFPS enrollment progress bar.
@@ -34,111 +39,193 @@ import java.util.List;
public class UdfpsEnrollProgressBarDrawable extends Drawable {
private static final String TAG = "UdfpsProgressBar";
- private static final float SEGMENT_GAP_ANGLE = 12f;
+ private static final long CHECKMARK_ANIMATION_DELAY_MS = 200L;
+ private static final long CHECKMARK_ANIMATION_DURATION_MS = 300L;
+ private static final long FILL_COLOR_ANIMATION_DURATION_MS = 200L;
+ private static final long PROGRESS_ANIMATION_DURATION_MS = 400L;
+ private static final float STROKE_WIDTH_DP = 12f;
- @NonNull private final Context mContext;
+ private final float mStrokeWidthPx;
+ @ColorInt private final int mProgressColor;
+ @ColorInt private final int mHelpColor;
+ @NonNull private final Drawable mCheckmarkDrawable;
+ @NonNull private final Interpolator mCheckmarkInterpolator;
+ @NonNull private final Paint mBackgroundPaint;
+ @NonNull private final Paint mFillPaint;
- @Nullable private UdfpsEnrollHelper mEnrollHelper;
- @NonNull private List<UdfpsEnrollProgressBarSegment> mSegments = new ArrayList<>();
- private int mTotalSteps = 1;
- private int mProgressSteps = 0;
- private boolean mIsShowingHelp = false;
+ private boolean mAfterFirstTouch;
+
+ private int mRemainingSteps = 0;
+ private int mTotalSteps = 0;
+ private float mProgress = 0f;
+ @Nullable private ValueAnimator mProgressAnimator;
+ @NonNull private final ValueAnimator.AnimatorUpdateListener mProgressUpdateListener;
+
+ private boolean mShowingHelp = false;
+ @Nullable private ValueAnimator mFillColorAnimator;
+ @NonNull private final ValueAnimator.AnimatorUpdateListener mFillColorUpdateListener;
+
+ private boolean mComplete = false;
+ private float mCheckmarkScale = 0f;
+ @Nullable private ValueAnimator mCheckmarkAnimator;
+ @NonNull private final ValueAnimator.AnimatorUpdateListener mCheckmarkUpdateListener;
public UdfpsEnrollProgressBarDrawable(@NonNull Context context) {
- mContext = context;
- }
+ mStrokeWidthPx = Utils.dpToPixels(context, STROKE_WIDTH_DP);
+ mProgressColor = context.getColor(R.color.udfps_enroll_progress);
+ mHelpColor = context.getColor(R.color.udfps_enroll_progress_help);
+ mCheckmarkDrawable = context.getDrawable(R.drawable.udfps_enroll_checkmark);
+ mCheckmarkDrawable.mutate();
+ mCheckmarkInterpolator = new OvershootInterpolator();
- void setEnrollHelper(@Nullable UdfpsEnrollHelper enrollHelper) {
- mEnrollHelper = enrollHelper;
- if (enrollHelper != null) {
- final int stageCount = enrollHelper.getStageCount();
- mSegments = new ArrayList<>(stageCount);
- float startAngle = SEGMENT_GAP_ANGLE / 2f;
- final float sweepAngle = (360f / stageCount) - SEGMENT_GAP_ANGLE;
- final Runnable invalidateRunnable = this::invalidateSelf;
- for (int index = 0; index < stageCount; index++) {
- mSegments.add(new UdfpsEnrollProgressBarSegment(mContext, getBounds(), startAngle,
- sweepAngle, SEGMENT_GAP_ANGLE, invalidateRunnable));
- startAngle += sweepAngle + SEGMENT_GAP_ANGLE;
- }
- invalidateSelf();
+ mBackgroundPaint = new Paint();
+ mBackgroundPaint.setStrokeWidth(mStrokeWidthPx);
+ mBackgroundPaint.setColor(context.getColor(R.color.white_disabled));
+ mBackgroundPaint.setAntiAlias(true);
+ mBackgroundPaint.setStyle(Paint.Style.STROKE);
+ mBackgroundPaint.setStrokeCap(Paint.Cap.ROUND);
+
+ // Set background paint color and alpha.
+ final int[] attrs = new int[] {android.R.attr.colorControlNormal};
+ final TypedArray typedArray = context.obtainStyledAttributes(attrs);
+ try {
+ @ColorInt final int tintColor = typedArray.getColor(0, mBackgroundPaint.getColor());
+ mBackgroundPaint.setColor(tintColor);
+ } finally {
+ typedArray.recycle();
}
+ TypedValue alpha = new TypedValue();
+ context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, alpha, true);
+ mBackgroundPaint.setAlpha((int) (alpha.getFloat() * 255f));
+
+ // Progress fill should *not* use the extracted system color.
+ mFillPaint = new Paint();
+ mFillPaint.setStrokeWidth(mStrokeWidthPx);
+ mFillPaint.setColor(mProgressColor);
+ mFillPaint.setAntiAlias(true);
+ mFillPaint.setStyle(Paint.Style.STROKE);
+ mFillPaint.setStrokeCap(Paint.Cap.ROUND);
+
+ mProgressUpdateListener = animation -> {
+ mProgress = (float) animation.getAnimatedValue();
+ invalidateSelf();
+ };
+
+ mFillColorUpdateListener = animation -> {
+ mFillPaint.setColor((int) animation.getAnimatedValue());
+ invalidateSelf();
+ };
+
+ mCheckmarkUpdateListener = animation -> {
+ mCheckmarkScale = (float) animation.getAnimatedValue();
+ invalidateSelf();
+ };
}
void onEnrollmentProgress(int remaining, int totalSteps) {
- mTotalSteps = totalSteps;
- updateState(getProgressSteps(remaining, totalSteps), false /* isShowingHelp */);
+ mAfterFirstTouch = true;
+ updateState(remaining, totalSteps, false /* showingHelp */);
}
void onEnrollmentHelp(int remaining, int totalSteps) {
- updateState(getProgressSteps(remaining, totalSteps), true /* isShowingHelp */);
+ updateState(remaining, totalSteps, true /* showingHelp */);
}
void onLastStepAcquired() {
- updateState(mTotalSteps, false /* isShowingHelp */);
+ updateState(0, mTotalSteps, false /* showingHelp */);
}
- private static int getProgressSteps(int remaining, int totalSteps) {
- // Show some progress for the initial touch.
- return Math.max(1, totalSteps - remaining);
+ private void updateState(int remainingSteps, int totalSteps, boolean showingHelp) {
+ updateProgress(remainingSteps, totalSteps);
+ updateFillColor(showingHelp);
}
- private void updateState(int progressSteps, boolean isShowingHelp) {
- updateProgress(progressSteps);
- updateFillColor(isShowingHelp);
+ private void updateProgress(int remainingSteps, int totalSteps) {
+ if (mRemainingSteps == remainingSteps && mTotalSteps == totalSteps) {
+ return;
+ }
+ mRemainingSteps = remainingSteps;
+ mTotalSteps = totalSteps;
+
+ final int progressSteps = Math.max(0, totalSteps - remainingSteps);
+
+ // If needed, add 1 to progress and total steps to account for initial touch.
+ final int adjustedSteps = mAfterFirstTouch ? progressSteps + 1 : progressSteps;
+ final int adjustedTotal = mAfterFirstTouch ? mTotalSteps + 1 : mTotalSteps;
+
+ final float targetProgress = Math.min(1f, (float) adjustedSteps / (float) adjustedTotal);
+
+ if (mProgressAnimator != null && mProgressAnimator.isRunning()) {
+ mProgressAnimator.cancel();
+ }
+
+ mProgressAnimator = ValueAnimator.ofFloat(mProgress, targetProgress);
+ mProgressAnimator.setDuration(PROGRESS_ANIMATION_DURATION_MS);
+ mProgressAnimator.addUpdateListener(mProgressUpdateListener);
+ mProgressAnimator.start();
+
+ if (remainingSteps == 0) {
+ startCompletionAnimation();
+ } else if (remainingSteps > 0) {
+ rollBackCompletionAnimation();
+ }
}
- private void updateProgress(int progressSteps) {
- if (mProgressSteps == progressSteps) {
+ private void updateFillColor(boolean showingHelp) {
+ if (mShowingHelp == showingHelp) {
return;
}
- mProgressSteps = progressSteps;
+ mShowingHelp = showingHelp;
- if (mEnrollHelper == null) {
- Log.e(TAG, "updateState: UDFPS enroll helper was null");
- return;
+ if (mFillColorAnimator != null && mFillColorAnimator.isRunning()) {
+ mFillColorAnimator.cancel();
}
- int index = 0;
- int prevThreshold = 0;
- while (index < mSegments.size()) {
- final UdfpsEnrollProgressBarSegment segment = mSegments.get(index);
- final int thresholdSteps = mEnrollHelper.getStageThresholdSteps(mTotalSteps, index);
- if (progressSteps >= thresholdSteps && segment.getProgress() < 1f) {
- segment.updateProgress(1f);
- break;
- } else if (progressSteps >= prevThreshold && progressSteps < thresholdSteps) {
- final int relativeSteps = progressSteps - prevThreshold;
- final int relativeThreshold = thresholdSteps - prevThreshold;
- final float segmentProgress = (float) relativeSteps / (float) relativeThreshold;
- segment.updateProgress(segmentProgress);
- break;
- }
-
- index++;
- prevThreshold = thresholdSteps;
+ @ColorInt final int targetColor = showingHelp ? mHelpColor : mProgressColor;
+ mFillColorAnimator = ValueAnimator.ofArgb(mFillPaint.getColor(), targetColor);
+ mFillColorAnimator.setDuration(FILL_COLOR_ANIMATION_DURATION_MS);
+ mFillColorAnimator.addUpdateListener(mFillColorUpdateListener);
+ mFillColorAnimator.start();
+ }
+
+ private void startCompletionAnimation() {
+ if (mComplete) {
+ return;
}
+ mComplete = true;
- if (progressSteps >= mTotalSteps) {
- for (final UdfpsEnrollProgressBarSegment segment : mSegments) {
- segment.startCompletionAnimation();
- }
- } else {
- for (final UdfpsEnrollProgressBarSegment segment : mSegments) {
- segment.cancelCompletionAnimation();
- }
+ if (mCheckmarkAnimator != null && mCheckmarkAnimator.isRunning()) {
+ mCheckmarkAnimator.cancel();
}
+
+ mCheckmarkAnimator = ValueAnimator.ofFloat(mCheckmarkScale, 1f);
+ mCheckmarkAnimator.setStartDelay(CHECKMARK_ANIMATION_DELAY_MS);
+ mCheckmarkAnimator.setDuration(CHECKMARK_ANIMATION_DURATION_MS);
+ mCheckmarkAnimator.setInterpolator(mCheckmarkInterpolator);
+ mCheckmarkAnimator.addUpdateListener(mCheckmarkUpdateListener);
+ mCheckmarkAnimator.start();
}
- private void updateFillColor(boolean isShowingHelp) {
- if (mIsShowingHelp == isShowingHelp) {
+ private void rollBackCompletionAnimation() {
+ if (!mComplete) {
return;
}
- mIsShowingHelp = isShowingHelp;
+ mComplete = false;
- for (final UdfpsEnrollProgressBarSegment segment : mSegments) {
- segment.updateFillColor(isShowingHelp);
+ // Adjust duration based on how much of the completion animation has played.
+ final float animatedFraction = mCheckmarkAnimator != null
+ ? mCheckmarkAnimator.getAnimatedFraction()
+ : 0f;
+ final long durationMs = Math.round(CHECKMARK_ANIMATION_DELAY_MS * animatedFraction);
+
+ if (mCheckmarkAnimator != null && mCheckmarkAnimator.isRunning()) {
+ mCheckmarkAnimator.cancel();
}
+
+ mCheckmarkAnimator = ValueAnimator.ofFloat(mCheckmarkScale, 0f);
+ mCheckmarkAnimator.setDuration(durationMs);
+ mCheckmarkAnimator.addUpdateListener(mCheckmarkUpdateListener);
+ mCheckmarkAnimator.start();
}
@Override
@@ -148,12 +235,55 @@ public class UdfpsEnrollProgressBarDrawable extends Drawable {
// Progress starts from the top, instead of the right
canvas.rotate(-90f, getBounds().centerX(), getBounds().centerY());
- // Draw each of the enroll segments.
- for (final UdfpsEnrollProgressBarSegment segment : mSegments) {
- segment.draw(canvas);
+ final float halfPaddingPx = mStrokeWidthPx / 2f;
+
+ if (mProgress < 1f) {
+ // Draw the background color of the progress circle.
+ canvas.drawArc(
+ halfPaddingPx,
+ halfPaddingPx,
+ getBounds().right - halfPaddingPx,
+ getBounds().bottom - halfPaddingPx,
+ 0f /* startAngle */,
+ 360f /* sweepAngle */,
+ false /* useCenter */,
+ mBackgroundPaint);
+ }
+
+ if (mProgress > 0f) {
+ // Draw the filled portion of the progress circle.
+ canvas.drawArc(
+ halfPaddingPx,
+ halfPaddingPx,
+ getBounds().right - halfPaddingPx,
+ getBounds().bottom - halfPaddingPx,
+ 0f /* startAngle */,
+ 360f * mProgress /* sweepAngle */,
+ false /* useCenter */,
+ mFillPaint);
}
canvas.restore();
+
+ if (mCheckmarkScale > 0f) {
+ final float offsetScale = (float) Math.sqrt(2) / 2f;
+ final float centerXOffset = (getBounds().width() - mStrokeWidthPx) / 2f * offsetScale;
+ final float centerYOffset = (getBounds().height() - mStrokeWidthPx) / 2f * offsetScale;
+ final float centerX = getBounds().centerX() + centerXOffset;
+ final float centerY = getBounds().centerY() + centerYOffset;
+
+ final float boundsXOffset =
+ mCheckmarkDrawable.getIntrinsicWidth() / 2f * mCheckmarkScale;
+ final float boundsYOffset =
+ mCheckmarkDrawable.getIntrinsicHeight() / 2f * mCheckmarkScale;
+
+ final int left = Math.round(centerX - boundsXOffset);
+ final int top = Math.round(centerY - boundsYOffset);
+ final int right = Math.round(centerX + boundsXOffset);
+ final int bottom = Math.round(centerY + boundsYOffset);
+ mCheckmarkDrawable.setBounds(left, top, right, bottom);
+ mCheckmarkDrawable.draw(canvas);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarSegment.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarSegment.java
deleted file mode 100644
index bd6ab4443630..000000000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarSegment.java
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.biometrics;
-
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Log;
-import android.util.TypedValue;
-
-import androidx.annotation.ColorInt;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.systemui.R;
-
-/**
- * A single segment of the UDFPS enrollment progress bar.
- */
-public class UdfpsEnrollProgressBarSegment {
- private static final String TAG = "UdfpsProgressBarSegment";
-
- private static final long FILL_COLOR_ANIMATION_DURATION_MS = 200L;
- private static final long PROGRESS_ANIMATION_DURATION_MS = 400L;
- private static final long OVER_SWEEP_ANIMATION_DELAY_MS = 200L;
- private static final long OVER_SWEEP_ANIMATION_DURATION_MS = 200L;
-
- private static final float STROKE_WIDTH_DP = 12f;
-
- private final Handler mHandler = new Handler(Looper.getMainLooper());
-
- @NonNull private final Rect mBounds;
- @NonNull private final Runnable mInvalidateRunnable;
- private final float mStartAngle;
- private final float mSweepAngle;
- private final float mMaxOverSweepAngle;
- private final float mStrokeWidthPx;
- @ColorInt private final int mProgressColor;
- @ColorInt private final int mHelpColor;
-
- @NonNull private final Paint mBackgroundPaint;
- @NonNull private final Paint mProgressPaint;
-
- private float mProgress = 0f;
- private float mAnimatedProgress = 0f;
- @Nullable private ValueAnimator mProgressAnimator;
- @NonNull private final ValueAnimator.AnimatorUpdateListener mProgressUpdateListener;
-
- private boolean mIsShowingHelp = false;
- @Nullable private ValueAnimator mFillColorAnimator;
- @NonNull private final ValueAnimator.AnimatorUpdateListener mFillColorUpdateListener;
-
- private float mOverSweepAngle = 0f;
- @Nullable private ValueAnimator mOverSweepAnimator;
- @Nullable private ValueAnimator mOverSweepReverseAnimator;
- @NonNull private final ValueAnimator.AnimatorUpdateListener mOverSweepUpdateListener;
- @NonNull private final Runnable mOverSweepAnimationRunnable;
-
- public UdfpsEnrollProgressBarSegment(@NonNull Context context, @NonNull Rect bounds,
- float startAngle, float sweepAngle, float maxOverSweepAngle,
- @NonNull Runnable invalidateRunnable) {
-
- mBounds = bounds;
- mInvalidateRunnable = invalidateRunnable;
- mStartAngle = startAngle;
- mSweepAngle = sweepAngle;
- mMaxOverSweepAngle = maxOverSweepAngle;
- mStrokeWidthPx = Utils.dpToPixels(context, STROKE_WIDTH_DP);
- mProgressColor = context.getColor(R.color.udfps_enroll_progress);
- mHelpColor = context.getColor(R.color.udfps_enroll_progress_help);
-
- mBackgroundPaint = new Paint();
- mBackgroundPaint.setStrokeWidth(mStrokeWidthPx);
- mBackgroundPaint.setColor(context.getColor(R.color.white_disabled));
- mBackgroundPaint.setAntiAlias(true);
- mBackgroundPaint.setStyle(Paint.Style.STROKE);
- mBackgroundPaint.setStrokeCap(Paint.Cap.ROUND);
-
- // Background paint color + alpha
- final int[] attrs = new int[] {android.R.attr.colorControlNormal};
- final TypedArray ta = context.obtainStyledAttributes(attrs);
- @ColorInt final int tintColor = ta.getColor(0, mBackgroundPaint.getColor());
- mBackgroundPaint.setColor(tintColor);
- ta.recycle();
- TypedValue alpha = new TypedValue();
- context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, alpha, true);
- mBackgroundPaint.setAlpha((int) (alpha.getFloat() * 255f));
-
- // Progress should not be color extracted
- mProgressPaint = new Paint();
- mProgressPaint.setStrokeWidth(mStrokeWidthPx);
- mProgressPaint.setColor(mProgressColor);
- mProgressPaint.setAntiAlias(true);
- mProgressPaint.setStyle(Paint.Style.STROKE);
- mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
-
- mProgressUpdateListener = animation -> {
- mAnimatedProgress = (float) animation.getAnimatedValue();
- mInvalidateRunnable.run();
- };
-
- mFillColorUpdateListener = animation -> {
- mProgressPaint.setColor((int) animation.getAnimatedValue());
- mInvalidateRunnable.run();
- };
-
- mOverSweepUpdateListener = animation -> {
- mOverSweepAngle = (float) animation.getAnimatedValue();
- mInvalidateRunnable.run();
- };
- mOverSweepAnimationRunnable = () -> {
- if (mOverSweepAnimator != null && mOverSweepAnimator.isRunning()) {
- mOverSweepAnimator.cancel();
- }
- mOverSweepAnimator = ValueAnimator.ofFloat(mOverSweepAngle, mMaxOverSweepAngle);
- mOverSweepAnimator.setDuration(OVER_SWEEP_ANIMATION_DURATION_MS);
- mOverSweepAnimator.addUpdateListener(mOverSweepUpdateListener);
- mOverSweepAnimator.start();
- };
- }
-
- /**
- * Draws this segment to the given canvas.
- */
- public void draw(@NonNull Canvas canvas) {
- final float halfPaddingPx = mStrokeWidthPx / 2f;
-
- if (mAnimatedProgress < 1f) {
- // Draw the unfilled background color of the segment.
- canvas.drawArc(
- halfPaddingPx,
- halfPaddingPx,
- mBounds.right - halfPaddingPx,
- mBounds.bottom - halfPaddingPx,
- mStartAngle,
- mSweepAngle,
- false /* useCenter */,
- mBackgroundPaint);
- }
-
- if (mAnimatedProgress > 0f) {
- // Draw the filled progress portion of the segment.
- canvas.drawArc(
- halfPaddingPx,
- halfPaddingPx,
- mBounds.right - halfPaddingPx,
- mBounds.bottom - halfPaddingPx,
- mStartAngle,
- mSweepAngle * mAnimatedProgress + mOverSweepAngle,
- false /* useCenter */,
- mProgressPaint);
- }
- }
-
- /**
- * @return The fill progress of this segment, in the range [0, 1]. If fill progress is being
- * animated, returns the value it is animating to.
- */
- public float getProgress() {
- return mProgress;
- }
-
- /**
- * Updates the fill progress of this segment, animating if necessary.
- *
- * @param progress The new fill progress, in the range [0, 1].
- */
- public void updateProgress(float progress) {
- updateProgress(progress, PROGRESS_ANIMATION_DURATION_MS);
- }
-
- private void updateProgress(float progress, long animationDurationMs) {
- if (mProgress == progress) {
- return;
- }
- mProgress = progress;
-
- if (mProgressAnimator != null && mProgressAnimator.isRunning()) {
- mProgressAnimator.cancel();
- }
-
- mProgressAnimator = ValueAnimator.ofFloat(mAnimatedProgress, progress);
- mProgressAnimator.setDuration(animationDurationMs);
- mProgressAnimator.addUpdateListener(mProgressUpdateListener);
- mProgressAnimator.start();
- }
-
- /**
- * Updates the fill color of this segment, animating if necessary.
- *
- * @param isShowingHelp Whether fill color should indicate that a help message is being shown.
- */
- public void updateFillColor(boolean isShowingHelp) {
- if (mIsShowingHelp == isShowingHelp) {
- return;
- }
- mIsShowingHelp = isShowingHelp;
-
- if (mFillColorAnimator != null && mFillColorAnimator.isRunning()) {
- mFillColorAnimator.cancel();
- }
-
- @ColorInt final int targetColor = isShowingHelp ? mHelpColor : mProgressColor;
- mFillColorAnimator = ValueAnimator.ofArgb(mProgressPaint.getColor(), targetColor);
- mFillColorAnimator.setDuration(FILL_COLOR_ANIMATION_DURATION_MS);
- mFillColorAnimator.addUpdateListener(mFillColorUpdateListener);
- mFillColorAnimator.start();
- }
-
- /**
- * Queues and runs the completion animation for this segment.
- */
- public void startCompletionAnimation() {
- final boolean hasCallback = mHandler.hasCallbacks(mOverSweepAnimationRunnable);
- if (hasCallback || mOverSweepAngle >= mMaxOverSweepAngle) {
- Log.d(TAG, "startCompletionAnimation skipped: hasCallback = " + hasCallback
- + ", mOverSweepAngle = " + mOverSweepAngle);
- return;
- }
-
- // Reset sweep angle back to zero if the animation is being rolled back.
- if (mOverSweepReverseAnimator != null && mOverSweepReverseAnimator.isRunning()) {
- mOverSweepReverseAnimator.cancel();
- mOverSweepAngle = 0f;
- }
-
- // Clear help color and start filling the segment if it isn't already.
- if (mAnimatedProgress < 1f) {
- updateProgress(1f, OVER_SWEEP_ANIMATION_DELAY_MS);
- updateFillColor(false /* isShowingHelp */);
- }
-
- // Queue the animation to run after fill completes.
- mHandler.postDelayed(mOverSweepAnimationRunnable, OVER_SWEEP_ANIMATION_DELAY_MS);
- }
-
- /**
- * Cancels (and reverses, if necessary) a queued or running completion animation.
- */
- public void cancelCompletionAnimation() {
- // Cancel the animation if it's queued or running.
- mHandler.removeCallbacks(mOverSweepAnimationRunnable);
- if (mOverSweepAnimator != null && mOverSweepAnimator.isRunning()) {
- mOverSweepAnimator.cancel();
- }
-
- // Roll back the animation if it has at least partially run.
- if (mOverSweepAngle > 0f) {
- if (mOverSweepReverseAnimator != null && mOverSweepReverseAnimator.isRunning()) {
- mOverSweepReverseAnimator.cancel();
- }
-
- final float completion = mOverSweepAngle / mMaxOverSweepAngle;
- final long proratedDuration = (long) (OVER_SWEEP_ANIMATION_DURATION_MS * completion);
- mOverSweepReverseAnimator = ValueAnimator.ofFloat(mOverSweepAngle, 0f);
- mOverSweepReverseAnimator.setDuration(proratedDuration);
- mOverSweepReverseAnimator.addUpdateListener(mOverSweepUpdateListener);
- mOverSweepReverseAnimator.start();
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
index 729838ed59aa..93df2cf0f835 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
@@ -73,7 +73,6 @@ public class UdfpsEnrollView extends UdfpsAnimationView {
}
void setEnrollHelper(UdfpsEnrollHelper enrollHelper) {
- mFingerprintProgressDrawable.setEnrollHelper(enrollHelper);
mFingerprintDrawable.setEnrollHelper(enrollHelper);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
index af7c3522dc23..292a904af96e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
@@ -22,9 +22,7 @@ import android.graphics.PointF;
import com.android.systemui.R;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.phone.StatusBar;
-
-import java.util.Optional;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
/**
* Class that coordinates non-HBM animations during enrollment.
@@ -55,9 +53,9 @@ public class UdfpsEnrollViewController extends UdfpsAnimationViewController<Udfp
@NonNull UdfpsEnrollView view,
@NonNull UdfpsEnrollHelper enrollHelper,
@NonNull StatusBarStateController statusBarStateController,
- @NonNull Optional<StatusBar> statusBarOptional,
+ @NonNull PanelExpansionStateManager panelExpansionStateManager,
@NonNull DumpManager dumpManager) {
- super(view, statusBarStateController, statusBarOptional, dumpManager);
+ super(view, statusBarStateController, panelExpansionStateManager, dumpManager);
mEnrollProgressBarRadius = getContext().getResources()
.getInteger(R.integer.config_udfpsEnrollProgressBar);
mEnrollHelper = enrollHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java
index dcb5aefc8aa3..619873367ee8 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.java
@@ -20,9 +20,7 @@ import android.annotation.NonNull;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.phone.StatusBar;
-
-import java.util.Optional;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
/**
* Class that coordinates non-HBM animations for non keyguard, enrollment or biometric prompt
@@ -34,9 +32,9 @@ class UdfpsFpmOtherViewController extends UdfpsAnimationViewController<UdfpsFpmO
protected UdfpsFpmOtherViewController(
@NonNull UdfpsFpmOtherView view,
@NonNull StatusBarStateController statusBarStateController,
- @NonNull Optional<StatusBar> statusBarOptional,
+ @NonNull PanelExpansionStateManager panelExpansionStateManager,
@NonNull DumpManager dumpManager) {
- super(view, statusBarStateController, statusBarOptional, dumpManager);
+ super(view, statusBarStateController, panelExpansionStateManager, dumpManager);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index 7a28c9d52260..d1ea45cac081 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -30,16 +30,16 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
-import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.time.SystemClock;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.Optional;
/**
* Class that coordinates non-HBM animations during keyguard authentication.
@@ -77,7 +77,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
protected UdfpsKeyguardViewController(
@NonNull UdfpsKeyguardView view,
@NonNull StatusBarStateController statusBarStateController,
- @NonNull Optional<StatusBar> statusBarOptional,
+ @NonNull PanelExpansionStateManager panelExpansionStateManager,
@NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager,
@NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
@NonNull DumpManager dumpManager,
@@ -87,7 +87,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
@NonNull KeyguardStateController keyguardStateController,
@NonNull UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
@NonNull UdfpsController udfpsController) {
- super(view, statusBarStateController, statusBarOptional, dumpManager);
+ super(view, statusBarStateController, panelExpansionStateManager, dumpManager);
mKeyguardViewManager = statusBarKeyguardViewManager;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockScreenShadeTransitionController = transitionController;
@@ -126,9 +126,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
mInputBouncerHiddenAmount = KeyguardBouncer.EXPANSION_HIDDEN;
mIsBouncerVisible = mKeyguardViewManager.bouncerIsOrWillBeShowing();
mConfigurationController.addCallback(mConfigurationListener);
- mStatusBarOptional.ifPresent(
- statusBar -> statusBar.addExpansionChangedListener(
- mStatusBarExpansionChangedListener));
+ mPanelExpansionStateManager.addExpansionListener(mPanelExpansionListener);
updateAlpha();
updatePauseAuth();
@@ -147,9 +145,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
mKeyguardViewManager.removeAlternateAuthInterceptor(mAlternateAuthInterceptor);
mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
mConfigurationController.removeCallback(mConfigurationListener);
- mStatusBarOptional.ifPresent(
- statusBar -> statusBar.removeExpansionChangedListener(
- mStatusBarExpansionChangedListener));
+ mPanelExpansionStateManager.removeExpansionListener(mPanelExpansionListener);
if (mLockScreenShadeTransitionController.getUdfpsKeyguardViewController() == this) {
mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(null);
}
@@ -403,14 +399,14 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
}
};
- private final StatusBar.ExpansionChangedListener mStatusBarExpansionChangedListener =
- new StatusBar.ExpansionChangedListener() {
- @Override
- public void onExpansionChanged(float expansion, boolean expanded) {
- mStatusBarExpansion = expansion;
- updateAlpha();
- }
- };
+ private final PanelExpansionListener mPanelExpansionListener = new PanelExpansionListener() {
+ @Override
+ public void onPanelExpansionChanged(
+ float fraction, boolean expanded, boolean tracking) {
+ mStatusBarExpansion = fraction;
+ updateAlpha();
+ }
+ };
private final KeyguardStateController.Callback mKeyguardStateControllerCallback =
new KeyguardStateController.Callback() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/Utils.java b/packages/SystemUI/src/com/android/systemui/biometrics/Utils.java
index 322584c4aa69..6989547dce52 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/Utils.java
@@ -31,6 +31,7 @@ import android.hardware.biometrics.SensorPropertiesInternal;
import android.os.UserManager;
import android.util.DisplayMetrics;
import android.view.ViewGroup;
+import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -46,6 +47,13 @@ public class Utils {
public static final int CREDENTIAL_PATTERN = 2;
public static final int CREDENTIAL_PASSWORD = 3;
+ /** Base set of layout flags for fingerprint overlay widgets. */
+ public static final int FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS =
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+
@Retention(RetentionPolicy.SOURCE)
@IntDef({CREDENTIAL_PIN, CREDENTIAL_PATTERN, CREDENTIAL_PASSWORD})
@interface CredentialType {}
@@ -55,11 +63,6 @@ public class Utils {
/ DisplayMetrics.DENSITY_DEFAULT);
}
- static float pixelsToDp(Context context, float pixels) {
- return pixels / ((float) context.getResources().getDisplayMetrics().densityDpi
- / DisplayMetrics.DENSITY_DEFAULT);
- }
-
static void notifyAccessibilityContentChanged(AccessibilityManager am, ViewGroup view) {
if (!am.isEnabled()) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt
index bf84d77224b1..7e5b26732e00 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt
@@ -28,6 +28,7 @@ import android.os.UserHandle
import android.service.controls.Control
import android.service.controls.ControlsProviderService
import android.util.Log
+import java.lang.ClassCastException
/**
* Proxy to launch in user 0
@@ -59,20 +60,29 @@ class ControlsRequestReceiver : BroadcastReceiver() {
return
}
- val packageName = intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME)
- ?.packageName
+ val targetComponent = try {
+ intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME)
+ } catch (e: ClassCastException) {
+ Log.e(TAG, "Malformed intent extra ComponentName", e)
+ return
+ }
+
+ val control = try {
+ intent.getParcelableExtra<Control>(ControlsProviderService.EXTRA_CONTROL)
+ } catch (e: ClassCastException) {
+ Log.e(TAG, "Malformed intent extra Control", e)
+ return
+ }
+
+ val packageName = targetComponent?.packageName
if (packageName == null || !isPackageInForeground(context, packageName)) {
return
}
val activityIntent = Intent(context, ControlsRequestDialog::class.java).apply {
- Intent.EXTRA_COMPONENT_NAME.let {
- putExtra(it, intent.getParcelableExtra<ComponentName>(it))
- }
- ControlsProviderService.EXTRA_CONTROL.let {
- putExtra(it, intent.getParcelableExtra<Control>(it))
- }
+ putExtra(Intent.EXTRA_COMPONENT_NAME, targetComponent)
+ putExtra(ControlsProviderService.EXTRA_CONTROL, control)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
}
activityIntent.putExtra(Intent.EXTRA_USER_ID, context.userId)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 72da7f4f893a..5a52fd0516ea 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -120,7 +120,7 @@ class ControlsUiControllerImpl @Inject constructor (
private val onSeedingComplete = Consumer<Boolean> {
accepted ->
if (accepted) {
- selectedStructure = controlsController.get().getFavorites().maxBy {
+ selectedStructure = controlsController.get().getFavorites().maxByOrNull {
it.controls.size
} ?: EMPTY_STRUCTURE
updatePreferences(selectedStructure)
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
index de8ed7013ab2..bce878434aa1 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
@@ -22,7 +22,6 @@ import com.android.systemui.ForegroundServicesDialog;
import com.android.systemui.keyguard.WorkLockActivity;
import com.android.systemui.people.PeopleSpaceActivity;
import com.android.systemui.people.widget.LaunchConversationActivity;
-import com.android.systemui.screenrecord.ScreenRecordDialog;
import com.android.systemui.screenshot.LongScreenshotActivity;
import com.android.systemui.sensorprivacy.SensorUseStartedActivity;
import com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity;
@@ -67,12 +66,6 @@ public abstract class DefaultActivityBinder {
@ClassKey(BrightnessDialog.class)
public abstract Activity bindBrightnessDialog(BrightnessDialog activity);
- /** Inject into ScreenRecordDialog */
- @Binds
- @IntoMap
- @ClassKey(ScreenRecordDialog.class)
- public abstract Activity bindScreenRecordDialog(ScreenRecordDialog activity);
-
/** Inject into UsbDebuggingActivity. */
@Binds
@IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index a9a4da8d94a2..a9fb743bff8d 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -25,6 +25,8 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardSliceProvider;
import com.android.systemui.people.PeopleProvider;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.unfold.SysUIUnfoldComponent;
+import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider;
import com.android.wm.shell.ShellCommandHandler;
import com.android.wm.shell.TaskViewFactory;
import com.android.wm.shell.apppairs.AppPairs;
@@ -34,6 +36,7 @@ import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
+import com.android.wm.shell.recents.RecentTasks;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelper;
@@ -101,6 +104,9 @@ public interface SysUIComponent {
@BindsInstance
Builder setTaskSurfaceHelper(Optional<TaskSurfaceHelper> t);
+ @BindsInstance
+ Builder setRecentTasks(Optional<RecentTasks> r);
+
SysUIComponent build();
}
@@ -108,7 +114,14 @@ public interface SysUIComponent {
* Initializes all the SysUI components.
*/
default void init() {
- // Do nothing
+ // Initialize components that have no direct tie to the dagger dependency graph,
+ // but are critical to this component's operation
+ // TODO(b/205034537): I think this is a good idea?
+ getSysUIUnfoldComponent().ifPresent(c -> {
+ c.getUnfoldLightRevealOverlayAnimation().init();
+ c.getUnfoldTransitionWallpaperController().init();
+ });
+ getNaturalRotationUnfoldProgressProvider().ifPresent(o -> o.init());
}
/**
@@ -146,6 +159,16 @@ public interface SysUIComponent {
InitController getInitController();
/**
+ * For devices with a hinge: access objects within this component
+ */
+ Optional<SysUIUnfoldComponent> getSysUIUnfoldComponent();
+
+ /**
+ * For devices with a hinge: the rotation animation
+ */
+ Optional<NaturalRotationUnfoldProgressProvider> getNaturalRotationUnfoldProgressProvider();
+
+ /**
* Member injection into the supplied argument.
*/
void inject(SystemUIAppComponentFactory factory);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index a4e2572836f8..12786f278a16 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -18,7 +18,6 @@ package com.android.systemui.dagger;
import android.app.INotificationManager;
import android.content.Context;
-import android.view.LayoutInflater;
import androidx.annotation.Nullable;
@@ -27,7 +26,6 @@ import com.android.keyguard.clock.ClockModule;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.BootCompleteCache;
import com.android.systemui.BootCompleteCacheImpl;
-import com.android.systemui.R;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.appops.dagger.AppOpsModule;
import com.android.systemui.assist.AssistModule;
@@ -42,6 +40,7 @@ import com.android.systemui.flags.FeatureFlagManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.FlagReader;
import com.android.systemui.flags.FlagWriter;
+import com.android.systemui.flags.FlagsModule;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.log.dagger.LogModule;
import com.android.systemui.model.SysUiState;
@@ -66,14 +65,15 @@ import com.android.systemui.statusbar.notification.row.dagger.NotificationRowCom
import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.phone.StatusBarWindowView;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.policy.dagger.SmartRepliesInflationModule;
import com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule;
+import com.android.systemui.statusbar.window.StatusBarWindowModule;
import com.android.systemui.tuner.dagger.TunerModule;
+import com.android.systemui.unfold.SysUIUnfoldModule;
import com.android.systemui.user.UserModule;
import com.android.systemui.util.concurrency.SysUIConcurrencyModule;
import com.android.systemui.util.dagger.UtilModule;
@@ -104,6 +104,7 @@ import dagger.Provides;
ControlsModule.class,
DemoModeModule.class,
FalsingModule.class,
+ FlagsModule.class,
LogModule.class,
PeopleHubModule.class,
PluginModule.class,
@@ -113,7 +114,9 @@ import dagger.Provides;
SettingsUtilModule.class,
SmartRepliesInflationModule.class,
StatusBarPolicyModule.class,
+ StatusBarWindowModule.class,
SysUIConcurrencyModule.class,
+ SysUIUnfoldModule.class,
TunerModule.class,
UserModule.class,
UtilModule.class,
@@ -212,17 +215,4 @@ public abstract class SystemUIModule {
groupManager, entryManager, notifPipeline, sysUiState, featureFlags, dumpManager,
sysuiMainExecutor));
}
-
- @Provides
- @SysUISingleton
- static StatusBarWindowView providesStatusBarWindowView(LayoutInflater layoutInflater) {
- StatusBarWindowView view =
- (StatusBarWindowView) layoutInflater.inflate(R.layout.super_status_bar,
- /* root= */ null);
- if (view == null) {
- throw new IllegalStateException(
- "R.layout.super_status_bar could not be properly inflated");
- }
- return view;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index 618c26b89196..d8b77426703e 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -20,18 +20,20 @@ import android.content.Context;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.tv.TvWMComponent;
-import com.android.systemui.wmshell.TvWMShellModule;
-import com.android.systemui.wmshell.WMShellModule;
+import com.android.wm.shell.dagger.TvWMShellModule;
+import com.android.wm.shell.dagger.WMShellModule;
import com.android.wm.shell.ShellCommandHandler;
import com.android.wm.shell.ShellInit;
import com.android.wm.shell.TaskViewFactory;
import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.bubbles.Bubbles;
+import com.android.wm.shell.dagger.WMSingleton;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
+import com.android.wm.shell.recents.RecentTasks;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelper;
@@ -110,4 +112,7 @@ public interface WMComponent {
@WMSingleton
Optional<TaskSurfaceHelper> getTaskSurfaceHelper();
+
+ @WMSingleton
+ Optional<RecentTasks> getRecentTasks();
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 669965bcbea5..25115200ba19 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -115,7 +115,7 @@ public class DozeLog implements Dumpable {
}
/**
- * Appends dozing event to the logs
+ * Appends dozing event to the logs. Logs current dozing state when entering/exiting AOD.
* @param dozing true if dozing, else false
*/
public void traceDozing(boolean dozing) {
@@ -124,6 +124,14 @@ public class DozeLog implements Dumpable {
}
/**
+ * Appends dozing event to the logs when dozing has changed in AOD.
+ * @param dozing true if we're now dozing, else false
+ */
+ public void traceDozingChanged(boolean dozing) {
+ mLogger.logDozingChanged(dozing);
+ }
+
+ /**
* Appends dozing event to the logs
* @param suppressed true if dozing is suppressed
*/
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
index d79bf22cced2..4ba6b51c83c8 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
@@ -66,6 +66,14 @@ class DozeLogger @Inject constructor(
})
}
+ fun logDozingChanged(isDozing: Boolean) {
+ buffer.log(TAG, INFO, {
+ bool1 = isDozing
+ }, {
+ "Dozing changed dozing=$bool1"
+ })
+ }
+
fun logDozingSuppressed(isDozingSuppressed: Boolean) {
buffer.log(TAG, INFO, {
bool1 = isDozingSuppressed
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index 8f1486b0c7cb..908397bd775c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -107,6 +107,11 @@ public class DozeScreenState implements DozeMachine.Part {
public void onAllAuthenticatorsRegistered() {
updateUdfpsController();
}
+
+ @Override
+ public void onEnrollmentsChanged() {
+ updateUdfpsController();
+ }
});
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 9d0591e4bda2..5c3e07fbaea1 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -659,7 +659,7 @@ public class DozeSensors {
@Override
@AnyThread
public void onTrigger(TriggerEvent event) {
- final Sensor sensor = mSensors[mDevicePosture];
+ final Sensor sensor = mSensors[mPosture];
mDozeLog.traceSensor(mPulseReason);
mHandler.post(mWakeLock.wrap(() -> {
if (DEBUG) Log.d(TAG, "onTrigger: " + triggerEventToString(event));
diff --git a/packages/SystemUI/src/com/android/systemui/egg/MLand.java b/packages/SystemUI/src/com/android/systemui/egg/MLand.java
deleted file mode 100644
index 0fb4432cbade..000000000000
--- a/packages/SystemUI/src/com/android/systemui/egg/MLand.java
+++ /dev/null
@@ -1,1440 +0,0 @@
-/*
- * Copyright (C) 2015 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.egg;
-
-import android.animation.LayoutTransition;
-import android.animation.TimeAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Matrix;
-import android.graphics.Outline;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.GradientDrawable;
-import android.media.AudioAttributes;
-import android.media.AudioManager;
-import android.os.Vibrator;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.InputDevice;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.R;
-
-import java.util.ArrayList;
-
-// It's like LLand, but "M"ultiplayer.
-public class MLand extends FrameLayout {
- public static final String TAG = "MLand";
-
- public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- public static final boolean DEBUG_DRAW = false; // DEBUG
-
- public static final boolean SHOW_TOUCHES = true;
-
- public static void L(String s, Object ... objects) {
- if (DEBUG) {
- Log.d(TAG, objects.length == 0 ? s : String.format(s, objects));
- }
- }
-
- public static final float PI_2 = (float) (Math.PI/2);
-
- public static final boolean AUTOSTART = true;
- public static final boolean HAVE_STARS = true;
-
- public static final float DEBUG_SPEED_MULTIPLIER = 0.5f; // only if DEBUG
- public static final boolean DEBUG_IDDQD = Log.isLoggable(TAG + ".iddqd", Log.DEBUG);
-
- public static final int DEFAULT_PLAYERS = 1;
- public static final int MIN_PLAYERS = 1;
- public static final int MAX_PLAYERS = 6;
-
- static final float CONTROLLER_VIBRATION_MULTIPLIER = 2f;
-
- private static class Params {
- public float TRANSLATION_PER_SEC;
- public int OBSTACLE_SPACING, OBSTACLE_PERIOD;
- public int BOOST_DV;
- public int PLAYER_HIT_SIZE;
- public int PLAYER_SIZE;
- public int OBSTACLE_WIDTH, OBSTACLE_STEM_WIDTH;
- public int OBSTACLE_GAP;
- public int OBSTACLE_MIN;
- public int BUILDING_WIDTH_MIN, BUILDING_WIDTH_MAX;
- public int BUILDING_HEIGHT_MIN;
- public int CLOUD_SIZE_MIN, CLOUD_SIZE_MAX;
- public int STAR_SIZE_MIN, STAR_SIZE_MAX;
- public int G;
- public int MAX_V;
- public float SCENERY_Z, OBSTACLE_Z, PLAYER_Z, PLAYER_Z_BOOST, HUD_Z;
- public Params(Resources res) {
- TRANSLATION_PER_SEC = res.getDimension(R.dimen.translation_per_sec);
- OBSTACLE_SPACING = res.getDimensionPixelSize(R.dimen.obstacle_spacing);
- OBSTACLE_PERIOD = (int) (OBSTACLE_SPACING / TRANSLATION_PER_SEC);
- BOOST_DV = res.getDimensionPixelSize(R.dimen.boost_dv);
- PLAYER_HIT_SIZE = res.getDimensionPixelSize(R.dimen.player_hit_size);
- PLAYER_SIZE = res.getDimensionPixelSize(R.dimen.player_size);
- OBSTACLE_WIDTH = res.getDimensionPixelSize(R.dimen.obstacle_width);
- OBSTACLE_STEM_WIDTH = res.getDimensionPixelSize(R.dimen.obstacle_stem_width);
- OBSTACLE_GAP = res.getDimensionPixelSize(R.dimen.obstacle_gap);
- OBSTACLE_MIN = res.getDimensionPixelSize(R.dimen.obstacle_height_min);
- BUILDING_HEIGHT_MIN = res.getDimensionPixelSize(R.dimen.building_height_min);
- BUILDING_WIDTH_MIN = res.getDimensionPixelSize(R.dimen.building_width_min);
- BUILDING_WIDTH_MAX = res.getDimensionPixelSize(R.dimen.building_width_max);
- CLOUD_SIZE_MIN = res.getDimensionPixelSize(R.dimen.cloud_size_min);
- CLOUD_SIZE_MAX = res.getDimensionPixelSize(R.dimen.cloud_size_max);
- STAR_SIZE_MIN = res.getDimensionPixelSize(R.dimen.star_size_min);
- STAR_SIZE_MAX = res.getDimensionPixelSize(R.dimen.star_size_max);
-
- G = res.getDimensionPixelSize(R.dimen.G);
- MAX_V = res.getDimensionPixelSize(R.dimen.max_v);
-
- SCENERY_Z = res.getDimensionPixelSize(R.dimen.scenery_z);
- OBSTACLE_Z = res.getDimensionPixelSize(R.dimen.obstacle_z);
- PLAYER_Z = res.getDimensionPixelSize(R.dimen.player_z);
- PLAYER_Z_BOOST = res.getDimensionPixelSize(R.dimen.player_z_boost);
- HUD_Z = res.getDimensionPixelSize(R.dimen.hud_z);
-
- // Sanity checking
- if (OBSTACLE_MIN <= OBSTACLE_WIDTH / 2) {
- L("error: obstacles might be too short, adjusting");
- OBSTACLE_MIN = OBSTACLE_WIDTH / 2 + 1;
- }
- }
- }
-
- private TimeAnimator mAnim;
- private Vibrator mVibrator;
- private AudioManager mAudioManager;
- private final AudioAttributes mAudioAttrs = new AudioAttributes.Builder()
- .setUsage(AudioAttributes.USAGE_GAME).build();
-
- private View mSplash;
- private ViewGroup mScoreFields;
-
- private ArrayList<Player> mPlayers = new ArrayList<Player>();
- private ArrayList<Obstacle> mObstaclesInPlay = new ArrayList<Obstacle>();
-
- private float t, dt;
-
- private float mLastPipeTime; // in sec
- private int mCurrentPipeId; // basically, equivalent to the current score
- private int mWidth, mHeight;
- private boolean mAnimating, mPlaying;
- private boolean mFrozen; // after death, a short backoff
- private int mCountdown = 0;
- private boolean mFlipped;
-
- private int mTaps;
-
- private int mTimeOfDay;
- private static final int DAY = 0, NIGHT = 1, TWILIGHT = 2, SUNSET = 3;
- private static final int[][] SKIES = {
- { 0xFFc0c0FF, 0xFFa0a0FF }, // DAY
- { 0xFF000010, 0xFF000000 }, // NIGHT
- { 0xFF000040, 0xFF000010 }, // TWILIGHT
- { 0xFFa08020, 0xFF204080 }, // SUNSET
- };
-
- private int mScene;
- private static final int SCENE_CITY = 0, SCENE_TX = 1, SCENE_ZRH = 2;
- private static final int SCENE_COUNT = 3;
-
- private static Params PARAMS;
-
- private static float dp = 1f;
-
- private Paint mTouchPaint, mPlayerTracePaint;
-
- private ArrayList<Integer> mGameControllers = new ArrayList<>();
-
- public MLand(Context context) {
- this(context, null);
- }
-
- public MLand(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public MLand(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
- mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
- setFocusable(true);
- PARAMS = new Params(getResources());
- mTimeOfDay = irand(0, SKIES.length - 1);
- mScene = irand(0, SCENE_COUNT);
-
- mTouchPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mTouchPaint.setColor(0x80FFFFFF);
- mTouchPaint.setStyle(Paint.Style.FILL);
-
- mPlayerTracePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mPlayerTracePaint.setColor(0x80FFFFFF);
- mPlayerTracePaint.setStyle(Paint.Style.STROKE);
- mPlayerTracePaint.setStrokeWidth(2 * dp);
-
- // we assume everything will be laid out left|top
- setLayoutDirection(LAYOUT_DIRECTION_LTR);
-
- setupPlayers(DEFAULT_PLAYERS);
-
- MetricsLogger.count(getContext(), "egg_mland_create", 1);
- }
-
- @Override
- public void onAttachedToWindow() {
- super.onAttachedToWindow();
- dp = getResources().getDisplayMetrics().density;
-
- reset();
- if (AUTOSTART) {
- start(false);
- }
- }
-
- @Override
- public boolean willNotDraw() {
- return !DEBUG;
- }
-
- public int getGameWidth() { return mWidth; }
- public int getGameHeight() { return mHeight; }
- public float getGameTime() { return t; }
- public float getLastTimeStep() { return dt; }
-
- public void setScoreFieldHolder(ViewGroup vg) {
- mScoreFields = vg;
- if (vg != null) {
- final LayoutTransition lt = new LayoutTransition();
- lt.setDuration(250);
- mScoreFields.setLayoutTransition(lt);
- }
- for (Player p : mPlayers) {
- mScoreFields.addView(p.mScoreField,
- new MarginLayoutParams(
- MarginLayoutParams.WRAP_CONTENT,
- MarginLayoutParams.MATCH_PARENT));
- }
- }
-
- public void setSplash(View v) {
- mSplash = v;
- }
-
- public static boolean isGamePad(InputDevice dev) {
- int sources = dev.getSources();
-
- // Verify that the device has gamepad buttons, control sticks, or both.
- return (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
- || ((sources & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK));
- }
-
- public ArrayList getGameControllers() {
- mGameControllers.clear();
- int[] deviceIds = InputDevice.getDeviceIds();
- for (int deviceId : deviceIds) {
- InputDevice dev = InputDevice.getDevice(deviceId);
- if (isGamePad(dev)) {
- if (!mGameControllers.contains(deviceId)) {
- mGameControllers.add(deviceId);
- }
- }
- }
- return mGameControllers;
- }
-
- public int getControllerPlayer(int id) {
- final int player = mGameControllers.indexOf(id);
- if (player < 0 || player >= mPlayers.size()) return 0;
- return player;
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- dp = getResources().getDisplayMetrics().density;
-
- stop();
-
- reset();
- if (AUTOSTART) {
- start(false);
- }
- }
-
- final static float hsv[] = {0, 0, 0};
-
- private static float luma(int bgcolor) {
- return 0.2126f * (float) (bgcolor & 0xFF0000) / 0xFF0000
- + 0.7152f * (float) (bgcolor & 0xFF00) / 0xFF00
- + 0.0722f * (float) (bgcolor & 0xFF) / 0xFF;
- }
-
- public Player getPlayer(int i) {
- return i < mPlayers.size() ? mPlayers.get(i) : null;
- }
-
- private int addPlayerInternal(Player p) {
- mPlayers.add(p);
- realignPlayers();
- TextView scoreField = (TextView)
- LayoutInflater.from(getContext()).inflate(R.layout.mland_scorefield, null);
- if (mScoreFields != null) {
- mScoreFields.addView(scoreField,
- new MarginLayoutParams(
- MarginLayoutParams.WRAP_CONTENT,
- MarginLayoutParams.MATCH_PARENT));
- }
- p.setScoreField(scoreField);
- return mPlayers.size()-1;
- }
-
- private void removePlayerInternal(Player p) {
- if (mPlayers.remove(p)) {
- removeView(p);
- mScoreFields.removeView(p.mScoreField);
- realignPlayers();
- }
- }
-
- private void realignPlayers() {
- final int N = mPlayers.size();
- float x = (mWidth - (N-1) * PARAMS.PLAYER_SIZE) / 2;
- for (int i=0; i<N; i++) {
- final Player p = mPlayers.get(i);
- p.setX(x);
- x += PARAMS.PLAYER_SIZE;
- }
- }
-
- private void clearPlayers() {
- while (mPlayers.size() > 0) {
- removePlayerInternal(mPlayers.get(0));
- }
- }
-
- public void setupPlayers(int num) {
- clearPlayers();
- for (int i=0; i<num; i++) {
- addPlayerInternal(Player.create(this));
- }
- }
-
- public void addPlayer() {
- if (getNumPlayers() == MAX_PLAYERS) return;
- addPlayerInternal(Player.create(this));
- }
-
- public int getNumPlayers() {
- return mPlayers.size();
- }
-
- public void removePlayer() {
- if (getNumPlayers() == MIN_PLAYERS) return;
- removePlayerInternal(mPlayers.get(mPlayers.size() - 1));
- }
-
- private void thump(int playerIndex, long ms) {
- if (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) {
- // No interruptions. Not even game haptics.
- return;
- }
- if (playerIndex < mGameControllers.size()) {
- int controllerId = mGameControllers.get(playerIndex);
- InputDevice dev = InputDevice.getDevice(controllerId);
- if (dev != null && dev.getVibrator().hasVibrator()) {
- dev.getVibrator().vibrate(
- (long) (ms * CONTROLLER_VIBRATION_MULTIPLIER),
- mAudioAttrs);
- return;
- }
- }
- mVibrator.vibrate(ms, mAudioAttrs);
- }
-
- public void reset() {
- L("reset");
- final Drawable sky = new GradientDrawable(
- GradientDrawable.Orientation.BOTTOM_TOP,
- SKIES[mTimeOfDay]
- );
- sky.setDither(true);
- setBackground(sky);
-
- mFlipped = frand() > 0.5f;
- setScaleX(mFlipped ? -1 : 1);
-
- int i = getChildCount();
- while (i-->0) {
- final View v = getChildAt(i);
- if (v instanceof GameView) {
- removeViewAt(i);
- }
- }
-
- mObstaclesInPlay.clear();
- mCurrentPipeId = 0;
-
- mWidth = getWidth();
- mHeight = getHeight();
-
- boolean showingSun = (mTimeOfDay == DAY || mTimeOfDay == SUNSET) && frand() > 0.25;
- if (showingSun) {
- final Star sun = new Star(getContext());
- sun.setBackgroundResource(R.drawable.sun);
- final int w = getResources().getDimensionPixelSize(R.dimen.sun_size);
- sun.setTranslationX(frand(w, mWidth-w));
- if (mTimeOfDay == DAY) {
- sun.setTranslationY(frand(w, (mHeight * 0.66f)));
- sun.getBackground().setTint(0);
- } else {
- sun.setTranslationY(frand(mHeight * 0.66f, mHeight - w));
- sun.getBackground().setTintMode(PorterDuff.Mode.SRC_ATOP);
- sun.getBackground().setTint(0xC0FF8000);
-
- }
- addView(sun, new LayoutParams(w, w));
- }
- if (!showingSun) {
- final boolean dark = mTimeOfDay == NIGHT || mTimeOfDay == TWILIGHT;
- final float ff = frand();
- if ((dark && ff < 0.75f) || ff < 0.5f) {
- final Star moon = new Star(getContext());
- moon.setBackgroundResource(R.drawable.moon);
- moon.getBackground().setAlpha(dark ? 255 : 128);
- moon.setScaleX(frand() > 0.5 ? -1 : 1);
- moon.setRotation(moon.getScaleX() * frand(5, 30));
- final int w = getResources().getDimensionPixelSize(R.dimen.sun_size);
- moon.setTranslationX(frand(w, mWidth - w));
- moon.setTranslationY(frand(w, mHeight - w));
- addView(moon, new LayoutParams(w, w));
- }
- }
-
- final int mh = mHeight / 6;
- final boolean cloudless = frand() < 0.25;
- final int N = 20;
- for (i=0; i<N; i++) {
- final float r1 = frand();
- final Scenery s;
- if (HAVE_STARS && r1 < 0.3 && mTimeOfDay != DAY) {
- s = new Star(getContext());
- } else if (r1 < 0.6 && !cloudless) {
- s = new Cloud(getContext());
- } else {
- switch (mScene) {
- case SCENE_ZRH:
- s = new Mountain(getContext());
- break;
- case SCENE_TX:
- s = new Cactus(getContext());
- break;
- case SCENE_CITY:
- default:
- s = new Building(getContext());
- break;
- }
- s.z = (float) i / N;
- // no more shadows for these things
- //s.setTranslationZ(PARAMS.SCENERY_Z * (1+s.z));
- s.v = 0.85f * s.z; // buildings move proportional to their distance
- if (mScene == SCENE_CITY) {
- s.setBackgroundColor(Color.GRAY);
- s.h = irand(PARAMS.BUILDING_HEIGHT_MIN, mh);
- }
- final int c = (int)(255f*s.z);
- final Drawable bg = s.getBackground();
- if (bg != null) bg.setColorFilter(Color.rgb(c,c,c), PorterDuff.Mode.MULTIPLY);
- }
- final LayoutParams lp = new LayoutParams(s.w, s.h);
- if (s instanceof Building) {
- lp.gravity = Gravity.BOTTOM;
- } else {
- lp.gravity = Gravity.TOP;
- final float r = frand();
- if (s instanceof Star) {
- lp.topMargin = (int) (r * r * mHeight);
- } else {
- lp.topMargin = (int) (1 - r*r * mHeight/2) + mHeight/2;
- }
- }
-
-
- addView(s, lp);
- s.setTranslationX(frand(-lp.width, mWidth + lp.width));
- }
-
- for (Player p : mPlayers) {
- addView(p); // put it back!
- p.reset();
- }
-
- realignPlayers();
-
- if (mAnim != null) {
- mAnim.cancel();
- }
- mAnim = new TimeAnimator();
- mAnim.setTimeListener(new TimeAnimator.TimeListener() {
- @Override
- public void onTimeUpdate(TimeAnimator timeAnimator, long t, long dt) {
- step(t, dt);
- }
- });
- }
-
- public void start(boolean startPlaying) {
- L("start(startPlaying=%s)", startPlaying ? "true" : "false");
- if (startPlaying && mCountdown <= 0) {
- showSplash();
-
- mSplash.findViewById(R.id.play_button).setEnabled(false);
-
- final View playImage = mSplash.findViewById(R.id.play_button_image);
- final TextView playText = (TextView) mSplash.findViewById(R.id.play_button_text);
-
- playImage.animate().alpha(0f);
- playText.animate().alpha(1f);
-
- mCountdown = 3;
- post(new Runnable() {
- @Override
- public void run() {
- if (mCountdown == 0) {
- startPlaying();
- } else {
- postDelayed(this, 500);
- }
- playText.setText(String.valueOf(mCountdown));
- mCountdown--;
- }
- });
- }
-
- for (Player p : mPlayers) {
- p.setVisibility(View.INVISIBLE);
- }
-
- if (!mAnimating) {
- mAnim.start();
- mAnimating = true;
- }
- }
-
- public void hideSplash() {
- if (mSplash != null && mSplash.getVisibility() == View.VISIBLE) {
- mSplash.setClickable(false);
- mSplash.animate().alpha(0).translationZ(0).setDuration(300).withEndAction(
- new Runnable() {
- @Override
- public void run() {
- mSplash.setVisibility(View.GONE);
- }
- }
- );
- }
- }
-
- public void showSplash() {
- if (mSplash != null && mSplash.getVisibility() != View.VISIBLE) {
- mSplash.setClickable(true);
- mSplash.setAlpha(0f);
- mSplash.setVisibility(View.VISIBLE);
- mSplash.animate().alpha(1f).setDuration(1000);
- mSplash.findViewById(R.id.play_button_image).setAlpha(1f);
- mSplash.findViewById(R.id.play_button_text).setAlpha(0f);
- mSplash.findViewById(R.id.play_button).setEnabled(true);
- mSplash.findViewById(R.id.play_button).requestFocus();
- }
- }
-
- public void startPlaying() {
- mPlaying = true;
-
- t = 0;
- // there's a sucker born every OBSTACLE_PERIOD
- mLastPipeTime = getGameTime() - PARAMS.OBSTACLE_PERIOD;
-
- hideSplash();
-
- realignPlayers();
- mTaps = 0;
-
- final int N = mPlayers.size();
- MetricsLogger.histogram(getContext(), "egg_mland_players", N);
- for (int i=0; i<N; i++) {
- final Player p = mPlayers.get(i);
- p.setVisibility(View.VISIBLE);
- p.reset();
- p.start();
- p.boost(-1, -1); // start you off flying!
- p.unboost(); // not forever, though
- }
- }
-
- public void stop() {
- if (mAnimating) {
- mAnim.cancel();
- mAnim = null;
- mAnimating = false;
- mPlaying = false;
- mTimeOfDay = irand(0, SKIES.length - 1); // for next reset
- mScene = irand(0, SCENE_COUNT);
- mFrozen = true;
- for (Player p : mPlayers) {
- p.die();
- }
- postDelayed(new Runnable() {
- @Override
- public void run() {
- mFrozen = false;
- }
- }, 250);
- }
- }
-
- public static final float lerp(float x, float a, float b) {
- return (b - a) * x + a;
- }
-
- public static final float rlerp(float v, float a, float b) {
- return (v - a) / (b - a);
- }
-
- public static final float clamp(float f) {
- return f < 0f ? 0f : f > 1f ? 1f : f;
- }
-
- public static final float frand() {
- return (float) Math.random();
- }
-
- public static final float frand(float a, float b) {
- return lerp(frand(), a, b);
- }
-
- public static final int irand(int a, int b) {
- return Math.round(frand((float) a, (float) b));
- }
-
- public static int pick(int[] l) {
- return l[irand(0, l.length-1)];
- }
-
- private void step(long t_ms, long dt_ms) {
- t = t_ms / 1000f; // seconds
- dt = dt_ms / 1000f;
-
- if (DEBUG) {
- t *= DEBUG_SPEED_MULTIPLIER;
- dt *= DEBUG_SPEED_MULTIPLIER;
- }
-
- // 1. Move all objects and update bounds
- final int N = getChildCount();
- int i = 0;
- for (; i<N; i++) {
- final View v = getChildAt(i);
- if (v instanceof GameView) {
- ((GameView) v).step(t_ms, dt_ms, t, dt);
- }
- }
-
- if (mPlaying) {
- int livingPlayers = 0;
- for (i = 0; i < mPlayers.size(); i++) {
- final Player p = getPlayer(i);
-
- if (p.mAlive) {
- // 2. Check for altitude
- if (p.below(mHeight)) {
- if (DEBUG_IDDQD) {
- poke(i);
- unpoke(i);
- } else {
- L("player %d hit the floor", i);
- thump(i, 80);
- p.die();
- }
- }
-
- // 3. Check for obstacles
- int maxPassedStem = 0;
- for (int j = mObstaclesInPlay.size(); j-- > 0; ) {
- final Obstacle ob = mObstaclesInPlay.get(j);
- if (ob.intersects(p) && !DEBUG_IDDQD) {
- L("player hit an obstacle");
- thump(i, 80);
- p.die();
- } else if (ob.cleared(p)) {
- if (ob instanceof Stem) {
- maxPassedStem = Math.max(maxPassedStem, ((Stem)ob).id);
- }
- }
- }
-
- if (maxPassedStem > p.mScore) {
- p.addScore(1);
- }
- }
-
- if (p.mAlive) livingPlayers++;
- }
-
- if (livingPlayers == 0) {
- stop();
-
- MetricsLogger.count(getContext(), "egg_mland_taps", mTaps);
- mTaps = 0;
- final int playerCount = mPlayers.size();
- for (int pi=0; pi<playerCount; pi++) {
- final Player p = mPlayers.get(pi);
- MetricsLogger.histogram(getContext(), "egg_mland_score", p.getScore());
- }
- }
- }
-
- // 4. Handle edge of screen
- // Walk backwards to make sure removal is safe
- while (i-->0) {
- final View v = getChildAt(i);
- if (v instanceof Obstacle) {
- if (v.getTranslationX() + v.getWidth() < 0) {
- removeViewAt(i);
- mObstaclesInPlay.remove(v);
- }
- } else if (v instanceof Scenery) {
- final Scenery s = (Scenery) v;
- if (v.getTranslationX() + s.w < 0) {
- v.setTranslationX(getWidth());
- }
- }
- }
-
- // 3. Time for more obstacles!
- if (mPlaying && (t - mLastPipeTime) > PARAMS.OBSTACLE_PERIOD) {
- mLastPipeTime = t;
- mCurrentPipeId ++;
- final int obstacley =
- (int)(frand() * (mHeight - 2*PARAMS.OBSTACLE_MIN - PARAMS.OBSTACLE_GAP)) +
- PARAMS.OBSTACLE_MIN;
-
- final int inset = (PARAMS.OBSTACLE_WIDTH - PARAMS.OBSTACLE_STEM_WIDTH) / 2;
- final int yinset = PARAMS.OBSTACLE_WIDTH/2;
-
- final int d1 = irand(0,250);
- final Obstacle s1 = new Stem(getContext(), obstacley - yinset, false);
- addView(s1, new LayoutParams(
- PARAMS.OBSTACLE_STEM_WIDTH,
- (int) s1.h,
- Gravity.TOP|Gravity.LEFT));
- s1.setTranslationX(mWidth+inset);
- s1.setTranslationY(-s1.h-yinset);
- s1.setTranslationZ(PARAMS.OBSTACLE_Z*0.75f);
- s1.animate()
- .translationY(0)
- .setStartDelay(d1)
- .setDuration(250);
- mObstaclesInPlay.add(s1);
-
- final Obstacle p1 = new Pop(getContext(), PARAMS.OBSTACLE_WIDTH);
- addView(p1, new LayoutParams(
- PARAMS.OBSTACLE_WIDTH,
- PARAMS.OBSTACLE_WIDTH,
- Gravity.TOP|Gravity.LEFT));
- p1.setTranslationX(mWidth);
- p1.setTranslationY(-PARAMS.OBSTACLE_WIDTH);
- p1.setTranslationZ(PARAMS.OBSTACLE_Z);
- p1.setScaleX(0.25f);
- p1.setScaleY(-0.25f);
- p1.animate()
- .translationY(s1.h-inset)
- .scaleX(1f)
- .scaleY(-1f)
- .setStartDelay(d1)
- .setDuration(250);
- mObstaclesInPlay.add(p1);
-
- final int d2 = irand(0,250);
- final Obstacle s2 = new Stem(getContext(),
- mHeight - obstacley - PARAMS.OBSTACLE_GAP - yinset,
- true);
- addView(s2, new LayoutParams(
- PARAMS.OBSTACLE_STEM_WIDTH,
- (int) s2.h,
- Gravity.TOP|Gravity.LEFT));
- s2.setTranslationX(mWidth+inset);
- s2.setTranslationY(mHeight+yinset);
- s2.setTranslationZ(PARAMS.OBSTACLE_Z*0.75f);
- s2.animate()
- .translationY(mHeight-s2.h)
- .setStartDelay(d2)
- .setDuration(400);
- mObstaclesInPlay.add(s2);
-
- final Obstacle p2 = new Pop(getContext(), PARAMS.OBSTACLE_WIDTH);
- addView(p2, new LayoutParams(
- PARAMS.OBSTACLE_WIDTH,
- PARAMS.OBSTACLE_WIDTH,
- Gravity.TOP|Gravity.LEFT));
- p2.setTranslationX(mWidth);
- p2.setTranslationY(mHeight);
- p2.setTranslationZ(PARAMS.OBSTACLE_Z);
- p2.setScaleX(0.25f);
- p2.setScaleY(0.25f);
- p2.animate()
- .translationY(mHeight-s2.h-yinset)
- .scaleX(1f)
- .scaleY(1f)
- .setStartDelay(d2)
- .setDuration(400);
- mObstaclesInPlay.add(p2);
- }
-
- if (SHOW_TOUCHES || DEBUG_DRAW) invalidate();
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- L("touch: %s", ev);
- final int actionIndex = ev.getActionIndex();
- final float x = ev.getX(actionIndex);
- final float y = ev.getY(actionIndex);
- int playerIndex = (int) (getNumPlayers() * (x / getWidth()));
- if (mFlipped) playerIndex = getNumPlayers() - 1 - playerIndex;
- switch (ev.getActionMasked()) {
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_POINTER_DOWN:
- poke(playerIndex, x, y);
- return true;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_POINTER_UP:
- unpoke(playerIndex);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean onTrackballEvent(MotionEvent ev) {
- L("trackball: %s", ev);
- switch (ev.getAction()) {
- case MotionEvent.ACTION_DOWN:
- poke(0);
- return true;
- case MotionEvent.ACTION_UP:
- unpoke(0);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent ev) {
- L("keyDown: %d", keyCode);
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_CENTER:
- case KeyEvent.KEYCODE_DPAD_UP:
- case KeyEvent.KEYCODE_SPACE:
- case KeyEvent.KEYCODE_ENTER:
- case KeyEvent.KEYCODE_BUTTON_A:
- int player = getControllerPlayer(ev.getDeviceId());
- poke(player);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent ev) {
- L("keyDown: %d", keyCode);
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_CENTER:
- case KeyEvent.KEYCODE_DPAD_UP:
- case KeyEvent.KEYCODE_SPACE:
- case KeyEvent.KEYCODE_ENTER:
- case KeyEvent.KEYCODE_BUTTON_A:
- int player = getControllerPlayer(ev.getDeviceId());
- unpoke(player);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean onGenericMotionEvent (MotionEvent ev) {
- L("generic: %s", ev);
- return false;
- }
-
- private void poke(int playerIndex) {
- poke(playerIndex, -1, -1);
- }
-
- private void poke(int playerIndex, float x, float y) {
- L("poke(%d)", playerIndex);
- if (mFrozen) return;
- if (!mAnimating) {
- reset();
- }
- if (!mPlaying) {
- start(true);
- } else {
- final Player p = getPlayer(playerIndex);
- if (p == null) return; // no player for this controller
- p.boost(x, y);
- mTaps++;
- if (DEBUG) {
- p.dv *= DEBUG_SPEED_MULTIPLIER;
- p.animate().setDuration((long) (200 / DEBUG_SPEED_MULTIPLIER));
- }
- }
- }
-
- private void unpoke(int playerIndex) {
- L("unboost(%d)", playerIndex);
- if (mFrozen || !mAnimating || !mPlaying) return;
- final Player p = getPlayer(playerIndex);
- if (p == null) return; // no player for this controller
- p.unboost();
- }
-
- @Override
- public void onDraw(Canvas c) {
- super.onDraw(c);
-
- if (SHOW_TOUCHES) {
- for (Player p : mPlayers) {
- if (p.mTouchX > 0) {
- mTouchPaint.setColor(0x80FFFFFF & p.color);
- mPlayerTracePaint.setColor(0x80FFFFFF & p.color);
- float x1 = p.mTouchX;
- float y1 = p.mTouchY;
- c.drawCircle(x1, y1, 100, mTouchPaint);
- float x2 = p.getX() + p.getPivotX();
- float y2 = p.getY() + p.getPivotY();
- float angle = PI_2 - (float) Math.atan2(x2-x1, y2-y1);
- x1 += 100*Math.cos(angle);
- y1 += 100*Math.sin(angle);
- c.drawLine(x1, y1, x2, y2, mPlayerTracePaint);
- }
- }
- }
-
- if (!DEBUG_DRAW) return;
-
- final Paint pt = new Paint();
- pt.setColor(0xFFFFFFFF);
- for (Player p : mPlayers) {
- final int L = p.corners.length;
- final int N = L / 2;
- for (int i = 0; i < N; i++) {
- final int x = (int) p.corners[i * 2];
- final int y = (int) p.corners[i * 2 + 1];
- c.drawCircle(x, y, 4, pt);
- c.drawLine(x, y,
- p.corners[(i * 2 + 2) % L],
- p.corners[(i * 2 + 3) % L],
- pt);
- }
- }
-
- pt.setStyle(Paint.Style.STROKE);
- pt.setStrokeWidth(getResources().getDisplayMetrics().density);
-
- final int M = getChildCount();
- pt.setColor(0x8000FF00);
- for (int i=0; i<M; i++) {
- final View v = getChildAt(i);
- if (v instanceof Player) continue;
- if (!(v instanceof GameView)) continue;
- if (v instanceof Pop) {
- final Pop pop = (Pop) v;
- c.drawCircle(pop.cx, pop.cy, pop.r, pt);
- } else {
- final Rect r = new Rect();
- v.getHitRect(r);
- c.drawRect(r, pt);
- }
- }
-
- pt.setColor(Color.BLACK);
- final StringBuilder sb = new StringBuilder("obstacles: ");
- for (Obstacle ob : mObstaclesInPlay) {
- sb.append(ob.hitRect.toShortString());
- sb.append(" ");
- }
- pt.setTextSize(20f);
- c.drawText(sb.toString(), 20, 100, pt);
- }
-
- static final Rect sTmpRect = new Rect();
-
- private interface GameView {
- public void step(long t_ms, long dt_ms, float t, float dt);
- }
-
- private static class Player extends ImageView implements GameView {
- public float dv;
- public int color;
- private MLand mLand;
- private boolean mBoosting;
- private float mTouchX = -1, mTouchY = -1;
- private boolean mAlive;
- private int mScore;
- private TextView mScoreField;
-
- private final int[] sColors = new int[] {
- //0xFF78C557,
- 0xFFDB4437,
- 0xFF3B78E7,
- 0xFFF4B400,
- 0xFF0F9D58,
- 0xFF7B1880,
- 0xFF9E9E9E,
- };
- static int sNextColor = 0;
-
- private final float[] sHull = new float[] {
- 0.3f, 0f, // left antenna
- 0.7f, 0f, // right antenna
- 0.92f, 0.33f, // off the right shoulder of Orion
- 0.92f, 0.75f, // right hand (our right, not his right)
- 0.6f, 1f, // right foot
- 0.4f, 1f, // left foot BLUE!
- 0.08f, 0.75f, // sinistram
- 0.08f, 0.33f, // cold shoulder
- };
- public final float[] corners = new float[sHull.length];
-
- public static Player create(MLand land) {
- final Player p = new Player(land.getContext());
- p.mLand = land;
- p.reset();
- p.setVisibility(View.INVISIBLE);
- land.addView(p, new LayoutParams(PARAMS.PLAYER_SIZE, PARAMS.PLAYER_SIZE));
- return p;
- }
-
- private void setScore(int score) {
- mScore = score;
- if (mScoreField != null) {
- mScoreField.setText(DEBUG_IDDQD ? "??" : String.valueOf(score));
- }
- }
-
- public int getScore() {
- return mScore;
- }
-
- private void addScore(int incr) {
- setScore(mScore + incr);
- }
-
- public void setScoreField(TextView tv) {
- mScoreField = tv;
- if (tv != null) {
- setScore(mScore); // reapply
- //mScoreField.setBackgroundResource(R.drawable.scorecard);
- mScoreField.getBackground().setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
- mScoreField.setTextColor(luma(color) > 0.7f ? 0xFF000000 : 0xFFFFFFFF);
- }
- }
-
- public void reset() {
- //setX(mLand.mWidth / 2);
- setY(mLand.mHeight / 2
- + (int)(Math.random() * PARAMS.PLAYER_SIZE)
- - PARAMS.PLAYER_SIZE / 2);
- setScore(0);
- setScoreField(mScoreField); // refresh color
- mBoosting = false;
- dv = 0;
- }
-
- public Player(Context context) {
- super(context);
-
- setBackgroundResource(R.drawable.android);
- getBackground().setTintMode(PorterDuff.Mode.SRC_ATOP);
- color = sColors[(sNextColor++%sColors.length)];
- getBackground().setTint(color);
- setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- final int w = view.getWidth();
- final int h = view.getHeight();
- final int ix = (int) (w * 0.3f);
- final int iy = (int) (h * 0.2f);
- outline.setRect(ix, iy, w - ix, h - iy);
- }
- });
- }
-
- public void prepareCheckIntersections() {
- final int inset = (PARAMS.PLAYER_SIZE - PARAMS.PLAYER_HIT_SIZE)/2;
- final int scale = PARAMS.PLAYER_HIT_SIZE;
- final int N = sHull.length/2;
- for (int i=0; i<N; i++) {
- corners[i*2] = scale * sHull[i*2] + inset;
- corners[i*2+1] = scale * sHull[i*2+1] + inset;
- }
- final Matrix m = getMatrix();
- m.mapPoints(corners);
- }
-
- public boolean below(int h) {
- final int N = corners.length/2;
- for (int i=0; i<N; i++) {
- final int y = (int) corners[i*2+1];
- if (y >= h) return true;
- }
- return false;
- }
-
- public void step(long t_ms, long dt_ms, float t, float dt) {
- if (!mAlive) {
- // float away with the garbage
- setTranslationX(getTranslationX()-PARAMS.TRANSLATION_PER_SEC*dt);
- return;
- }
-
- if (mBoosting) {
- dv = -PARAMS.BOOST_DV;
- } else {
- dv += PARAMS.G;
- }
- if (dv < -PARAMS.MAX_V) dv = -PARAMS.MAX_V;
- else if (dv > PARAMS.MAX_V) dv = PARAMS.MAX_V;
-
- final float y = getTranslationY() + dv * dt;
- setTranslationY(y < 0 ? 0 : y);
- setRotation(
- 90 + lerp(clamp(rlerp(dv, PARAMS.MAX_V, -1 * PARAMS.MAX_V)), 90, -90));
-
- prepareCheckIntersections();
- }
-
- public void boost(float x, float y) {
- mTouchX = x;
- mTouchY = y;
- boost();
- }
-
- public void boost() {
- mBoosting = true;
- dv = -PARAMS.BOOST_DV;
-
- animate().cancel();
- animate()
- .scaleX(1.25f)
- .scaleY(1.25f)
- .translationZ(PARAMS.PLAYER_Z_BOOST)
- .setDuration(100);
- setScaleX(1.25f);
- setScaleY(1.25f);
- }
-
- public void unboost() {
- mBoosting = false;
- mTouchX = mTouchY = -1;
-
- animate().cancel();
- animate()
- .scaleX(1f)
- .scaleY(1f)
- .translationZ(PARAMS.PLAYER_Z)
- .setDuration(200);
- }
-
- public void die() {
- mAlive = false;
- if (mScoreField != null) {
- //mScoreField.setTextColor(0xFFFFFFFF);
- //mScoreField.getBackground().setColorFilter(0xFF666666, PorterDuff.Mode.SRC_ATOP);
- //mScoreField.setBackgroundResource(R.drawable.scorecard_gameover);
- }
- }
-
- public void start() {
- mAlive = true;
- }
- }
-
- private class Obstacle extends View implements GameView {
- public float h;
-
- public final Rect hitRect = new Rect();
-
- public Obstacle(Context context, float h) {
- super(context);
- setBackgroundColor(0xFFFF0000);
- this.h = h;
- }
-
- public boolean intersects(Player p) {
- final int N = p.corners.length/2;
- for (int i=0; i<N; i++) {
- final int x = (int) p.corners[i*2];
- final int y = (int) p.corners[i*2+1];
- if (hitRect.contains(x, y)) return true;
- }
- return false;
- }
-
- public boolean cleared(Player p) {
- final int N = p.corners.length/2;
- for (int i=0; i<N; i++) {
- final int x = (int) p.corners[i*2];
- if (hitRect.right >= x) return false;
- }
- return true;
- }
-
- @Override
- public void step(long t_ms, long dt_ms, float t, float dt) {
- setTranslationX(getTranslationX()-PARAMS.TRANSLATION_PER_SEC*dt);
- getHitRect(hitRect);
- }
- }
-
- static final int[] ANTENNAE = new int[] {R.drawable.mm_antennae, R.drawable.mm_antennae2};
- static final int[] EYES = new int[] {R.drawable.mm_eyes, R.drawable.mm_eyes2};
- static final int[] MOUTHS = new int[] {R.drawable.mm_mouth1, R.drawable.mm_mouth2,
- R.drawable.mm_mouth3, R.drawable.mm_mouth4};
- private class Pop extends Obstacle {
- int mRotate;
- int cx, cy, r;
- // The marshmallow illustration and hitbox is 2/3 the size of its container.
- Drawable antenna, eyes, mouth;
-
-
- public Pop(Context context, float h) {
- super(context, h);
- setBackgroundResource(R.drawable.mm_head);
- antenna = context.getDrawable(pick(ANTENNAE));
- if (frand() > 0.5f) {
- eyes = context.getDrawable(pick(EYES));
- if (frand() > 0.8f) {
- mouth = context.getDrawable(pick(MOUTHS));
- }
- }
- setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- final int pad = (int) (getWidth() * 1f/6);
- outline.setOval(pad, pad, getWidth()-pad, getHeight()-pad);
- }
- });
- }
-
- public boolean intersects(Player p) {
- final int N = p.corners.length/2;
- for (int i=0; i<N; i++) {
- final int x = (int) p.corners[i*2];
- final int y = (int) p.corners[i*2+1];
- if (Math.hypot(x-cx, y-cy) <= r) return true;
- }
- return false;
- }
-
- @Override
- public void step(long t_ms, long dt_ms, float t, float dt) {
- super.step(t_ms, dt_ms, t, dt);
- if (mRotate != 0) {
- setRotation(getRotation() + dt * 45 * mRotate);
- }
-
- cx = (hitRect.left + hitRect.right)/2;
- cy = (hitRect.top + hitRect.bottom)/2;
- r = getWidth() / 3; // see above re 2/3 container size
- }
-
- @Override
- public void onDraw(Canvas c) {
- super.onDraw(c);
- if (antenna != null) {
- antenna.setBounds(0, 0, c.getWidth(), c.getHeight());
- antenna.draw(c);
- }
- if (eyes != null) {
- eyes.setBounds(0, 0, c.getWidth(), c.getHeight());
- eyes.draw(c);
- }
- if (mouth != null) {
- mouth.setBounds(0, 0, c.getWidth(), c.getHeight());
- mouth.draw(c);
- }
- }
- }
-
- private class Stem extends Obstacle {
- Paint mPaint = new Paint();
- Path mShadow = new Path();
- GradientDrawable mGradient = new GradientDrawable();
- boolean mDrawShadow;
- Path mJandystripe;
- Paint mPaint2;
- int id; // use this to track which pipes have been cleared
-
- public Stem(Context context, float h, boolean drawShadow) {
- super(context, h);
- id = mCurrentPipeId;
-
- mDrawShadow = drawShadow;
- setBackground(null);
- mGradient.setOrientation(GradientDrawable.Orientation.LEFT_RIGHT);
- mPaint.setColor(0xFF000000);
- mPaint.setColorFilter(new PorterDuffColorFilter(0x22000000, PorterDuff.Mode.MULTIPLY));
-
- if (frand() < 0.01f) {
- mGradient.setColors(new int[]{0xFFFFFFFF, 0xFFDDDDDD});
- mJandystripe = new Path();
- mPaint2 = new Paint();
- mPaint2.setColor(0xFFFF0000);
- mPaint2.setColorFilter(new PorterDuffColorFilter(0xFFFF0000, PorterDuff.Mode.MULTIPLY));
- } else {
- //mPaint.setColor(0xFFA1887F);
- mGradient.setColors(new int[]{0xFFBCAAA4, 0xFFA1887F});
- }
- }
-
- @Override
- public void onAttachedToWindow() {
- super.onAttachedToWindow();
- setWillNotDraw(false);
- setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRect(0, 0, getWidth(), getHeight());
- }
- });
- }
- @Override
- public void onDraw(Canvas c) {
- final int w = c.getWidth();
- final int h = c.getHeight();
- mGradient.setGradientCenter(w * 0.75f, 0);
- mGradient.setBounds(0, 0, w, h);
- mGradient.draw(c);
-
- if (mJandystripe != null) {
- mJandystripe.reset();
- mJandystripe.moveTo(0, w);
- mJandystripe.lineTo(w, 0);
- mJandystripe.lineTo(w, 2 * w);
- mJandystripe.lineTo(0, 3 * w);
- mJandystripe.close();
- for (int y=0; y<h; y+=4*w) {
- c.drawPath(mJandystripe, mPaint2);
- mJandystripe.offset(0, 4 * w);
- }
- }
-
- if (!mDrawShadow) return;
- mShadow.reset();
- mShadow.moveTo(0, 0);
- mShadow.lineTo(w, 0);
- mShadow.lineTo(w, PARAMS.OBSTACLE_WIDTH * 0.4f + w*1.5f);
- mShadow.lineTo(0, PARAMS.OBSTACLE_WIDTH * 0.4f);
- mShadow.close();
- c.drawPath(mShadow, mPaint);
- }
- }
-
- private class Scenery extends FrameLayout implements GameView {
- public float z;
- public float v;
- public int h, w;
- public Scenery(Context context) {
- super(context);
- }
-
- @Override
- public void step(long t_ms, long dt_ms, float t, float dt) {
- setTranslationX(getTranslationX() - PARAMS.TRANSLATION_PER_SEC * dt * v);
- }
- }
-
- private class Building extends Scenery {
- public Building(Context context) {
- super(context);
-
- w = irand(PARAMS.BUILDING_WIDTH_MIN, PARAMS.BUILDING_WIDTH_MAX);
- h = 0; // will be setup later, along with z
- }
- }
-
- static final int[] CACTI = { R.drawable.cactus1, R.drawable.cactus2, R.drawable.cactus3 };
- private class Cactus extends Building {
- public Cactus(Context context) {
- super(context);
-
- setBackgroundResource(pick(CACTI));
- w = h = irand(PARAMS.BUILDING_WIDTH_MAX / 4, PARAMS.BUILDING_WIDTH_MAX / 2);
- }
- }
-
- static final int[] MOUNTAINS = {
- R.drawable.mountain1, R.drawable.mountain2, R.drawable.mountain3 };
- private class Mountain extends Building {
- public Mountain(Context context) {
- super(context);
-
- setBackgroundResource(pick(MOUNTAINS));
- w = h = irand(PARAMS.BUILDING_WIDTH_MAX / 2, PARAMS.BUILDING_WIDTH_MAX);
- z = 0;
- }
- }
- private class Cloud extends Scenery {
- public Cloud(Context context) {
- super(context);
- setBackgroundResource(frand() < 0.01f ? R.drawable.cloud_off : R.drawable.cloud);
- getBackground().setAlpha(0x40);
- w = h = irand(PARAMS.CLOUD_SIZE_MIN, PARAMS.CLOUD_SIZE_MAX);
- z = 0;
- v = frand(0.15f,0.5f);
- }
- }
-
- private class Star extends Scenery {
- public Star(Context context) {
- super(context);
- setBackgroundResource(R.drawable.star);
- w = h = irand(PARAMS.STAR_SIZE_MIN, PARAMS.STAR_SIZE_MAX);
- v = z = 0;
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/egg/MLandActivity.java b/packages/SystemUI/src/com/android/systemui/egg/MLandActivity.java
deleted file mode 100644
index 84b91bc8e3a1..000000000000
--- a/packages/SystemUI/src/com/android/systemui/egg/MLandActivity.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2015 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.egg;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-
-import com.android.systemui.R;
-
-public class MLandActivity extends Activity {
- MLand mLand;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.mland);
- mLand = findViewById(R.id.world);
- mLand.setScoreFieldHolder(findViewById(R.id.scores));
- final View welcome = findViewById(R.id.welcome);
- mLand.setSplash(welcome);
- final int numControllers = mLand.getGameControllers().size();
- if (numControllers > 0) {
- mLand.setupPlayers(numControllers);
- }
- }
-
- public void updateSplashPlayers() {
- final int N = mLand.getNumPlayers();
- final View minus = findViewById(R.id.player_minus_button);
- final View plus = findViewById(R.id.player_plus_button);
- if (N == 1) {
- minus.setVisibility(View.INVISIBLE);
- plus.setVisibility(View.VISIBLE);
- plus.requestFocus();
- } else if (N == mLand.MAX_PLAYERS) {
- minus.setVisibility(View.VISIBLE);
- plus.setVisibility(View.INVISIBLE);
- minus.requestFocus();
- } else {
- minus.setVisibility(View.VISIBLE);
- plus.setVisibility(View.VISIBLE);
- }
- }
-
- @Override
- public void onPause() {
- mLand.stop();
- super.onPause();
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- mLand.onAttachedToWindow(); // resets and starts animation
- updateSplashPlayers();
- mLand.showSplash();
- }
-
- public void playerMinus(View v) {
- mLand.removePlayer();
- updateSplashPlayers();
- }
-
- public void playerPlus(View v) {
- mLand.addPlayer();
- updateSplashPlayers();
- }
-
- public void startButtonPressed(View v) {
- findViewById(R.id.player_minus_button).setVisibility(View.INVISIBLE);
- findViewById(R.id.player_plus_button).setVisibility(View.INVISIBLE);
- mLand.start(true);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagManager.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagManager.java
deleted file mode 100644
index 85baed4a221c..000000000000
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagManager.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.flags;
-
-import com.android.systemui.dagger.SysUISingleton;
-
-import javax.inject.Inject;
-
-/**
- * Default implementation of the a Flag manager that returns default values for release builds
- */
-@SysUISingleton
-public class FeatureFlagManager implements FlagReader, FlagWriter {
- @Inject
- public FeatureFlagManager() {}
- public boolean isEnabled(String key, boolean defaultValue) {
- return defaultValue;
- }
- public boolean isEnabled(int key, boolean defaultValue) {
- return defaultValue;
- }
- public void setEnabled(String key, boolean value) {}
- public void setEnabled(int key, boolean value) {}
-}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java
deleted file mode 100644
index e78646a4839d..000000000000
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.flags;
-
-import android.content.res.Resources;
-import android.util.SparseArray;
-
-import androidx.annotation.BoolRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.systemui.Dumpable;
-import com.android.systemui.R;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.util.wrapper.BuildInfo;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-import javax.inject.Inject;
-/**
- * Reads and caches feature flags for quick access
- *
- * Feature flags must be defined as boolean resources. For example:t
- *
- * {@code
- * <bool name="flag_foo_bar_baz">false</bool>
- * }
- *
- * It is strongly recommended that the name of the resource begin with "flag_".
- *
- * Flags can be overridden via adb on development builds. For example, to override the flag from the
- * previous example, do the following:
- *
- * {@code
- * $ adb shell setprop persist.systemui.flag_foo_bar_baz 1
- * }
- *
- * Note that all storage keys begin with "flag_", even if their associated resId does not.
- *
- * Calls to this class should probably be wrapped by a method in {@link FeatureFlags}.
- */
-@SysUISingleton
-public class FeatureFlagReader implements Dumpable {
- private final Resources mResources;
- private final boolean mAreFlagsOverrideable;
- private final SystemPropertiesHelper mSystemPropertiesHelper;
- private final SparseArray<CachedFlag> mCachedFlags = new SparseArray<>();
-
- private final FlagReader mFlagReader;
-
- @Inject
- public FeatureFlagReader(
- @Main Resources resources,
- BuildInfo build,
- DumpManager dumpManager,
- SystemPropertiesHelper systemPropertiesHelper,
- FlagReader reader) {
- mResources = resources;
- mFlagReader = reader;
- mSystemPropertiesHelper = systemPropertiesHelper;
- mAreFlagsOverrideable =
- build.isDebuggable() && mResources.getBoolean(R.bool.are_flags_overrideable);
- dumpManager.registerDumpable("FeatureFlags", this);
- }
-
- boolean isEnabled(BooleanFlag flag) {
- return mFlagReader.isEnabled(flag.getId(), flag.getDefault());
- }
-
- void addListener(FlagReader.Listener listener) {
- mFlagReader.addListener(listener);
- }
-
- void removeListener(FlagReader.Listener listener) {
- mFlagReader.removeListener(listener);
- }
-
- /**
- * Returns true if the specified feature flag has been enabled.
- *
- * @param resId The backing boolean resource that determines the value of the flag. This value
- * can be overridden via DeviceConfig on development builds.
- */
- public boolean isEnabled(@BoolRes int resId) {
- synchronized (mCachedFlags) {
- CachedFlag cachedFlag = mCachedFlags.get(resId);
-
- if (cachedFlag == null) {
- String name = resourceIdToFlagName(resId);
- boolean value = mResources.getBoolean(resId);
- if (mAreFlagsOverrideable) {
- value = mSystemPropertiesHelper.getBoolean(flagNameToStorageKey(name), value);
- }
-
- cachedFlag = new CachedFlag(name, value);
- mCachedFlags.put(resId, cachedFlag);
- }
-
- return cachedFlag.value;
- }
- }
-
- private String resourceIdToFlagName(@BoolRes int resId) {
- String resName = mResources.getResourceEntryName(resId);
- if (resName.startsWith(RESNAME_PREFIX)) {
- resName = resName.substring(RESNAME_PREFIX.length());
- }
- return resName;
- }
-
- private String flagNameToStorageKey(String flagName) {
- if (flagName.startsWith(STORAGE_KEY_PREFIX)) {
- return flagName;
- } else {
- return STORAGE_KEY_PREFIX + flagName;
- }
- }
-
- @Nullable
- private String storageKeyToFlagName(String configName) {
- if (configName.startsWith(STORAGE_KEY_PREFIX)) {
- return configName.substring(STORAGE_KEY_PREFIX.length());
- } else {
- return null;
- }
- }
-
- @Override
- public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
- ArrayList<String> flagStrings = new ArrayList<>(mCachedFlags.size());
- for (int i = 0; i < mCachedFlags.size(); i++) {
- int key = mCachedFlags.keyAt(i);
- // get the object by the key.
- CachedFlag flag = mCachedFlags.get(key);
- flagStrings.add(" " + RESNAME_PREFIX + flag.name + ": " + flag.value + "\n");
- }
- flagStrings.sort(String.CASE_INSENSITIVE_ORDER);
- pw.println("AreFlagsOverrideable: " + mAreFlagsOverrideable);
- pw.println("Cached FeatureFlags:");
- for (String flagString : flagStrings) {
- pw.print(flagString);
- }
- }
-
- private static class CachedFlag {
- public final String name;
- public final boolean value;
-
- private CachedFlag(String name, boolean value) {
- this.name = name;
- this.value = value;
- }
- }
-
- private static final String STORAGE_KEY_PREFIX = "persist.systemui.flag_";
- private static final String RESNAME_PREFIX = "flag_";
-}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
index 947a39a32365..34f441510a7e 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
@@ -18,16 +18,11 @@ package com.android.systemui.flags;
import android.content.Context;
import android.util.FeatureFlagUtils;
+import android.util.Log;
+import android.widget.Toast;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
import javax.inject.Inject;
/**
@@ -37,28 +32,13 @@ import javax.inject.Inject;
*/
@SysUISingleton
public class FeatureFlags {
- private final FeatureFlagReader mFlagReader;
+ private final FlagReader 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) {
+ public FeatureFlags(FlagReader flagReader, Context context) {
mFlagReader = flagReader;
mContext = context;
-
- flagReader.addListener(mListener);
- }
-
- private final FlagReader.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);
}
/**
@@ -69,21 +49,20 @@ public class FeatureFlags {
return mFlagReader.isEnabled(flag);
}
- /**
- * @param flag The {@link IntFlag} of interest.
-
- /** 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);
+ public void assertLegacyPipelineEnabled() {
+ if (isNewNotifPipelineRenderingEnabled()) {
+ throw new IllegalStateException("Old pipeline code running w/ new pipeline enabled");
+ }
}
- /** 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 checkLegacyPipelineEnabled() {
+ if (!isNewNotifPipelineRenderingEnabled()) {
+ return true;
}
+ Log.d("NotifPipeline", "Old pipeline code running w/ new pipeline enabled",
+ new Exception());
+ Toast.makeText(mContext, "Old pipeline code running!", Toast.LENGTH_SHORT).show();
+ return false;
}
public boolean isNewNotifPipelineEnabled() {
@@ -100,13 +79,11 @@ public class FeatureFlags {
}
public boolean isPeopleTileEnabled() {
- // TODO(b/202860494): different resource overlays have different values.
- return mFlagReader.isEnabled(R.bool.flag_conversations);
+ return isEnabled(Flags.PEOPLE_TILE);
}
public boolean isMonetEnabled() {
- // TODO(b/202860494): used in wallpaper picker. Always true, maybe delete.
- return mFlagReader.isEnabled(R.bool.flag_monet);
+ return isEnabled(Flags.MONET);
}
public boolean isPMLiteEnabled() {
@@ -114,8 +91,7 @@ public class FeatureFlags {
}
public boolean isChargingRippleEnabled() {
- // TODO(b/202860494): different resource overlays have different values.
- return mFlagReader.isEnabled(R.bool.flag_charging_ripple);
+ return isEnabled(Flags.CHARGING_RIPPLE);
}
public boolean isOngoingCallStatusBarChipEnabled() {
@@ -132,8 +108,7 @@ public class FeatureFlags {
}
public boolean isSmartspaceEnabled() {
- // TODO(b/202860494): different resource overlays have different values.
- return mFlagReader.isEnabled(R.bool.flag_smartspace);
+ return isEnabled(Flags.SMARTSPACE);
}
public boolean isSmartspaceDedupingEnabled() {
@@ -165,14 +140,15 @@ public class FeatureFlags {
return isEnabled(Flags.NEW_USER_SWITCHER);
}
+ /**
+ * Use the new single view QS headers
+ */
+ public boolean useCombinedQSHeaders() {
+ return isEnabled(Flags.COMBINED_QS_HEADERS);
+ }
+
/** static method for the system setting */
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/plugin/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 3761d42ae98c..c33aa9e5ee28 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -16,6 +16,8 @@
package com.android.systemui.flags;
+import com.android.systemui.R;
+
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
@@ -47,7 +49,6 @@ public class Flags {
public static final BooleanFlag NOTIFICATION_UPDATES =
new BooleanFlag(102, true);
-
/***************************************/
// 200 - keyguard/lockscreen
public static final BooleanFlag KEYGUARD_LAYOUT =
@@ -59,6 +60,9 @@ public class Flags {
public static final BooleanFlag NEW_UNLOCK_SWIPE_ANIMATION =
new BooleanFlag(202, true);
+ public static final BooleanFlag CHARGING_RIPPLE =
+ new BooleanFlag(203, false, R.bool.flag_charging_ripple);
+
/***************************************/
// 300 - power menu
public static final BooleanFlag POWER_MENU_LITE =
@@ -72,26 +76,40 @@ public class Flags {
public static final BooleanFlag SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED =
new BooleanFlag(401, false);
+ public static final BooleanFlag SMARTSPACE =
+ new BooleanFlag(402, false, R.bool.flag_smartspace);
+
/***************************************/
// 500 - quick settings
public static final BooleanFlag NEW_USER_SWITCHER =
new BooleanFlag(500, true);
+ public static final BooleanFlag COMBINED_QS_HEADERS =
+ new BooleanFlag(501, false);
+
+ public static final BooleanFlag PEOPLE_TILE =
+ new BooleanFlag(502, false, R.bool.flag_conversations);
+
/***************************************/
// 600- status bar
public static final BooleanFlag COMBINED_STATUS_BAR_SIGNAL_ICONS =
- new BooleanFlag(501, false);
+ new BooleanFlag(601, false);
/***************************************/
// 700 - dialer/calls
public static final BooleanFlag ONGOING_CALL_STATUS_BAR_CHIP =
- new BooleanFlag(600, true);
+ new BooleanFlag(700, true);
public static final BooleanFlag ONGOING_CALL_IN_IMMERSIVE =
- new BooleanFlag(601, true);
+ new BooleanFlag(701, true);
public static final BooleanFlag ONGOING_CALL_IN_IMMERSIVE_CHIP_TAP =
- new BooleanFlag(602, true);
+ new BooleanFlag(702, true);
+
+ /***************************************/
+ // 800 - general visual/theme
+ public static final BooleanFlag MONET =
+ new BooleanFlag(800, true, R.bool.flag_monet);
// Pay no attention to the reflection behind the curtain.
// ========================== Curtain ==========================
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index b06b024a63a4..ad472326555e 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -607,6 +607,9 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
} else if (GLOBAL_ACTION_KEY_SCREENSHOT.equals(actionKey)) {
addIfShouldShowAction(tempActions, new ScreenshotAction());
} else if (GLOBAL_ACTION_KEY_LOGOUT.equals(actionKey)) {
+ // TODO(b/206032495): should call mDevicePolicyManager.getLogoutUserId() instead of
+ // hardcode it to USER_SYSTEM so it properly supports headless system user mode
+ // (and then call mDevicePolicyManager.clearLogoutUser() after switched)
if (mDevicePolicyManager.isLogoutEnabled()
&& currentUser.get() != null
&& currentUser.get().id != UserHandle.USER_SYSTEM) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt
deleted file mode 100644
index b4137fa80f19..000000000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.keyguard
-
-import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
-import android.animation.ValueAnimator
-import android.content.res.Resources
-import android.database.ContentObserver
-import android.graphics.Bitmap
-import android.graphics.BitmapFactory
-import android.graphics.Color
-import android.graphics.drawable.ColorDrawable
-import android.hardware.biometrics.BiometricSourceType
-import android.os.Handler
-import android.provider.Settings.System.SCREEN_BRIGHTNESS_FLOAT
-import android.util.MathUtils
-import android.view.View
-import android.view.WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
-import android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-import com.android.internal.annotations.VisibleForTesting
-import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.keyguard.KeyguardUpdateMonitorCallback
-import com.android.systemui.Dumpable
-import com.android.systemui.R
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dump.DumpManager
-import com.android.systemui.statusbar.NotificationShadeWindowController
-import com.android.systemui.util.settings.GlobalSettings
-import com.android.systemui.util.settings.SystemSettings
-import java.io.FileDescriptor
-import java.io.PrintWriter
-import java.lang.Float.max
-import java.util.concurrent.TimeUnit
-
-val DEFAULT_ANIMATION_DURATION = TimeUnit.SECONDS.toMillis(4)
-val MAX_SCREEN_BRIGHTNESS = 100 // 0..100
-val MAX_SCRIM_OPACTY = 50 // 0..100
-val DEFAULT_USE_FACE_WALLPAPER = false
-
-/**
- * This class is responsible for ramping up the display brightness (and white overlay) in order
- * to mitigate low light conditions when running face auth without an IR camera.
- */
-@SysUISingleton
-open class FaceAuthScreenBrightnessController(
- private val notificationShadeWindowController: NotificationShadeWindowController,
- private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
- private val resources: Resources,
- private val globalSettings: GlobalSettings,
- private val systemSettings: SystemSettings,
- private val mainHandler: Handler,
- private val dumpManager: DumpManager,
- private val enabled: Boolean
-) : Dumpable {
-
- private var userDefinedBrightness: Float = 1f
- @VisibleForTesting
- var useFaceAuthWallpaper = globalSettings
- .getInt("sysui.use_face_auth_wallpaper", if (DEFAULT_USE_FACE_WALLPAPER) 1 else 0) == 1
- private val brightnessAnimationDuration = globalSettings
- .getLong("sysui.face_brightness_anim_duration", DEFAULT_ANIMATION_DURATION)
- private val maxScreenBrightness = globalSettings
- .getInt("sysui.face_max_brightness", MAX_SCREEN_BRIGHTNESS) / 100f
- private val maxScrimOpacity = globalSettings
- .getInt("sysui.face_max_scrim_opacity", MAX_SCRIM_OPACTY) / 100f
- private val keyguardUpdateCallback = object : KeyguardUpdateMonitorCallback() {
- override fun onBiometricRunningStateChanged(
- running: Boolean,
- biometricSourceType: BiometricSourceType?
- ) {
- if (biometricSourceType != BiometricSourceType.FACE) {
- return
- }
- // TODO enable only when receiving a low-light error
- overridingBrightness = if (enabled) running else false
- }
- }
- private lateinit var whiteOverlay: View
- private var brightnessAnimator: ValueAnimator? = null
- private var overridingBrightness = false
- set(value) {
- if (field == value) {
- return
- }
- field = value
- brightnessAnimator?.cancel()
-
- if (!value) {
- notificationShadeWindowController.setFaceAuthDisplayBrightness(BRIGHTNESS_OVERRIDE_NONE)
- if (whiteOverlay.alpha > 0) {
- brightnessAnimator = createAnimator(whiteOverlay.alpha, 0f).apply {
- duration = 200
- addUpdateListener {
- whiteOverlay.alpha = it.animatedValue as Float
- }
- addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator?) {
- whiteOverlay.visibility = View.INVISIBLE
- brightnessAnimator = null
- }
- })
- start()
- }
- }
- return
- }
-
- val targetBrightness = max(maxScreenBrightness, userDefinedBrightness)
- whiteOverlay.visibility = View.VISIBLE
- brightnessAnimator = createAnimator(0f, 1f).apply {
- duration = brightnessAnimationDuration
- addUpdateListener {
- val progress = it.animatedValue as Float
- val brightnessProgress = MathUtils.constrainedMap(
- userDefinedBrightness, targetBrightness, 0f, 0.5f, progress)
- val scrimProgress = MathUtils.constrainedMap(
- 0f, maxScrimOpacity, 0.5f, 1f, progress)
- notificationShadeWindowController.setFaceAuthDisplayBrightness(brightnessProgress)
- whiteOverlay.alpha = scrimProgress
- }
- addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator?) {
- brightnessAnimator = null
- }
- })
- start()
- }
- }
-
- @VisibleForTesting
- open fun createAnimator(start: Float, end: Float) = ValueAnimator.ofFloat(start, end)
-
- /**
- * Returns a bitmap that should be used by the lock screen as a wallpaper, if face auth requires
- * a secure wallpaper.
- */
- var faceAuthWallpaper: Bitmap? = null
- get() {
- val user = KeyguardUpdateMonitor.getCurrentUser()
- if (useFaceAuthWallpaper && keyguardUpdateMonitor.isFaceAuthEnabledForUser(user)) {
- val options = BitmapFactory.Options().apply {
- inScaled = false
- }
- return BitmapFactory.decodeResource(resources, R.drawable.face_auth_wallpaper, options)
- }
- return null
- }
- private set
-
- fun attach(overlayView: View) {
- whiteOverlay = overlayView
- whiteOverlay.focusable = FLAG_NOT_FOCUSABLE
- whiteOverlay.background = ColorDrawable(Color.WHITE)
- whiteOverlay.isEnabled = false
- whiteOverlay.alpha = 0f
- whiteOverlay.visibility = View.INVISIBLE
-
- dumpManager.registerDumpable(this.javaClass.name, this)
- keyguardUpdateMonitor.registerCallback(keyguardUpdateCallback)
- systemSettings.registerContentObserver(SCREEN_BRIGHTNESS_FLOAT,
- object : ContentObserver(mainHandler) {
- override fun onChange(selfChange: Boolean) {
- userDefinedBrightness = systemSettings.getFloat(SCREEN_BRIGHTNESS_FLOAT)
- }
- })
- userDefinedBrightness = systemSettings.getFloat(SCREEN_BRIGHTNESS_FLOAT, 1f)
- }
-
- override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
- pw.apply {
- println("overridingBrightness: $overridingBrightness")
- println("useFaceAuthWallpaper: $useFaceAuthWallpaper")
- println("brightnessAnimator: $brightnessAnimator")
- println("brightnessAnimationDuration: $brightnessAnimationDuration")
- println("maxScreenBrightness: $maxScreenBrightness")
- println("userDefinedBrightness: $userDefinedBrightness")
- println("enabled: $enabled")
- }
- }
-} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 01a0f271e5b9..22a69d4012fa 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -118,6 +118,7 @@ public class KeyguardService extends Service {
private final KeyguardViewMediator mKeyguardViewMediator;
private final KeyguardLifecyclesDispatcher mKeyguardLifecyclesDispatcher;
+ private final ShellTransitions mShellTransitions;
private static int newModeToLegacyMode(int newMode) {
switch (newMode) {
@@ -231,54 +232,10 @@ public class KeyguardService extends Service {
super();
mKeyguardViewMediator = keyguardViewMediator;
mKeyguardLifecyclesDispatcher = keyguardLifecyclesDispatcher;
+ mShellTransitions = shellTransitions;
if (shellTransitions != null && Transitions.ENABLE_SHELL_TRANSITIONS) {
- if (sEnableRemoteKeyguardGoingAwayAnimation) {
- Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_GOING_AWAY");
- TransitionFilter f = new TransitionFilter();
- f.mFlags = TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
- shellTransitions.registerRemote(f,
- new RemoteTransition(wrap(mExitAnimationRunner)));
- }
- if (sEnableRemoteKeyguardOccludeAnimation) {
- Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_(UN)OCCLUDE");
- // Register for occluding
- TransitionFilter 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 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, new RemoteTransition(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, new RemoteTransition(mUnoccludeAnimation));
- }
+ // Nothing here. Initialization for this happens in onCreate.
} else {
RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
if (sEnableRemoteKeyguardGoingAwayAnimation) {
@@ -305,6 +262,58 @@ public class KeyguardService extends Service {
@Override
public void onCreate() {
((SystemUIApplication) getApplication()).startServicesIfNeeded();
+
+ if (mShellTransitions == null || !Transitions.ENABLE_SHELL_TRANSITIONS) {
+ return;
+ }
+ if (sEnableRemoteKeyguardGoingAwayAnimation) {
+ Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_GOING_AWAY");
+ TransitionFilter f = new TransitionFilter();
+ f.mFlags = TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
+ mShellTransitions.registerRemote(f,
+ new RemoteTransition(wrap(mExitAnimationRunner), getIApplicationThread()));
+ }
+ if (sEnableRemoteKeyguardOccludeAnimation) {
+ Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_(UN)OCCLUDE");
+ // Register for occluding
+ TransitionFilter 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 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};
+ mShellTransitions.registerRemote(f,
+ new RemoteTransition(mOccludeAnimation, getIApplicationThread()));
+
+ // 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};
+ mShellTransitions.registerRemote(f,
+ new RemoteTransition(mUnoccludeAnimation, getIApplicationThread()));
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 19ee50ac99cd..7f9eae8bd55f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -82,6 +82,8 @@ import android.view.WindowManagerPolicyConstants;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
+import androidx.annotation.Nullable;
+
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.jank.InteractionJankMonitor.Configuration;
import com.android.internal.policy.IKeyguardDismissCallback;
@@ -117,15 +119,17 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.unfold.SysUIUnfoldComponent;
import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
-import com.android.systemui.unfold.config.UnfoldTransitionConfig;
import com.android.systemui.util.DeviceConfigProxy;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
@@ -811,8 +815,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
private DeviceConfigProxy mDeviceConfig;
private DozeParameters mDozeParameters;
- private final UnfoldTransitionConfig mUnfoldTransitionConfig;
- private final Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealAnimation;
+ private final Optional<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealAnimation;
private final AtomicInteger mPendingDrawnTasks = new AtomicInteger();
private final KeyguardStateController mKeyguardStateController;
@@ -837,8 +840,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
NavigationModeController navigationModeController,
KeyguardDisplayManager keyguardDisplayManager,
DozeParameters dozeParameters,
- UnfoldTransitionConfig unfoldTransitionConfig,
- Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation,
+ Optional<SysUIUnfoldComponent> unfoldComponent,
SysuiStatusBarStateController statusBarStateController,
KeyguardStateController keyguardStateController,
Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationControllerLazy,
@@ -872,8 +874,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
mInGestureNavigationMode = QuickStepContract.isGesturalMode(mode);
}));
mDozeParameters = dozeParameters;
- mUnfoldTransitionConfig = unfoldTransitionConfig;
- mUnfoldLightRevealAnimation = unfoldLightRevealOverlayAnimation;
+ mUnfoldLightRevealAnimation = unfoldComponent.map(
+ c -> c.getUnfoldLightRevealOverlayAnimation());
mStatusBarStateController = statusBarStateController;
statusBarStateController.addCallback(this);
@@ -2557,7 +2559,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
synchronized (KeyguardViewMediator.this) {
if (DEBUG) Log.d(TAG, "handleNotifyScreenTurningOn");
- if (mUnfoldTransitionConfig.isEnabled()) {
+ if (mUnfoldLightRevealAnimation.isPresent()) {
mPendingDrawnTasks.set(2); // unfold overlay and keyguard drawn
mUnfoldLightRevealAnimation.get()
@@ -2654,10 +2656,16 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
*/
public KeyguardViewController registerStatusBar(StatusBar statusBar,
NotificationPanelViewController panelView,
+ @Nullable PanelExpansionStateManager panelExpansionStateManager,
BiometricUnlockController biometricUnlockController,
View notificationContainer, KeyguardBypassController bypassController) {
- mKeyguardViewControllerLazy.get().registerStatusBar(statusBar, panelView,
- biometricUnlockController, notificationContainer, bypassController);
+ mKeyguardViewControllerLazy.get().registerStatusBar(
+ statusBar,
+ panelView,
+ panelExpansionStateManager,
+ biometricUnlockController,
+ notificationContainer,
+ bypassController);
return mKeyguardViewControllerLazy.get();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 11d4aac9dc27..cae9feeb62eb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -20,9 +20,6 @@ import android.annotation.Nullable;
import android.app.trust.TrustManager;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.hardware.face.FaceManager;
-import android.os.Handler;
import android.os.PowerManager;
import com.android.internal.widget.LockPatternUtils;
@@ -37,17 +34,14 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.classifier.FalsingModule;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
-import com.android.systemui.keyguard.FaceAuthScreenBrightnessController;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationShadeDepthController;
-import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardLiftController;
@@ -55,12 +49,9 @@ import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
-import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
-import com.android.systemui.unfold.config.UnfoldTransitionConfig;
+import com.android.systemui.unfold.SysUIUnfoldComponent;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.sensors.AsyncSensorManager;
-import com.android.systemui.util.settings.GlobalSettings;
-import com.android.systemui.util.settings.SystemSettings;
import java.util.Optional;
import java.util.concurrent.Executor;
@@ -101,8 +92,7 @@ public class KeyguardModule {
NavigationModeController navigationModeController,
KeyguardDisplayManager keyguardDisplayManager,
DozeParameters dozeParameters,
- UnfoldTransitionConfig unfoldTransitionConfig,
- Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation,
+ Optional<SysUIUnfoldComponent> unfoldComponent,
SysuiStatusBarStateController statusBarStateController,
KeyguardStateController keyguardStateController,
Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationController,
@@ -125,8 +115,7 @@ public class KeyguardModule {
navigationModeController,
keyguardDisplayManager,
dozeParameters,
- unfoldTransitionConfig,
- unfoldLightRevealOverlayAnimation,
+ unfoldComponent,
statusBarStateController,
keyguardStateController,
keyguardUnlockAnimationController,
@@ -150,35 +139,4 @@ public class KeyguardModule {
return new KeyguardLiftController(statusBarStateController, asyncSensorManager,
keyguardUpdateMonitor, dumpManager);
}
-
- @SysUISingleton
- @Provides
- static Optional<FaceAuthScreenBrightnessController> provideFaceAuthScreenBrightnessController(
- Context context,
- NotificationShadeWindowController notificationShadeWindowController,
- @Main Resources resources,
- Handler handler,
- @Nullable FaceManager faceManager,
- PackageManager packageManager,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- GlobalSettings globalSetting,
- SystemSettings systemSettings,
- DumpManager dumpManager) {
- if (faceManager == null || !packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
- return Optional.empty();
- }
-
- // Cameras that support "self illumination," via IR for example, don't need low light
- // environment mitigation.
- boolean needsLowLightMitigation = faceManager.getSensorPropertiesInternal().stream()
- .anyMatch((properties) -> !properties.supportsSelfIllumination);
- if (!needsLowLightMitigation) {
- return Optional.empty();
- }
-
- // currently disabled (doesn't ramp up brightness or use scrim) see b/175918367
- return Optional.of(new FaceAuthScreenBrightnessController(
- notificationShadeWindowController, keyguardUpdateMonitor, resources,
- globalSetting, systemSettings, handler, dumpManager, false));
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
index c1db8edf4119..9e0038112dd3 100644
--- a/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
@@ -61,7 +61,7 @@ import java.util.Locale
*
* @param name The name of this buffer
* @param maxLogs The maximum number of messages to keep in memory at any one time, including the
- * unused pool.
+ * unused pool. Must be >= [poolSize].
* @param poolSize The maximum amount that the size of the buffer is allowed to flex in response to
* sequential calls to [document] that aren't immediately followed by a matching call to [push].
*/
@@ -71,6 +71,13 @@ class LogBuffer(
private val poolSize: Int,
private val logcatEchoTracker: LogcatEchoTracker
) {
+ init {
+ if (maxLogs < poolSize) {
+ throw IllegalArgumentException("maxLogs must be greater than or equal to poolSize, " +
+ "but maxLogs=$maxLogs < $poolSize=poolSize")
+ }
+ }
+
private val buffer: ArrayDeque<LogMessageImpl> = ArrayDeque()
var frozen = false
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 72601e9816f9..46e2274970f7 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -112,6 +112,17 @@ public class LogModule {
}
/**
+ * Provides a logging buffer for logs related to {@link com.android.systemui.qs.QSFragment}'s
+ * disable flag adjustments.
+ */
+ @Provides
+ @SysUISingleton
+ @QSFragmentDisableLog
+ public static LogBuffer provideQSFragmentDisableLogBuffer(LogBufferFactory factory) {
+ return factory.create("QSFragmentDisableFlagsLog", 10);
+ }
+
+ /**
* Provides a logging buffer for logs related to swiping away the status bar while in immersive
* mode. See {@link com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureLogger}.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/QSFragmentDisableLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/QSFragmentDisableLog.java
new file mode 100644
index 000000000000..557a254e5c09
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/QSFragmentDisableLog.java
@@ -0,0 +1,36 @@
+/*
+ * 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.log.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.android.systemui.log.LogBuffer;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/**
+ * A {@link LogBuffer} for disable flag adjustments made in
+ * {@link com.android.systemui.qs.QSFragment}.
+ */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface QSFragmentDisableLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
index 292b0e291244..fbfb919ede1e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
@@ -109,11 +109,9 @@ class MediaDeviceManager @Inject constructor(
}
@MainThread
- private fun processDevice(key: String, oldKey: String?, device: MediaDevice?) {
- val enabled = device != null
- val data = MediaDeviceData(enabled, device?.iconWithoutBackground, device?.name)
+ private fun processDevice(key: String, oldKey: String?, device: MediaDeviceData?) {
listeners.forEach {
- it.onMediaDeviceChanged(key, oldKey, data)
+ it.onMediaDeviceChanged(key, oldKey, device)
}
}
@@ -135,7 +133,7 @@ class MediaDeviceManager @Inject constructor(
get() = controller?.sessionToken
private var started = false
private var playbackType = PLAYBACK_TYPE_UNKNOWN
- private var current: MediaDevice? = null
+ private var current: MediaDeviceData? = null
set(value) {
if (!started || value != field) {
field = value
@@ -201,15 +199,13 @@ class MediaDeviceManager @Inject constructor(
@WorkerThread
private fun updateCurrent() {
- val device = localMediaManager.getCurrentConnectedDevice()
- controller?.let {
- val route = mr2manager.getRoutingSessionForMediaController(it)
- // If we get a null route, then don't trust the device. Just set to null to disable the
- // output switcher chip.
- current = if (route != null) device else null
- } ?: run {
- current = device
- }
+ val device = localMediaManager.currentConnectedDevice
+ val route = controller?.let { mr2manager.getRoutingSessionForMediaController(it)}
+
+ // If we have a controller but get a null route, then don't trust the device
+ val enabled = device != null && (controller == null || route != null)
+ val name = route?.name?.toString() ?: device?.name
+ current = MediaDeviceData(enabled, device?.iconWithoutBackground, name)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
index f32dad632721..042a337322e9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
@@ -106,6 +106,7 @@ class PlayerViewHolder private constructor(itemView: View) {
*/
@JvmStatic fun create(inflater: LayoutInflater, parent: ViewGroup): PlayerViewHolder {
val mediaView = inflater.inflate(R.layout.media_view, parent, false)
+ mediaView.setLayerType(View.LAYER_TYPE_HARDWARE, null)
// Because this media view (a TransitionLayout) is used to measure and layout the views
// in various states before being attached to its parent, we can't depend on the default
// LAYOUT_DIRECTION_INHERIT to correctly resolve the ltr direction.
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 125b87b31e63..113ba59cd514 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -16,14 +16,10 @@
package com.android.systemui.media.dialog;
-import static android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE;
-
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
-import android.text.SpannableString;
import android.text.TextUtils;
-import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -99,23 +95,6 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
return mController.getMediaDevices().size();
}
- @Override
- CharSequence getItemTitle(MediaDevice device) {
- if (device.getDeviceType() == MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE
- && !device.isConnected()) {
- final CharSequence deviceName = device.getName();
- // Append status to title only for the disconnected Bluetooth device.
- final SpannableString spannableTitle = new SpannableString(
- mContext.getString(R.string.media_output_dialog_disconnected, deviceName));
- spannableTitle.setSpan(new ForegroundColorSpan(
- Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorSecondary)),
- deviceName.length(),
- spannableTitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
- return spannableTitle;
- }
- return super.getItemTitle(device);
- }
-
class MediaDeviceViewHolder extends MediaDeviceBaseViewHolder {
MediaDeviceViewHolder(View view) {
@@ -166,6 +145,14 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
false /* showProgressBar */, false /* showSubtitle */);
initSeekbar(device);
mCurrentActivePosition = position;
+ } else if (
+ device.getDeviceType() == MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE
+ && !device.isConnected()) {
+ setTwoLineLayout(device, false /* bFocused */,
+ false /* showSeekBar */, false /* showProgressBar */,
+ true /* showSubtitle */);
+ mSubTitleText.setText(R.string.media_output_dialog_disconnected);
+ mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
} else {
setSingleLineLayout(getItemTitle(device), false /* bFocused */);
mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
@@ -175,7 +162,6 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
@Override
void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) {
- super.onBind(customizedItem, topMargin, bottomMargin);
if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) {
mCheckBox.setVisibility(View.GONE);
mAddIcon.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index 1ffc2c4c35ba..868193b44704 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -153,9 +153,7 @@ public abstract class MediaOutputBaseAdapter extends
});
}
- void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) {
- // TODO (b/201718621): clean up method after adjustment
- }
+ abstract void onBind(int customizedItem, boolean topMargin, boolean bottomMargin);
void setSingleLineLayout(CharSequence title, boolean bFocused) {
mTwoLineLayout.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index 6895ef10fd07..26ce645eefc5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -104,8 +104,6 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
lp.setFitInsetsIgnoringVisibility(true);
window.setAttributes(lp);
window.setContentView(mDialogView);
- window.setLayout(mContext.getResources().getDimensionPixelSize(R.dimen.large_dialog_width),
- ViewGroup.LayoutParams.WRAP_CONTENT);
mHeaderTitle = mDialogView.requireViewById(R.id.header_title);
mHeaderSubtitle = mDialogView.requireViewById(R.id.header_subtitle);
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 42dd8862576b..19812697719c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -79,6 +79,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
private final DialogLaunchAnimator mDialogLaunchAnimator;
private final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>();
private final boolean mAboveStatusbar;
+ private final boolean mVolumeAdjustmentForRemoteGroupSessions;
private final NotificationEntryManager mNotificationEntryManager;
@VisibleForTesting
final List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
@@ -111,6 +112,8 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName);
mUiEventLogger = uiEventLogger;
mDialogLaunchAnimator = dialogLaunchAnimator;
+ mVolumeAdjustmentForRemoteGroupSessions = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions);
}
void start(@NonNull Callback cb) {
@@ -477,7 +480,9 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
}
boolean isVolumeControlEnabled(@NonNull MediaDevice device) {
- return !isActiveRemoteDevice(device);
+ // TODO(b/202500642): Also enable volume control for remote non-group sessions.
+ return !isActiveRemoteDevice(device)
+ || mVolumeAdjustmentForRemoteGroupSessions;
}
private final MediaController.Callback mCb = new MediaController.Callback() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
index 11d76dba1423..a201c071bbbe 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
@@ -126,7 +126,6 @@ public class MediaOutputGroupAdapter extends MediaOutputBaseAdapter {
@Override
void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) {
- super.onBind(customizedItem, topMargin, bottomMargin);
if (customizedItem == CUSTOMIZED_ITEM_GROUP) {
setTwoLineLayout(mContext.getText(R.string.media_output_dialog_group),
true /* bFocused */, true /* showSeekBar */, false /* showProgressBar */,
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 7809b5fb83ce..bc023cc892a6 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -24,9 +24,6 @@ import static android.app.StatusBarManager.WindowType;
import static android.app.StatusBarManager.WindowVisibleState;
import static android.app.StatusBarManager.windowStateToString;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
-import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
-import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE;
-import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.containsType;
@@ -133,6 +130,8 @@ import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.rotation.RotationButton;
+import com.android.systemui.shared.rotation.RotationButtonController;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.AutoHideUiElement;
@@ -612,8 +611,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mDeviceProvisionedController.addCallback(mUserSetupListener);
mNotificationShadeDepthController.addListener(mDepthListener);
- updateAccessibilityButtonModeIfNeeded();
-
return barView;
}
@@ -944,7 +941,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
// not valid. Just ignore the rotation in this case.
if (!mNavigationBarView.isAttachedToWindow()) return;
- final int winRotation = mNavigationBarView.getDisplay().getRotation();
final boolean rotateSuggestionsDisabled = RotationButtonController
.hasDisable2RotateSuggestionFlag(mDisabledFlags2);
final RotationButtonController rotationButtonController =
@@ -953,7 +949,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
if (RotationContextButton.DEBUG_ROTATION) {
Log.v(TAG, "onRotationProposal proposedRotation=" + Surface.rotationToString(rotation)
- + ", winRotation=" + Surface.rotationToString(winRotation)
+ ", isValid=" + isValid + ", mNavBarWindowState="
+ StatusBarManager.windowStateToString(mNavigationBarWindowState)
+ ", rotateSuggestionsDisabled=" + rotateSuggestionsDisabled
@@ -963,7 +958,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
// Respect the disabled flag, no need for action as flag change callback will handle hiding
if (rotateSuggestionsDisabled) return;
- rotationButtonController.onRotationProposal(rotation, winRotation, isValid);
+ rotationButtonController.onRotationProposal(rotation, isValid);
}
@Override
@@ -1406,34 +1401,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
updateSystemUiStateFlags(a11yFlags);
}
- private void updateAccessibilityButtonModeIfNeeded() {
- final int mode = Settings.Secure.getIntForUser(mContentResolver,
- Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
- ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT);
-
- // ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU is compatible under gestural or non-gestural
- // mode, so we don't need to update it.
- if (mode == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) {
- return;
- }
-
- // ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR is incompatible under gestural mode. Need to
- // force update to ACCESSIBILITY_BUTTON_MODE_GESTURE.
- if (QuickStepContract.isGesturalMode(mNavBarMode)
- && mode == ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR) {
- Settings.Secure.putIntForUser(mContentResolver,
- Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_GESTURE,
- UserHandle.USER_CURRENT);
- // ACCESSIBILITY_BUTTON_MODE_GESTURE is incompatible under non gestural mode. Need to
- // force update to ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR.
- } else if (!QuickStepContract.isGesturalMode(mNavBarMode)
- && mode == ACCESSIBILITY_BUTTON_MODE_GESTURE) {
- Settings.Secure.putIntForUser(mContentResolver,
- Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
- ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT);
- }
- }
-
public void updateSystemUiStateFlags(int a11yFlags) {
if (a11yFlags < 0) {
a11yFlags = mNavigationBarA11yHelper.getA11yButtonState();
@@ -1551,6 +1518,9 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
@Override
public void onNavigationModeChanged(int mode) {
mNavBarMode = mode;
+ // update assistant entry points on system navigation radio button click
+ updateAssistantEntrypoints();
+
if (!QuickStepContract.isGesturalMode(mode)) {
// Reset the override alpha
if (getBarTransitions() != null) {
@@ -1558,7 +1528,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
}
}
updateScreenPinningGestures();
- updateAccessibilityButtonModeIfNeeded();
if (!canShowSecondaryHandle()) {
resetSecondaryHandle();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 97bcb00eddbd..3dc79c43d894 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -16,10 +16,14 @@
package com.android.systemui.navigationbar;
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE;
+import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.systemui.shared.recents.utilities.Utilities.isTablet;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -27,6 +31,8 @@ import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
import android.util.Log;
import android.util.SparseArray;
import android.view.Display;
@@ -46,6 +52,7 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.model.SysUiState;
import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.phone.AutoHideController;
@@ -142,6 +149,8 @@ public class NavigationBarController implements
}
final int oldMode = mNavMode;
mNavMode = mode;
+ updateAccessibilityButtonModeIfNeeded();
+
mHandler.post(() -> {
// create/destroy nav bar based on nav mode only in unfolded state
if (oldMode != mNavMode) {
@@ -157,6 +166,35 @@ public class NavigationBarController implements
});
}
+ private void updateAccessibilityButtonModeIfNeeded() {
+ ContentResolver contentResolver = mContext.getContentResolver();
+ final int mode = Settings.Secure.getIntForUser(contentResolver,
+ Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
+ ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT);
+
+ // ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU is compatible under gestural or non-gestural
+ // mode, so we don't need to update it.
+ if (mode == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) {
+ return;
+ }
+
+ // ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR is incompatible under gestural mode. Need to
+ // force update to ACCESSIBILITY_BUTTON_MODE_GESTURE.
+ if (QuickStepContract.isGesturalMode(mNavMode)
+ && mode == ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR) {
+ Settings.Secure.putIntForUser(contentResolver,
+ Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_GESTURE,
+ UserHandle.USER_CURRENT);
+ // ACCESSIBILITY_BUTTON_MODE_GESTURE is incompatible under non gestural mode. Need to
+ // force update to ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR.
+ } else if (!QuickStepContract.isGesturalMode(mNavMode)
+ && mode == ACCESSIBILITY_BUTTON_MODE_GESTURE) {
+ Settings.Secure.putIntForUser(contentResolver,
+ Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
+ ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT);
+ }
+ }
+
/** @see #initializeTaskbarIfNecessary() */
private boolean updateNavbarForTaskbar() {
boolean taskbarShown = initializeTaskbarIfNecessary();
@@ -222,13 +260,14 @@ public class NavigationBarController implements
*/
public void createNavigationBars(final boolean includeDefaultDisplay,
RegisterStatusBarResult result) {
- if (initializeTaskbarIfNecessary()) {
- return;
- }
+ updateAccessibilityButtonModeIfNeeded();
+ // Don't need to create nav bar on the default display if we initialize TaskBar.
+ final boolean shouldCreateDefaultNavbar = includeDefaultDisplay
+ && !initializeTaskbarIfNecessary();
Display[] displays = mDisplayManager.getDisplays();
for (Display display : displays) {
- if (includeDefaultDisplay || display.getDisplayId() != DEFAULT_DISPLAY) {
+ if (shouldCreateDefaultNavbar || display.getDisplayId() != DEFAULT_DISPLAY) {
createNavigationBar(display, null /* savedState */, result);
}
}
@@ -246,12 +285,15 @@ public class NavigationBarController implements
return;
}
- if (mIsTablet) {
+ final int displayId = display.getDisplayId();
+ final boolean isOnDefaultDisplay = displayId == DEFAULT_DISPLAY;
+
+ // We may show TaskBar on the default display for large screen device. Don't need to create
+ // navigation bar for this case.
+ if (mIsTablet && isOnDefaultDisplay) {
return;
}
- final int displayId = display.getDisplayId();
- final boolean isOnDefaultDisplay = displayId == DEFAULT_DISPLAY;
final IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
try {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index c02cc8dda4c4..680cc5cb5cba 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -67,7 +67,6 @@ import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.model.SysUiState;
-import com.android.systemui.navigationbar.RotationButton.RotationButtonUpdatesCallback;
import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
import com.android.systemui.navigationbar.buttons.ContextualButton;
import com.android.systemui.navigationbar.buttons.ContextualButtonGroup;
@@ -76,9 +75,11 @@ import com.android.systemui.navigationbar.buttons.KeyButtonDrawable;
import com.android.systemui.navigationbar.buttons.NearestTouchFrame;
import com.android.systemui.navigationbar.buttons.RotationContextButton;
import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
-import com.android.systemui.navigationbar.gestural.FloatingRotationButton;
+import com.android.systemui.shared.rotation.FloatingRotationButton;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
+import com.android.systemui.shared.rotation.RotationButton.RotationButtonUpdatesCallback;
+import com.android.systemui.shared.rotation.RotationButtonController;
import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
@@ -322,9 +323,23 @@ public class NavigationBarView extends FrameLayout implements
mContextualButtonGroup.addButton(accessibilityButton);
mRotationContextButton = new RotationContextButton(R.id.rotate_suggestion,
mLightContext, R.drawable.ic_sysbar_rotate_button_ccw_start_0);
- mFloatingRotationButton = new FloatingRotationButton(context);
- mRotationButtonController = new RotationButtonController(mLightContext,
- mLightIconColor, mDarkIconColor);
+ mFloatingRotationButton = new FloatingRotationButton(mContext,
+ R.string.accessibility_rotate_button,
+ R.layout.rotate_suggestion,
+ R.id.rotate_suggestion,
+ R.dimen.floating_rotation_button_min_margin,
+ R.dimen.rounded_corner_content_padding,
+ R.dimen.floating_rotation_button_taskbar_left_margin,
+ R.dimen.floating_rotation_button_taskbar_bottom_margin,
+ R.dimen.floating_rotation_button_diameter,
+ R.dimen.key_button_ripple_max_width);
+ mRotationButtonController = new RotationButtonController(mLightContext, mLightIconColor,
+ mDarkIconColor, R.drawable.ic_sysbar_rotate_button_ccw_start_0,
+ R.drawable.ic_sysbar_rotate_button_ccw_start_90,
+ R.drawable.ic_sysbar_rotate_button_cw_start_0,
+ R.drawable.ic_sysbar_rotate_button_cw_start_90,
+ () -> getDisplay().getRotation());
+
updateRotationButton();
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
@@ -661,7 +676,7 @@ public class NavigationBarView extends FrameLayout implements
}
public void setBehavior(@Behavior int behavior) {
- mRotationButtonController.onBehaviorChanged(behavior);
+ mRotationButtonController.onBehaviorChanged(Display.DEFAULT_DISPLAY, behavior);
}
@Override
@@ -1277,6 +1292,7 @@ public class NavigationBarView extends FrameLayout implements
mButtonDispatchers.valueAt(i).onDestroy();
}
if (mRotationButtonController != null) {
+ mFloatingRotationButton.hide();
mRotationButtonController.unregisterListeners();
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java
deleted file mode 100644
index 3486c6e75931..000000000000
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.navigationbar;
-
-import android.view.View;
-
-import com.android.systemui.navigationbar.buttons.KeyButtonDrawable;
-
-/** Interface of a rotation button that interacts {@link RotationButtonController}. */
-public interface RotationButton {
- void setRotationButtonController(RotationButtonController rotationButtonController);
- void setUpdatesCallback(RotationButtonUpdatesCallback updatesCallback);
- View getCurrentView();
- boolean show();
- boolean hide();
- boolean isVisible();
- void updateIcon(int lightIconColor, int darkIconColor);
- void setOnClickListener(View.OnClickListener onClickListener);
- void setOnHoverListener(View.OnHoverListener onHoverListener);
- KeyButtonDrawable getImageDrawable();
- void setDarkIntensity(float darkIntensity);
- default void setCanShowRotationButton(boolean canShow) {}
- default boolean acceptRotationProposal() {
- return getCurrentView() != null;
- }
-
- /**
- * Callback for updates provided by a rotation button
- */
- interface RotationButtonUpdatesCallback {
- void onVisibilityChanged(boolean isVisible);
- void onPositionChanged();
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java
index 9ea938325659..debd2ebb51be 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java
@@ -168,7 +168,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
setClickable(true);
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
- mRipple = new KeyButtonRipple(context, this);
+ mRipple = new KeyButtonRipple(context, this, R.dimen.key_button_ripple_max_width);
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
mInputManager = manager;
setBackground(mRipple);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java
index ebb67af43a37..ac014b5b4a64 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java
@@ -21,8 +21,8 @@ import android.annotation.IdRes;
import android.content.Context;
import android.view.View;
-import com.android.systemui.navigationbar.RotationButton;
-import com.android.systemui.navigationbar.RotationButtonController;
+import com.android.systemui.shared.rotation.RotationButton;
+import com.android.systemui.shared.rotation.RotationButtonController;
/** Containing logic for the rotation button in nav bar. */
public class RotationContextButton extends ContextualButton implements RotationButton {
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipBuilder.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipBuilder.kt
index 1d2e74703b42..eec69f98b9be 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipBuilder.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipBuilder.kt
@@ -28,7 +28,7 @@ class PrivacyChipBuilder(private val context: Context, itemsList: List<PrivacyIt
appsAndTypes = itemsList.groupBy({ it.application }, { it.privacyType })
.toList()
.sortedWith(compareBy({ -it.second.size }, // Sort by number of AppOps
- { it.second.min() })) // Sort by "smallest" AppOpp (Location is largest)
+ { it.second.minOrNull() })) // Sort by "smallest" AppOpp (Location is largest)
types = itemsList.map { it.privacyType }.distinct().sorted()
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
index 9e8f6b82c182..23482677038c 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
@@ -24,7 +24,6 @@ import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.WindowInsets
import android.widget.ImageView
import android.widget.TextView
@@ -65,7 +64,6 @@ class PrivacyDialog(
window?.apply {
attributes.fitInsetsTypes = attributes.fitInsetsTypes or WindowInsets.Type.statusBars()
attributes.receiveInsetsIgnoringZOrder = true
- setLayout(context.resources.getDimensionPixelSize(R.dimen.qs_panel_width), WRAP_CONTENT)
setGravity(Gravity.TOP or Gravity.CENTER_HORIZONTAL)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
index 4f87cad225c7..98b914672112 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
@@ -72,12 +72,6 @@ class FooterActionsController @Inject constructor(
private var listening: Boolean = false
var expanded = false
- set(value) {
- if (field != value) {
- field = value
- updateView()
- }
- }
private val settingsButton: SettingsButton = view.findViewById(R.id.settings_button)
private val settingsButtonContainer: View? = view.findViewById(R.id.settings_button_container)
@@ -176,8 +170,7 @@ class FooterActionsController @Inject constructor(
}
private fun updateView() {
- mView.updateEverything(buttonsVisible(), isTunerEnabled(),
- multiUserSwitchController.isMultiUserEnabled)
+ mView.updateEverything(isTunerEnabled(), multiUserSwitchController.isMultiUserEnabled)
}
override fun onViewDetached() {
@@ -191,14 +184,14 @@ class FooterActionsController @Inject constructor(
this.listening = listening
if (this.listening) {
userInfoController.addCallback(onUserInfoChangedListener)
+ updateView()
} else {
userInfoController.removeCallback(onUserInfoChangedListener)
}
}
fun disable(state2: Int) {
- mView.disable(buttonsVisible(), state2, isTunerEnabled(),
- multiUserSwitchController.isMultiUserEnabled)
+ mView.disable(state2, isTunerEnabled(), multiUserSwitchController.isMultiUserEnabled)
}
fun setExpansion(headerExpansionFraction: Float) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
index 941e54a55393..f81f7bf73f64 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
@@ -107,7 +107,6 @@ class FooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout(
}
fun disable(
- buttonsVisible: Boolean,
state2: Int,
isTunerEnabled: Boolean,
multiUserEnabled: Boolean
@@ -115,16 +114,15 @@ class FooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout(
val disabled = state2 and StatusBarManager.DISABLE2_QUICK_SETTINGS != 0
if (disabled == qsDisabled) return
qsDisabled = disabled
- updateEverything(buttonsVisible, isTunerEnabled, multiUserEnabled)
+ updateEverything(isTunerEnabled, multiUserEnabled)
}
fun updateEverything(
- buttonsVisible: Boolean,
isTunerEnabled: Boolean,
multiUserEnabled: Boolean
) {
post {
- updateVisibilities(buttonsVisible, isTunerEnabled, multiUserEnabled)
+ updateVisibilities(isTunerEnabled, multiUserEnabled)
updateClickabilities()
isClickable = false
}
@@ -137,15 +135,14 @@ class FooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout(
}
private fun updateVisibilities(
- buttonsVisible: Boolean,
isTunerEnabled: Boolean,
multiUserEnabled: Boolean
) {
settingsContainer.visibility = if (qsDisabled) GONE else VISIBLE
tunerIcon.visibility = if (isTunerEnabled) VISIBLE else INVISIBLE
- multiUserSwitch.visibility = if (buttonsVisible && multiUserEnabled) VISIBLE else GONE
+ multiUserSwitch.visibility = if (multiUserEnabled) VISIBLE else GONE
val isDemo = UserManager.isDeviceInDemoMode(context)
- settingsButton.visibility = if (isDemo || !buttonsVisible) INVISIBLE else VISIBLE
+ settingsButton.visibility = if (isDemo) INVISIBLE else VISIBLE
}
fun onUserInfoChanged(picture: Drawable?, isGuestUser: Boolean) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 1a7a306c978c..cdf770f80387 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -112,6 +112,16 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+ // Pass configuration change to non-attached pages as well. Some config changes will cause
+ // QS to recreate itself (as determined in FragmentHostManager), but in order to minimize
+ // those, make sure that all get passed to all pages.
+ int numPages = mPages.size();
+ for (int i = 0; i < numPages; i++) {
+ View page = mPages.get(i);
+ if (page.getParent() == null) {
+ page.dispatchConfigurationChanged(newConfig);
+ }
+ }
if (mLayoutOrientation != newConfig.orientation) {
mLayoutOrientation = newConfig.orientation;
mDistributeTiles = true;
@@ -166,6 +176,14 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
updateListening();
}
+ @Override
+ public void setSquishinessFraction(float squishinessFraction) {
+ int nPages = mPages.size();
+ for (int i = 0; i < nPages; i++) {
+ mPages.get(i).setSquishinessFraction(squishinessFraction);
+ }
+ }
+
private void updateListening() {
for (TileLayout tilePage : mPages) {
tilePage.setListening(tilePage.getParent() != null && mListening);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 90d3448ac1ef..44d5e21e6354 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -316,8 +316,8 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
if (mQQSTileHeightAnimator == null) {
mQQSTileHeightAnimator = new HeightExpansionAnimator(this,
- quickTileView.getHeight(), tileView.getHeight());
- qqsTileHeight = quickTileView.getHeight();
+ quickTileView.getMeasuredHeight(), tileView.getMeasuredHeight());
+ qqsTileHeight = quickTileView.getMeasuredHeight();
}
mQQSTileHeightAnimator.addView(quickTileView);
@@ -380,7 +380,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
if (mOtherTilesExpandAnimator == null) {
mOtherTilesExpandAnimator =
new HeightExpansionAnimator(
- this, qqsTileHeight, tileView.getHeight());
+ this, qqsTileHeight, tileView.getMeasuredHeight());
}
mOtherTilesExpandAnimator.addView(tileView);
tileView.setClipChildren(true);
@@ -658,7 +658,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
mTranslateWhileExpanding = shouldTranslate;
}
- static class HeightExpansionAnimator {
+ private static class HeightExpansionAnimator {
private final List<View> mViews = new ArrayList<>();
private final ValueAnimator mAnimator;
private final TouchAnimator.Listener mListener;
@@ -673,9 +673,10 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
int height = (Integer) valueAnimator.getAnimatedValue();
for (int i = 0; i < viewCount; i++) {
View v = mViews.get(i);
- v.setBottom(v.getTop() + height);
if (v instanceof HeightOverrideable) {
((HeightOverrideable) v).setHeightOverride(height);
+ } else {
+ v.setBottom(v.getTop() + height);
}
}
if (t == 0f) {
@@ -713,9 +714,10 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
final int viewsCount = mViews.size();
for (int i = 0; i < viewsCount; i++) {
View v = mViews.get(i);
- v.setBottom(v.getTop() + v.getMeasuredHeight());
if (v instanceof HeightOverrideable) {
((HeightOverrideable) v).resetOverride();
+ } else {
+ v.setBottom(v.getTop() + v.getMeasuredHeight());
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 89bbcf5053a0..dd876b7c7d24 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -15,6 +15,7 @@
package com.android.systemui.qs;
import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
+import static com.android.systemui.statusbar.DisableFlagsLogger.DisableState;
import static com.android.systemui.media.dagger.MediaModule.QS_PANEL;
import static com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL;
@@ -81,6 +82,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
private QSAnimator mQSAnimator;
private HeightListener mPanelView;
+ private QSSquishinessController mQSSquishinessController;
protected QuickStatusBarHeader mHeader;
protected NonInterceptingScrollView mQSPanelScrollView;
private QSDetail mQSDetail;
@@ -90,6 +92,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
private QSFooter mFooter;
private float mLastQSExpansion = -1;
private float mLastPanelFraction;
+ private float mSquishinessFraction = 1;
private boolean mQsDisabled;
private ImageView mQsDragHandler;
@@ -99,6 +102,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
private final MediaHost mQsMediaHost;
private final MediaHost mQqsMediaHost;
private final QSFragmentComponent.Factory mQsComponentFactory;
+ private final QSFragmentDisableFlagsLogger mQsFragmentDisableFlagsLogger;
private final QSTileHost mHost;
private boolean mShowCollapsedOnKeyguard;
private boolean mLastKeyguardAndExpanded;
@@ -149,6 +153,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
@Named(QUICK_QS_PANEL) MediaHost qqsMediaHost,
KeyguardBypassController keyguardBypassController,
QSFragmentComponent.Factory qsComponentFactory,
+ QSFragmentDisableFlagsLogger qsFragmentDisableFlagsLogger,
FalsingManager falsingManager, DumpManager dumpManager) {
mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
mCommandQueue = commandQueue;
@@ -156,6 +161,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
mQsMediaHost = qsMediaHost;
mQqsMediaHost = qqsMediaHost;
mQsComponentFactory = qsComponentFactory;
+ mQsFragmentDisableFlagsLogger = qsFragmentDisableFlagsLogger;
commandQueue.observe(getLifecycle(), this);
mHost = qsTileHost;
mFalsingManager = falsingManager;
@@ -210,6 +216,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
mQSDetail.setQsPanel(mQSPanelController, mHeader, mFooter, mFalsingManager);
mQSAnimator = qsFragmentComponent.getQSAnimator();
+ mQSSquishinessController = qsFragmentComponent.getQSSquishinessController();
mQSCustomizerController = qsFragmentComponent.getQSCustomizerController();
mQSCustomizerController.init();
@@ -231,7 +238,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
boolean sizeChanged = (oldTop - oldBottom) != (top - bottom);
if (sizeChanged) {
setQsExpansion(mLastQSExpansion, mLastPanelFraction,
- mLastHeaderTranslation);
+ mLastHeaderTranslation, mSquishinessFraction);
}
});
mQSPanelController.setUsingHorizontalLayoutChangeListener(
@@ -360,8 +367,14 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
if (displayId != getContext().getDisplayId()) {
return;
}
+ int state2BeforeAdjustment = state2;
state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2);
+ mQsFragmentDisableFlagsLogger.logDisableFlagChange(
+ /* new= */ new DisableState(state1, state2BeforeAdjustment),
+ /* newAfterLocalModification= */ new DisableState(state1, state2)
+ );
+
final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
if (disabled == mQsDisabled) return;
mQsDisabled = disabled;
@@ -413,7 +426,8 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
mQSAnimator.setShowCollapsedOnKeyguard(showCollapsed);
}
if (!showCollapsed && isKeyguardState()) {
- setQsExpansion(mLastQSExpansion, mLastPanelFraction, 0);
+ setQsExpansion(mLastQSExpansion, mLastPanelFraction, 0,
+ mSquishinessFraction);
}
}
}
@@ -494,12 +508,13 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
updateShowCollapsedOnKeyguard();
}
mFullShadeProgress = progress;
- setQsExpansion(mLastQSExpansion, mLastPanelFraction, mLastHeaderTranslation);
+ setQsExpansion(mLastQSExpansion, mLastPanelFraction, mLastHeaderTranslation,
+ isTransitioningToFullShade ? progress : mSquishinessFraction);
}
@Override
public void setQsExpansion(float expansion, float panelExpansionFraction,
- float proposedTranslation) {
+ float proposedTranslation, float squishinessFraction) {
float headerTranslation = mTransitioningToFullShade ? 0 : proposedTranslation;
float progress = mTransitioningToFullShade ? mFullShadeProgress : panelExpansionFraction;
setAlphaAnimationProgress(mInSplitShade ? progress : 1);
@@ -517,11 +532,13 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
if (expansion == mLastQSExpansion
&& mLastKeyguardAndExpanded == onKeyguardAndExpanded
&& mLastViewHeight == currentHeight
- && mLastHeaderTranslation == headerTranslation) {
+ && mLastHeaderTranslation == headerTranslation
+ && mSquishinessFraction == squishinessFraction) {
return;
}
mLastHeaderTranslation = headerTranslation;
mLastPanelFraction = panelExpansionFraction;
+ mSquishinessFraction = squishinessFraction;
mLastQSExpansion = expansion;
mLastKeyguardAndExpanded = onKeyguardAndExpanded;
mLastViewHeight = currentHeight;
@@ -557,6 +574,9 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
}
updateQsBounds();
+ if (mQSSquishinessController != null) {
+ mQSSquishinessController.setSquishiness(mSquishinessFraction);
+ }
if (mQSAnimator != null) {
mQSAnimator.setPosition(expansion);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt
new file mode 100644
index 000000000000..17a815e72583
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt
@@ -0,0 +1,48 @@
+package com.android.systemui.qs
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.dagger.QSFragmentDisableLog
+import com.android.systemui.statusbar.DisableFlagsLogger
+import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment
+import javax.inject.Inject
+
+/** A helper class for logging disable flag changes made in [QSFragment]. */
+class QSFragmentDisableFlagsLogger @Inject constructor(
+ @QSFragmentDisableLog private val buffer: LogBuffer,
+ private val disableFlagsLogger: DisableFlagsLogger
+) {
+
+ /**
+ * Logs a string representing the new state received by [QSFragment] and any modifications that
+ * were made to the flags locally.
+ *
+ * @param new see [DisableFlagsLogger.getDisableFlagsString]
+ * @param newAfterLocalModification see [DisableFlagsLogger.getDisableFlagsString]
+ */
+ fun logDisableFlagChange(
+ new: DisableFlagsLogger.DisableState,
+ newAfterLocalModification: DisableFlagsLogger.DisableState
+ ) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ {
+ int1 = new.disable1
+ int2 = new.disable2
+ long1 = newAfterLocalModification.disable1.toLong()
+ long2 = newAfterLocalModification.disable2.toLong()
+ },
+ {
+ disableFlagsLogger.getDisableFlagsString(
+ old = null,
+ new = DisableFlagsLogger.DisableState(int1, int2),
+ newAfterLocalModification =
+ DisableFlagsLogger.DisableState(long1.toInt(), long2.toInt())
+ )
+ }
+ )
+ }
+}
+
+private const val TAG = "QSFragmentDisableFlagsLog" \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 28aa884d6f9e..71eb4a2e6cbb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -41,7 +41,7 @@ import com.android.internal.widget.RemeasuringLinearLayout;
import com.android.systemui.R;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSTile;
-import com.android.systemui.settings.brightness.BrightnessSlider;
+import com.android.systemui.settings.brightness.BrightnessSliderController;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -69,7 +69,7 @@ public class QSPanel extends LinearLayout implements Tunable {
@Nullable
protected View mBrightnessView;
@Nullable
- protected BrightnessSlider mToggleSliderController;
+ protected BrightnessSliderController mToggleSliderController;
private final H mHandler = new H();
/** Whether or not the QS media player feature is enabled. */
@@ -736,6 +736,11 @@ public class QSPanel extends LinearLayout implements Tunable {
void setListening(boolean listening, UiEventLogger uiEventLogger);
/**
+ * Sets a size modifier for the tile. Where 0 means collapsed, and 1 expanded.
+ */
+ void setSquishinessFraction(float squishinessFraction);
+
+ /**
* Sets the minimum number of rows to show
*
* @param minRows the minimum.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index 70892a7047c0..6794d5b0cee4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -41,7 +41,7 @@ import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.settings.brightness.BrightnessController;
import com.android.systemui.settings.brightness.BrightnessMirrorHandler;
-import com.android.systemui.settings.brightness.BrightnessSlider;
+import com.android.systemui.settings.brightness.BrightnessSliderController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.tuner.TunerService;
@@ -63,7 +63,7 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
private final FalsingManager mFalsingManager;
private final CommandQueue mCommandQueue;
private final BrightnessController mBrightnessController;
- private final BrightnessSlider mBrightnessSlider;
+ private final BrightnessSliderController mBrightnessSliderController;
private final BrightnessMirrorHandler mBrightnessMirrorHandler;
private boolean mGridContentVisible = true;
@@ -99,8 +99,8 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
QSTileRevealController.Factory qsTileRevealControllerFactory,
DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
QSLogger qsLogger, BrightnessController.Factory brightnessControllerFactory,
- BrightnessSlider.Factory brightnessSliderFactory, FalsingManager falsingManager,
- CommandQueue commandQueue) {
+ BrightnessSliderController.Factory brightnessSliderFactory,
+ FalsingManager falsingManager, CommandQueue commandQueue) {
super(view, qstileHost, qsCustomizerController, usingMediaPlayer, mediaHost,
metricsLogger, uiEventLogger, qsLogger, dumpManager);
mQsSecurityFooter = qsSecurityFooter;
@@ -111,10 +111,10 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
mCommandQueue = commandQueue;
mQsSecurityFooter.setHostEnvironment(qstileHost);
- mBrightnessSlider = brightnessSliderFactory.create(getContext(), mView);
- mView.setBrightnessView(mBrightnessSlider.getRootView());
+ mBrightnessSliderController = brightnessSliderFactory.create(getContext(), mView);
+ mView.setBrightnessView(mBrightnessSliderController.getRootView());
- mBrightnessController = brightnessControllerFactory.create(mBrightnessSlider);
+ mBrightnessController = brightnessControllerFactory.create(mBrightnessSliderController);
mBrightnessMirrorHandler = new BrightnessMirrorHandler(mBrightnessController);
}
@@ -125,7 +125,7 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
mMediaHost.setShowsOnlyActiveMedia(false);
mMediaHost.init(MediaHierarchyManager.LOCATION_QS);
mQsCustomizerController.init();
- mBrightnessSlider.init();
+ mBrightnessSliderController.init();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSquishinessController.kt b/packages/SystemUI/src/com/android/systemui/qs/QSSquishinessController.kt
new file mode 100644
index 000000000000..c1c146d40e38
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSquishinessController.kt
@@ -0,0 +1,55 @@
+package com.android.systemui.qs
+
+import android.view.ViewGroup
+import com.android.systemui.qs.dagger.QSFragmentModule.QQS_FOOTER
+import com.android.systemui.qs.dagger.QSScope
+import javax.inject.Inject
+import javax.inject.Named
+
+@QSScope
+class QSSquishinessController @Inject constructor(
+ @Named(QQS_FOOTER) private val qqsFooterActionsView: FooterActionsView,
+ private val qsAnimator: QSAnimator,
+ private val qsPanelController: QSPanelController,
+ private val quickQSPanelController: QuickQSPanelController
+) {
+
+ /**
+ * Fraction from 0 to 1, where 0 is collapsed and 1 expanded.
+ */
+ var squishiness: Float = 1f
+ set(value) {
+ if (field == value) {
+ return
+ }
+ if ((field != 1f && value == 1f) || (field != 0f && value == 0f)) {
+ qsAnimator.requestAnimatorUpdate()
+ }
+ field = value
+ updateSquishiness()
+ }
+
+ /**
+ * Change the height of all tiles and repositions their siblings.
+ */
+ private fun updateSquishiness() {
+ (qsPanelController.tileLayout as QSPanel.QSTileLayout).setSquishinessFraction(squishiness)
+ val tileLayout = quickQSPanelController.tileLayout as TileLayout
+ tileLayout.setSquishinessFraction(squishiness)
+
+ // Calculate how much we should move the footer
+ val tileHeightOffset = tileLayout.height - tileLayout.tilesHeight
+ val footerTopMargin = (qqsFooterActionsView.layoutParams as ViewGroup.MarginLayoutParams)
+ .topMargin
+ val nextTop = tileLayout.bottom - tileHeightOffset + footerTopMargin
+ val amountMoved = nextTop - qqsFooterActionsView.top
+
+ // Move the footer and other siblings (MediaPlayer)
+ (qqsFooterActionsView.parent as ViewGroup?)?.let { parent ->
+ val index = parent.indexOfChild(qqsFooterActionsView)
+ for (i in index until parent.childCount) {
+ parent.getChildAt(i).top += amountMoved
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSBrightnessController.kt b/packages/SystemUI/src/com/android/systemui/qs/QuickQSBrightnessController.kt
index 14374ffe9f89..65889d792769 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSBrightnessController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSBrightnessController.kt
@@ -18,7 +18,7 @@ package com.android.systemui.qs
import androidx.annotation.VisibleForTesting
import com.android.systemui.settings.brightness.BrightnessController
-import com.android.systemui.settings.brightness.BrightnessSlider
+import com.android.systemui.settings.brightness.BrightnessSliderController
import com.android.systemui.settings.brightness.MirroredBrightnessController
import com.android.systemui.statusbar.policy.BrightnessMirrorController
import javax.inject.Inject
@@ -33,10 +33,11 @@ class QuickQSBrightnessController @VisibleForTesting constructor(
@Inject constructor(
brightnessControllerFactory: BrightnessController.Factory,
- brightnessSliderFactory: BrightnessSlider.Factory,
+ brightnessSliderControllerFactory: BrightnessSliderController.Factory,
quickQSPanel: QuickQSPanel
) : this(brightnessControllerFactory = {
- val slider = brightnessSliderFactory.create(quickQSPanel.context, quickQSPanel)
+ val slider = brightnessSliderControllerFactory.create(quickQSPanel.context,
+ quickQSPanel)
slider.init()
quickQSPanel.setBrightnessView(slider.rootView)
brightnessControllerFactory.create(slider)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 071e0535e7c2..a923effea1e1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -39,8 +39,8 @@ import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.qs.QSDetail.Callback;
+import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
-import com.android.systemui.statusbar.phone.StatusBarWindowView;
import com.android.systemui.statusbar.phone.StatusIconContainer;
import com.android.systemui.statusbar.policy.Clock;
import com.android.systemui.statusbar.policy.VariableDateView;
@@ -86,6 +86,7 @@ public class QuickStatusBarHeader extends FrameLayout {
private TintedIconManager mTintedIconManager;
private QSExpansionPathInterpolator mQSExpansionPathInterpolator;
+ private StatusBarContentInsetsProvider mInsetsProvider;
private int mRoundedCornerPadding = 0;
private int mWaterfallTopInset;
@@ -102,6 +103,8 @@ public class QuickStatusBarHeader extends FrameLayout {
private boolean mHasCenterCutout;
private boolean mConfigShowBatteryEstimate;
+ private boolean mUseCombinedQSHeader;
+
public QuickStatusBarHeader(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -158,9 +161,13 @@ public class QuickStatusBarHeader extends FrameLayout {
void onAttach(TintedIconManager iconManager,
QSExpansionPathInterpolator qsExpansionPathInterpolator,
- List<String> rssiIgnoredSlots) {
+ List<String> rssiIgnoredSlots,
+ boolean useCombinedQSHeader,
+ StatusBarContentInsetsProvider insetsProvider) {
+ mUseCombinedQSHeader = useCombinedQSHeader;
mTintedIconManager = iconManager;
mRssiIgnoredSlots = rssiIgnoredSlots;
+ mInsetsProvider = insetsProvider;
int fillColor = Utils.getColorAttrDefaultColor(getContext(),
android.R.attr.textColorPrimary);
@@ -233,8 +240,11 @@ public class QuickStatusBarHeader extends FrameLayout {
// status bar is already displayed out of QS in split shade
boolean shouldUseSplitShade =
resources.getBoolean(R.bool.config_use_split_notification_shade);
- mStatusIconsView.setVisibility(shouldUseSplitShade ? View.GONE : View.VISIBLE);
- mDatePrivacyView.setVisibility(shouldUseSplitShade ? View.GONE : View.VISIBLE);
+
+ mStatusIconsView.setVisibility(
+ shouldUseSplitShade || mUseCombinedQSHeader ? View.GONE : View.VISIBLE);
+ mDatePrivacyView.setVisibility(
+ shouldUseSplitShade || mUseCombinedQSHeader ? View.GONE : View.VISIBLE);
mConfigShowBatteryEstimate = resources.getBoolean(R.bool.config_showBatteryEstimateQSBH);
@@ -273,8 +283,8 @@ public class QuickStatusBarHeader extends FrameLayout {
}
MarginLayoutParams qqsLP = (MarginLayoutParams) mHeaderQsPanel.getLayoutParams();
- qqsLP.topMargin = mContext.getResources()
- .getDimensionPixelSize(R.dimen.qqs_layout_margin_top);
+ qqsLP.topMargin = shouldUseSplitShade || !mUseCombinedQSHeader ? mContext.getResources()
+ .getDimensionPixelSize(R.dimen.qqs_layout_margin_top) : qsOffsetHeight;
mHeaderQsPanel.setLayoutParams(qqsLP);
updateBatteryMode();
@@ -302,6 +312,10 @@ public class QuickStatusBarHeader extends FrameLayout {
}
private void updateAnimators() {
+ if (mUseCombinedQSHeader) {
+ mTranslationAnimator = null;
+ return;
+ }
updateAlphaAnimator();
int offset = mTopViewMeasureHeight;
@@ -314,6 +328,10 @@ public class QuickStatusBarHeader extends FrameLayout {
}
private void updateAlphaAnimator() {
+ if (mUseCombinedQSHeader) {
+ mAlphaAnimator = null;
+ return;
+ }
TouchAnimator.Builder builder = new TouchAnimator.Builder()
.addFloat(mSecurityHeaderView, "alpha", 0, 1)
// These views appear on expanding down
@@ -421,22 +439,20 @@ public class QuickStatusBarHeader extends FrameLayout {
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
// Handle padding of the views
DisplayCutout cutout = insets.getDisplayCutout();
- Pair<Integer, Integer> cornerCutoutPadding = StatusBarWindowView.cornerCutoutMargins(
- cutout, getDisplay());
- Pair<Integer, Integer> padding =
- StatusBarWindowView.paddingNeededForCutoutAndRoundedCorner(
- cutout, cornerCutoutPadding, -1);
- mDatePrivacyView.setPadding(padding.first, 0, padding.second, 0);
- mStatusIconsView.setPadding(padding.first, 0, padding.second, 0);
+
+ Pair<Integer, Integer> sbInsets = mInsetsProvider
+ .getStatusBarContentInsetsForCurrentRotation();
+ boolean hasCornerCutout = mInsetsProvider.currentRotationHasCornerCutout();
+
+ mDatePrivacyView.setPadding(sbInsets.first, 0, sbInsets.second, 0);
+ mStatusIconsView.setPadding(sbInsets.first, 0, sbInsets.second, 0);
LinearLayout.LayoutParams datePrivacySeparatorLayoutParams =
(LinearLayout.LayoutParams) mDatePrivacySeparator.getLayoutParams();
LinearLayout.LayoutParams mClockIconsSeparatorLayoutParams =
(LinearLayout.LayoutParams) mClockIconsSeparator.getLayoutParams();
- boolean cornerCutout = cornerCutoutPadding != null
- && (cornerCutoutPadding.first == 0 || cornerCutoutPadding.second == 0);
if (cutout != null) {
Rect topCutout = cutout.getBoundingRectTop();
- if (topCutout.isEmpty() || cornerCutout) {
+ if (topCutout.isEmpty() || hasCornerCutout) {
datePrivacySeparatorLayoutParams.width = 0;
mDatePrivacySeparator.setVisibility(View.GONE);
mClockIconsSeparatorLayoutParams.width = 0;
@@ -454,8 +470,8 @@ public class QuickStatusBarHeader extends FrameLayout {
}
mDatePrivacySeparator.setLayoutParams(datePrivacySeparatorLayoutParams);
mClockIconsSeparator.setLayoutParams(mClockIconsSeparatorLayoutParams);
- mCutOutPaddingLeft = padding.first;
- mCutOutPaddingRight = padding.second;
+ mCutOutPaddingLeft = sbInsets.first;
+ mCutOutPaddingRight = sbInsets.second;
mWaterfallTopInset = cutout == null ? 0 : cutout.getWaterfallInsets().top;
updateBatteryMode();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index 38428c53fead..3a80764d4c25 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -39,6 +39,7 @@ 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.phone.StatusBarContentInsetsProvider;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusIconContainer;
import com.android.systemui.statusbar.policy.Clock;
@@ -73,6 +74,7 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
private final QSExpansionPathInterpolator mQSExpansionPathInterpolator;
private final BatteryMeterViewController mBatteryMeterViewController;
private final FeatureFlags mFeatureFlags;
+ private final StatusBarContentInsetsProvider mInsetsProvider;
private final VariableDateViewController mVariableDateViewControllerDateView;
private final VariableDateViewController mVariableDateViewControllerClockDateView;
@@ -142,7 +144,8 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
QSExpansionPathInterpolator qsExpansionPathInterpolator,
BatteryMeterViewController batteryMeterViewController,
FeatureFlags featureFlags,
- VariableDateViewController.Factory variableDateViewControllerFactory) {
+ VariableDateViewController.Factory variableDateViewControllerFactory,
+ StatusBarContentInsetsProvider statusBarContentInsetsProvider) {
super(view);
mPrivacyItemController = privacyItemController;
mActivityStarter = activityStarter;
@@ -155,6 +158,7 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
mQSExpansionPathInterpolator = qsExpansionPathInterpolator;
mBatteryMeterViewController = batteryMeterViewController;
mFeatureFlags = featureFlags;
+ mInsetsProvider = statusBarContentInsetsProvider;
mQSCarrierGroupController = qsCarrierGroupControllerBuilder
.setQSCarrierGroup(mView.findViewById(R.id.carrier_group))
@@ -225,7 +229,8 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
);
}
- mView.onAttach(mIconManager, mQSExpansionPathInterpolator, rssiIgnoredSlots);
+ mView.onAttach(mIconManager, mQSExpansionPathInterpolator, rssiIgnoredSlots,
+ mFeatureFlags.useCombinedQSHeaders(), mInsetsProvider);
mDemoModeController.addCallback(mDemoModeReceiver);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 1a890a7ad07b..7f08e5bdb575 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -13,6 +13,7 @@ import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.qs.QSPanel.QSTileLayout;
import com.android.systemui.qs.QSPanelControllerBase.TileRecord;
+import com.android.systemui.qs.tileimpl.HeightOverrideable;
import java.util.ArrayList;
@@ -41,6 +42,8 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
private int mMinRows = 1;
private int mMaxColumns = NO_MAX_COLUMNS;
protected int mResourceColumns;
+ private float mSquishinessFraction = 1f;
+ private int mLastTileBottom;
public TileLayout(Context context) {
this(context, null);
@@ -210,10 +213,11 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
return mMaxCellHeight;
}
- protected void layoutTileRecords(int numRecords) {
+ private void layoutTileRecords(int numRecords, boolean forLayout) {
final boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
int row = 0;
int column = 0;
+ mLastTileBottom = 0;
// Layout each QS tile.
final int tilesToLayout = Math.min(numRecords, mRows * mColumns);
@@ -228,17 +232,23 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
final int top = getRowTop(row);
final int left = getColumnStart(isRtl ? mColumns - column - 1 : column);
final int right = left + mCellWidth;
- record.tileView.layout(left, top, right, top + record.tileView.getMeasuredHeight());
+ final int bottom = top + record.tileView.getMeasuredHeight();
+ if (forLayout) {
+ record.tileView.layout(left, top, right, bottom);
+ } else {
+ record.tileView.setLeftTopRightBottom(left, top, right, bottom);
+ }
+ mLastTileBottom = bottom;
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
- layoutTileRecords(mRecords.size());
+ layoutTileRecords(mRecords.size(), true /* forLayout */);
}
protected int getRowTop(int row) {
- return row * (mCellHeight + mCellMarginVertical);
+ return (int) (row * (mCellHeight * mSquishinessFraction + mCellMarginVertical));
}
protected int getColumnStart(int column) {
@@ -264,4 +274,23 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
// up.
return Math.max(mColumns * mRows, 1);
}
+
+ public int getTilesHeight() {
+ return mLastTileBottom + getPaddingBottom();
+ }
+
+ @Override
+ public void setSquishinessFraction(float squishinessFraction) {
+ if (Float.compare(mSquishinessFraction, squishinessFraction) == 0) {
+ return;
+ }
+ mSquishinessFraction = squishinessFraction;
+ layoutTileRecords(mRecords.size(), false /* forLayout */);
+
+ for (TileRecord record : mRecords) {
+ if (record.tileView instanceof HeightOverrideable) {
+ ((HeightOverrideable) record.tileView).setSquishinessFraction(mSquishinessFraction);
+ }
+ }
+ }
}
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 fec61d911577..141c246db260 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
@@ -19,6 +19,7 @@ package com.android.systemui.qs.carrier;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
import android.annotation.MainThread;
+import android.annotation.NonNull;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
@@ -42,8 +43,10 @@ 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.connectivity.IconState;
+import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
import com.android.systemui.statusbar.connectivity.NetworkController;
-import com.android.systemui.statusbar.connectivity.NetworkController.MobileDataIndicators;
+import com.android.systemui.statusbar.connectivity.SignalCallback;
import com.android.systemui.util.CarrierConfigTracker;
import java.util.function.Consumer;
@@ -81,10 +84,9 @@ public class QSCarrierGroupController {
private final SlotIndexResolver mSlotIndexResolver;
- private final NetworkController.SignalCallback mSignalCallback =
- new NetworkController.SignalCallback() {
+ private final SignalCallback mSignalCallback = new SignalCallback() {
@Override
- public void setMobileDataIndicators(MobileDataIndicators indicators) {
+ public void setMobileDataIndicators(@NonNull MobileDataIndicators indicators) {
if (mProviderModel) {
return;
}
@@ -109,7 +111,7 @@ public class QSCarrierGroupController {
}
@Override
- public void setCallIndicator(NetworkController.IconState statusIcon, int subId) {
+ public void setCallIndicator(@NonNull IconState statusIcon, int subId) {
if (!mProviderModel) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java
index 8cc05026e1f1..63cbc21ddf74 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java
@@ -21,6 +21,7 @@ import com.android.systemui.qs.QSContainerImplController;
import com.android.systemui.qs.QSFooter;
import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanelController;
+import com.android.systemui.qs.QSSquishinessController;
import com.android.systemui.qs.QuickQSPanelController;
import com.android.systemui.qs.customize.QSCustomizerController;
@@ -57,4 +58,7 @@ public interface QSFragmentComponent {
/** Construct a {@link QSCustomizerController}. */
QSCustomizerController getQSCustomizerController();
+
+ /** Construct a {@link QSSquishinessController}. */
+ QSSquishinessController getQSSquishinessController();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index a7cd11314d7e..0f2db338a2a8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -345,8 +345,12 @@ public class TileServices extends IQSService.Stub {
@Override
public void onReceive(Context context, Intent intent) {
if (TileService.ACTION_REQUEST_LISTENING.equals(intent.getAction())) {
- requestListening(
- (ComponentName) intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME));
+ try {
+ ComponentName c = intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME);
+ requestListening(c);
+ } catch (ClassCastException ex) {
+ Log.e(TAG, "Bad component name", ex);
+ }
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/HeightOverrideable.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/HeightOverrideable.kt
index 866fa097d6fd..61d68eceb961 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/HeightOverrideable.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/HeightOverrideable.kt
@@ -21,9 +21,8 @@ interface HeightOverrideable {
const val NO_OVERRIDE = -1
}
- var heightOverride: Int
+ abstract var heightOverride: Int
+ abstract fun resetOverride()
- fun resetOverride() {
- heightOverride = NO_OVERRIDE
- }
+ abstract var squishinessFraction: Float
} \ No newline at end of file
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 222539d49526..2bd5c8f0fc20 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -42,6 +42,7 @@ import androidx.annotation.VisibleForTesting
import com.android.settingslib.Utils
import com.android.systemui.FontSizeUtils
import com.android.systemui.R
+import com.android.systemui.animation.LaunchableView
import com.android.systemui.plugins.qs.QSIconView
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.plugins.qs.QSTile.BooleanState
@@ -54,7 +55,7 @@ open class QSTileViewImpl @JvmOverloads constructor(
context: Context,
private val _icon: QSIconView,
private val collapsed: Boolean = false
-) : QSTileView(context), HeightOverrideable {
+) : QSTileView(context), HeightOverrideable, LaunchableView {
companion object {
private const val INVALID = -1
@@ -68,6 +69,18 @@ open class QSTileViewImpl @JvmOverloads constructor(
}
override var heightOverride: Int = HeightOverrideable.NO_OVERRIDE
+ set(value) {
+ if (field == value) return
+ field = value
+ updateHeight()
+ }
+
+ override var squishinessFraction: Float = 1f
+ set(value) {
+ if (field == value) return
+ field = value
+ updateHeight()
+ }
private val colorActive = Utils.getColorAttrDefaultColor(context,
com.android.internal.R.attr.colorAccentPrimary)
@@ -118,6 +131,8 @@ open class QSTileViewImpl @JvmOverloads constructor(
private var lastStateDescription: CharSequence? = null
private var tileState = false
private var lastState = INVALID
+ private var blockVisibilityChanges = false
+ private var lastVisibility = View.VISIBLE
private val locInScreen = IntArray(2)
@@ -148,6 +163,11 @@ open class QSTileViewImpl @JvmOverloads constructor(
updateResources()
}
+ override fun resetOverride() {
+ heightOverride = HeightOverrideable.NO_OVERRIDE
+ updateHeight()
+ }
+
fun updateResources() {
FontSizeUtils.updateFontSize(label, R.dimen.qs_tile_text_size)
FontSizeUtils.updateFontSize(secondaryLabel, R.dimen.qs_tile_text_size)
@@ -218,9 +238,17 @@ open class QSTileViewImpl @JvmOverloads constructor(
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
super.onLayout(changed, l, t, r, b)
- if (heightOverride != HeightOverrideable.NO_OVERRIDE) {
- bottom = top + heightOverride
+ updateHeight()
+ }
+
+ private fun updateHeight() {
+ val actualHeight = if (heightOverride != HeightOverrideable.NO_OVERRIDE) {
+ heightOverride
+ } else {
+ measuredHeight
}
+ bottom = top + (actualHeight * squishinessFraction).toInt()
+ scrollY = (actualHeight - height) / 2
}
override fun updateAccessibilityOrder(previousView: View?): View {
@@ -294,6 +322,36 @@ open class QSTileViewImpl @JvmOverloads constructor(
return sideView
}
+ override fun setShouldBlockVisibilityChanges(block: Boolean) {
+ blockVisibilityChanges = block
+
+ if (block) {
+ lastVisibility = visibility
+ } else {
+ visibility = lastVisibility
+ }
+ }
+
+ override fun setVisibility(visibility: Int) {
+ if (blockVisibilityChanges) {
+ lastVisibility = visibility
+ return
+ }
+
+ super.setVisibility(visibility)
+ }
+
+ override fun setTransitionVisibility(visibility: Int) {
+ if (blockVisibilityChanges) {
+ // View.setTransitionVisibility just sets the visibility flag, so we don't have to save
+ // the transition visibility separately from the normal visibility.
+ lastVisibility = visibility
+ return
+ }
+
+ super.setTransitionVisibility(visibility)
+ }
+
// Accessibility
override fun onInitializeAccessibilityEvent(event: AccessibilityEvent) {
@@ -459,7 +517,7 @@ open class QSTileViewImpl @JvmOverloads constructor(
}
private fun setColor(color: Int) {
- colorBackgroundDrawable.setTint(color)
+ colorBackgroundDrawable.mutate().setTint(color)
paintColor = color
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 9de6ceb2de4b..0427e38aa811 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -18,6 +18,7 @@ package com.android.systemui.qs.tiles;
import static android.media.MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
+import android.annotation.NonNull;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
@@ -52,7 +53,8 @@ import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.connectivity.NetworkController;
-import com.android.systemui.statusbar.connectivity.NetworkController.WifiIndicators;
+import com.android.systemui.statusbar.connectivity.SignalCallback;
+import com.android.systemui.statusbar.connectivity.WifiIndicators;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastController.CastDevice;
@@ -273,10 +275,9 @@ public class CastTile extends QSTileImpl<BooleanState> {
return mWifiConnected || mHotspotConnected;
}
- private final NetworkController.SignalCallback mSignalCallback =
- new NetworkController.SignalCallback() {
+ private final SignalCallback mSignalCallback = new SignalCallback() {
@Override
- public void setWifiIndicators(WifiIndicators indicators) {
+ public void setWifiIndicators(@NonNull WifiIndicators indicators) {
// statusIcon.visible has the connected status information
boolean enabledAndConnected = indicators.enabled
&& (indicators.qsIcon == null ? false : indicators.qsIcon.visible);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 35dadd45eb3e..e5601f29af0b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -18,6 +18,7 @@ package com.android.systemui.qs.tiles;
import static com.android.systemui.Prefs.Key.QS_HAS_TURNED_OFF_MOBILE_DATA;
+import android.annotation.NonNull;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
@@ -56,10 +57,10 @@ import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.SignalTileView;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.statusbar.connectivity.IconState;
+import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
import com.android.systemui.statusbar.connectivity.NetworkController;
-import com.android.systemui.statusbar.connectivity.NetworkController.IconState;
-import com.android.systemui.statusbar.connectivity.NetworkController.MobileDataIndicators;
-import com.android.systemui.statusbar.connectivity.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.connectivity.SignalCallback;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import javax.inject.Inject;
@@ -269,7 +270,7 @@ public class CellularTile extends QSTileImpl<SignalState> {
private final CallbackInfo mInfo = new CallbackInfo();
@Override
- public void setMobileDataIndicators(MobileDataIndicators indicators) {
+ public void setMobileDataIndicators(@NonNull MobileDataIndicators indicators) {
if (indicators.qsIcon == null) {
// Not data sim, don't display.
return;
@@ -291,7 +292,7 @@ public class CellularTile extends QSTileImpl<SignalState> {
}
@Override
- public void setIsAirplaneMode(IconState icon) {
+ public void setIsAirplaneMode(@NonNull IconState icon) {
mInfo.airplaneModeEnabled = icon.visible;
refreshState(mInfo);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index 5a11ff83ff9e..7ba9cc22bec9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -14,7 +14,6 @@
package com.android.systemui.qs.tiles;
-import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
@@ -29,6 +28,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Prefs;
import com.android.systemui.R;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
@@ -47,6 +47,7 @@ public class DataSaverTile extends QSTileImpl<BooleanState> implements
DataSaverController.Listener{
private final DataSaverController mDataSaverController;
+ private final DialogLaunchAnimator mDialogLaunchAnimator;
@Inject
public DataSaverTile(
@@ -58,11 +59,13 @@ public class DataSaverTile extends QSTileImpl<BooleanState> implements
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
- DataSaverController dataSaverController
+ DataSaverController dataSaverController,
+ DialogLaunchAnimator dialogLaunchAnimator
) {
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
mDataSaverController = dataSaverController;
+ mDialogLaunchAnimator = dialogLaunchAnimator;
mDataSaverController.observe(getLifecycle(), this);
}
@@ -83,18 +86,27 @@ public class DataSaverTile extends QSTileImpl<BooleanState> implements
toggleDataSaver();
return;
}
- // Shows dialog first
- SystemUIDialog dialog = new SystemUIDialog(mContext);
- dialog.setTitle(com.android.internal.R.string.data_saver_enable_title);
- dialog.setMessage(com.android.internal.R.string.data_saver_description);
- dialog.setPositiveButton(com.android.internal.R.string.data_saver_enable_button,
- (OnClickListener) (dialogInterface, which) -> {
- toggleDataSaver();
- Prefs.putBoolean(mContext, Prefs.Key.QS_DATA_SAVER_DIALOG_SHOWN, true);
- });
- dialog.setNegativeButton(com.android.internal.R.string.cancel, null);
- dialog.setShowForAllUsers(true);
- dialog.show();
+
+ // Show a dialog to confirm first. Dialogs shown by the DialogLaunchAnimator must be created
+ // and shown on the main thread, so we post it to the UI handler.
+ mUiHandler.post(() -> {
+ SystemUIDialog dialog = new SystemUIDialog(mContext);
+ dialog.setTitle(com.android.internal.R.string.data_saver_enable_title);
+ dialog.setMessage(com.android.internal.R.string.data_saver_description);
+ dialog.setPositiveButton(com.android.internal.R.string.data_saver_enable_button,
+ (dialogInterface, which) -> {
+ toggleDataSaver();
+ Prefs.putBoolean(mContext, Prefs.Key.QS_DATA_SAVER_DIALOG_SHOWN, true);
+ });
+ dialog.setNegativeButton(com.android.internal.R.string.cancel, null);
+ dialog.setShowForAllUsers(true);
+
+ if (view != null) {
+ mDialogLaunchAnimator.showFromView(dialog, view);
+ } else {
+ dialog.show();
+ }
+ });
}
private void toggleDataSaver() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
index bc21b2d0fba7..80ec0adc21a9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
@@ -112,20 +112,9 @@ class DeviceControlsTile @Inject constructor(
}
mUiHandler.post {
- if (keyguardStateController.isUnlocked) {
- mActivityStarter.startActivity(
- intent, true /* dismissShade */, animationController)
- } else {
- if (state.state == Tile.STATE_ACTIVE) {
- mHost.collapsePanels()
- // With an active tile, don't use ActivityStarter so that the activity is
- // started without prompting keyguard unlock.
- mContext.startActivity(intent)
- } else {
- mActivityStarter.postStartActivityDismissingKeyguard(
- intent, 0 /* delay */, animationController)
- }
- }
+ val showOverLockscreenWhenLocked = state.state == Tile.STATE_ACTIVE
+ mActivityStarter.startActivity(
+ intent, true /* dismissShade */, animationController, showOverLockscreenWhenLocked)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index 98d0a72685ba..cd81b4a11703 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles;
+import android.annotation.NonNull;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -52,13 +53,13 @@ import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.qs.tiles.dialog.InternetDialogFactory;
+import com.android.systemui.statusbar.connectivity.AccessPointController;
+import com.android.systemui.statusbar.connectivity.IconState;
+import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
import com.android.systemui.statusbar.connectivity.NetworkController;
-import com.android.systemui.statusbar.connectivity.NetworkController.AccessPointController;
-import com.android.systemui.statusbar.connectivity.NetworkController.IconState;
-import com.android.systemui.statusbar.connectivity.NetworkController.MobileDataIndicators;
-import com.android.systemui.statusbar.connectivity.NetworkController.SignalCallback;
-import com.android.systemui.statusbar.connectivity.NetworkController.WifiIndicators;
+import com.android.systemui.statusbar.connectivity.SignalCallback;
import com.android.systemui.statusbar.connectivity.WifiIcons;
+import com.android.systemui.statusbar.connectivity.WifiIndicators;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -124,7 +125,7 @@ public class InternetTile extends QSTileImpl<SignalState> {
protected void handleClick(@Nullable View view) {
mHandler.post(() -> mInternetDialogFactory.create(true,
mAccessPointController.canConfigMobileData(),
- mAccessPointController.canConfigWifi()));
+ mAccessPointController.canConfigWifi(), view));
}
@Override
@@ -250,7 +251,7 @@ public class InternetTile extends QSTileImpl<SignalState> {
@Override
- public void setWifiIndicators(WifiIndicators indicators) {
+ public void setWifiIndicators(@NonNull WifiIndicators indicators) {
if (DEBUG) {
Log.d(TAG, "setWifiIndicators: " + indicators);
}
@@ -271,7 +272,7 @@ public class InternetTile extends QSTileImpl<SignalState> {
}
@Override
- public void setMobileDataIndicators(MobileDataIndicators indicators) {
+ public void setMobileDataIndicators(@NonNull MobileDataIndicators indicators) {
if (DEBUG) {
Log.d(TAG, "setMobileDataIndicators: " + indicators);
}
@@ -293,7 +294,7 @@ public class InternetTile extends QSTileImpl<SignalState> {
}
@Override
- public void setEthernetIndicators(IconState icon) {
+ public void setEthernetIndicators(@NonNull IconState icon) {
if (DEBUG) {
Log.d(TAG, "setEthernetIndicators: "
+ "icon = " + (icon == null ? "" : icon.toString()));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
index 24b9208d4ed1..8ff75cb3662d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
@@ -29,6 +29,7 @@ import androidx.annotation.Nullable;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
@@ -39,7 +40,9 @@ import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.screenrecord.RecordingController;
+import com.android.systemui.screenrecord.ScreenRecordDialog;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import javax.inject.Inject;
@@ -49,10 +52,13 @@ import javax.inject.Inject;
public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState>
implements RecordingController.RecordingStateChangeCallback {
private static final String TAG = "ScreenRecordTile";
- private RecordingController mController;
- private KeyguardDismissUtil mKeyguardDismissUtil;
+ private final RecordingController mController;
+ private final KeyguardDismissUtil mKeyguardDismissUtil;
+ private final KeyguardStateController mKeyguardStateController;
+ private final Callback mCallback = new Callback();
+ private final DialogLaunchAnimator mDialogLaunchAnimator;
+
private long mMillisUntilFinished = 0;
- private Callback mCallback = new Callback();
@Inject
public ScreenRecordTile(
@@ -65,13 +71,17 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState>
ActivityStarter activityStarter,
QSLogger qsLogger,
RecordingController controller,
- KeyguardDismissUtil keyguardDismissUtil
+ KeyguardDismissUtil keyguardDismissUtil,
+ KeyguardStateController keyguardStateController,
+ DialogLaunchAnimator dialogLaunchAnimator
) {
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
mController = controller;
mController.observe(this, mCallback);
mKeyguardDismissUtil = keyguardDismissUtil;
+ mKeyguardStateController = keyguardStateController;
+ mDialogLaunchAnimator = dialogLaunchAnimator;
}
@Override
@@ -89,7 +99,7 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState>
} else if (mController.isRecording()) {
stopRecording();
} else {
- mUiHandler.post(() -> showPrompt());
+ mUiHandler.post(() -> showPrompt(view));
}
refreshState();
}
@@ -136,15 +146,33 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState>
return mContext.getString(R.string.quick_settings_screen_record_label);
}
- private void showPrompt() {
- // Close QS, otherwise the dialog appears beneath it
- getHost().collapsePanels();
- Intent intent = mController.getPromptIntent();
+ private void showPrompt(@Nullable View view) {
+ // We animate from the touched view only if we are not on the keyguard, given that if we
+ // are we will dismiss it which will also collapse the shade.
+ boolean shouldAnimateFromView = view != null && !mKeyguardStateController.isShowing();
+
+ // Create the recording dialog that will collapse the shade only if we start the recording.
+ Runnable onStartRecordingClicked = () -> {
+ // We dismiss the shade. Since starting the recording will also dismiss the dialog, we
+ // disable the exit animation which looks weird when it happens at the same time as the
+ // shade collapsing.
+ mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations();
+ getHost().collapsePanels();
+ };
+ ScreenRecordDialog dialog = mController.createScreenRecordDialog(mContext,
+ onStartRecordingClicked);
+
ActivityStarter.OnDismissAction dismissAction = () -> {
- mHost.getUserContext().startActivity(intent);
+ if (shouldAnimateFromView) {
+ mDialogLaunchAnimator.showFromView(dialog, view);
+ } else {
+ dialog.show();
+ }
return false;
};
- mKeyguardDismissUtil.executeWhenUnlocked(dismissAction, false, false);
+
+ mKeyguardDismissUtil.executeWhenUnlocked(dismissAction, false /* requiresShadeOpen */,
+ true /* afterKeyguardDone */);
}
private void cancelCountdown() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index e6e7e21263bb..e79ca0c93212 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles;
+import android.annotation.NonNull;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -52,11 +53,11 @@ import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSIconViewImpl;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.statusbar.connectivity.AccessPointController;
import com.android.systemui.statusbar.connectivity.NetworkController;
-import com.android.systemui.statusbar.connectivity.NetworkController.AccessPointController;
-import com.android.systemui.statusbar.connectivity.NetworkController.SignalCallback;
-import com.android.systemui.statusbar.connectivity.NetworkController.WifiIndicators;
+import com.android.systemui.statusbar.connectivity.SignalCallback;
import com.android.systemui.statusbar.connectivity.WifiIcons;
+import com.android.systemui.statusbar.connectivity.WifiIndicators;
import com.android.wifitrackerlib.WifiEntry;
import java.util.List;
@@ -310,7 +311,7 @@ public class WifiTile extends QSTileImpl<SignalState> {
final CallbackInfo mInfo = new CallbackInfo();
@Override
- public void setWifiIndicators(WifiIndicators indicators) {
+ public void setWifiIndicators(@NonNull WifiIndicators indicators) {
if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + indicators.enabled);
if (indicators.qsIcon == null) {
return;
@@ -332,7 +333,7 @@ public class WifiTile extends QSTileImpl<SignalState> {
}
protected class WifiDetailAdapter implements DetailAdapter,
- NetworkController.AccessPointController.AccessPointCallback, QSDetailItems.Callback {
+ AccessPointController.AccessPointCallback, QSDetailItems.Callback {
private QSDetailItems mItems;
private WifiEntry[] mAccessPoints;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index 15b78e7cb08a..563c4cd628d2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -15,14 +15,11 @@
*/
package com.android.systemui.qs.tiles.dialog;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
-
import static com.android.systemui.Prefs.Key.QS_HAS_TURNED_OFF_MOBILE_DATA;
import android.app.AlertDialog;
import android.content.Context;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
+import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.net.Network;
import android.net.NetworkCapabilities;
@@ -41,10 +38,7 @@ import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
import android.view.Window;
-import android.view.WindowInsets;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -87,7 +81,6 @@ public class InternetDialog extends SystemUIDialog implements
private final Handler mHandler;
private final Executor mBackgroundExecutor;
- private final LinearLayoutManager mLayoutManager;
@VisibleForTesting
protected InternetAdapter mAdapter;
@@ -130,12 +123,14 @@ public class InternetDialog extends SystemUIDialog implements
private Switch mWiFiToggle;
private FrameLayout mDoneLayout;
private Drawable mBackgroundOn;
- private int mListMaxHeight;
+ private Drawable mBackgroundOff = null;
private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private boolean mCanConfigMobileData;
// Wi-Fi entries
+ @VisibleForTesting
protected WifiEntry mConnectedWifiEntry;
+ @VisibleForTesting
protected int mWifiEntriesCount;
// Wi-Fi scanning progress bar
@@ -149,20 +144,11 @@ public class InternetDialog extends SystemUIDialog implements
mInternetDialogSubTitle.setText(getSubtitleText());
};
- private final ViewTreeObserver.OnGlobalLayoutListener mInternetListLayoutListener = () -> {
- // Set max height for list
- if (mInternetDialogLayout.getHeight() > mListMaxHeight) {
- ViewGroup.LayoutParams params = mInternetDialogLayout.getLayoutParams();
- params.height = mListMaxHeight;
- mInternetDialogLayout.setLayoutParams(params);
- }
- };
-
public InternetDialog(Context context, InternetDialogFactory internetDialogFactory,
InternetDialogController internetDialogController, boolean canConfigMobileData,
boolean canConfigWifi, boolean aboveStatusBar, UiEventLogger uiEventLogger,
@Main Handler handler, @Background Executor executor) {
- super(context, R.style.Theme_SystemUI_Dialog_Internet);
+ super(context);
if (DEBUG) {
Log.d(TAG, "Init InternetDialog");
}
@@ -178,14 +164,6 @@ public class InternetDialog extends SystemUIDialog implements
mCanConfigMobileData = canConfigMobileData;
mCanConfigWifi = canConfigWifi;
- mLayoutManager = new LinearLayoutManager(mContext) {
- @Override
- public boolean canScrollVertically() {
- return false;
- }
- };
- mListMaxHeight = context.getResources().getDimensionPixelSize(
- R.dimen.internet_dialog_list_max_height);
mUiEventLogger = uiEventLogger;
mAdapter = new InternetAdapter(mInternetDialogController);
if (!aboveStatusBar) {
@@ -203,21 +181,9 @@ public class InternetDialog extends SystemUIDialog implements
mDialogView = LayoutInflater.from(mContext).inflate(R.layout.internet_connectivity_dialog,
null);
final Window window = getWindow();
- final WindowManager.LayoutParams layoutParams = window.getAttributes();
- layoutParams.gravity = Gravity.BOTTOM;
- // Move down the dialog to overlay the navigation bar.
- layoutParams.setFitInsetsTypes(
- layoutParams.getFitInsetsTypes() & ~WindowInsets.Type.navigationBars());
- layoutParams.setFitInsetsSides(WindowInsets.Side.all());
- layoutParams.setFitInsetsIgnoringVisibility(true);
- window.setAttributes(layoutParams);
window.setContentView(mDialogView);
- //Only fix the width for large screen or tablet.
- window.setLayout(mContext.getResources().getDimensionPixelSize(
- R.dimen.large_dialog_width), ViewGroup.LayoutParams.WRAP_CONTENT);
+
window.setWindowAnimations(R.style.Animation_InternetDialog);
- window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
- window.addFlags(FLAG_LAYOUT_NO_LIMITS);
mInternetDialogLayout = mDialogView.requireViewById(R.id.internet_connectivity_dialog);
mInternetDialogTitle = mDialogView.requireViewById(R.id.internet_dialog_title);
@@ -244,14 +210,20 @@ public class InternetDialog extends SystemUIDialog implements
mMobileDataToggle = mDialogView.requireViewById(R.id.mobile_toggle);
mWiFiToggle = mDialogView.requireViewById(R.id.wifi_toggle);
mBackgroundOn = mContext.getDrawable(R.drawable.settingslib_switch_bar_bg_on);
- mInternetDialogLayout.getViewTreeObserver().addOnGlobalLayoutListener(
- mInternetListLayoutListener);
mInternetDialogTitle.setText(getDialogTitleText());
mInternetDialogTitle.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
+ TypedArray typedArray = mContext.obtainStyledAttributes(
+ new int[]{android.R.attr.selectableItemBackground});
+ try {
+ mBackgroundOff = typedArray.getDrawable(0 /* index */);
+ } finally {
+ typedArray.recycle();
+ }
+
setOnClickListener();
mTurnWifiOnLayout.setBackground(null);
- mWifiRecyclerView.setLayoutManager(mLayoutManager);
+ mWifiRecyclerView.setLayoutManager(new LinearLayoutManager(mContext));
mWifiRecyclerView.setAdapter(mAdapter);
}
@@ -331,7 +303,7 @@ public class InternetDialog extends SystemUIDialog implements
showProgressBar();
final boolean isDeviceLocked = mInternetDialogController.isDeviceLocked();
final boolean isWifiEnabled = mWifiManager.isWifiEnabled();
- final boolean isWifiScanEnabled = mWifiManager.isScanAlwaysAvailable();
+ final boolean isWifiScanEnabled = mInternetDialogController.isWifiScanEnabled();
updateWifiToggle(isWifiEnabled, isDeviceLocked);
updateConnectedWifi(isWifiEnabled, isDeviceLocked);
updateWifiScanNotify(isWifiEnabled, isWifiScanEnabled, isDeviceLocked);
@@ -364,6 +336,9 @@ public class InternetDialog extends SystemUIDialog implements
mSeeAllLayout.setOnClickListener(v -> onClickSeeMoreButton());
mWiFiToggle.setOnCheckedChangeListener(
(buttonView, isChecked) -> {
+ if (isChecked) {
+ mWifiScanNotifyLayout.setVisibility(View.GONE);
+ }
buttonView.setChecked(isChecked);
mWifiManager.setWifiEnabled(isChecked);
});
@@ -404,7 +379,8 @@ public class InternetDialog extends SystemUIDialog implements
mMobileSummaryText.setTextAppearance(isCarrierNetworkConnected
? R.style.TextAppearance_InternetDialog_Secondary_Active
: R.style.TextAppearance_InternetDialog_Secondary);
- mMobileNetworkLayout.setBackground(isCarrierNetworkConnected ? mBackgroundOn : null);
+ mMobileNetworkLayout.setBackground(
+ isCarrierNetworkConnected ? mBackgroundOn : mBackgroundOff);
mMobileDataToggle.setVisibility(mCanConfigMobileData ? View.VISIBLE : View.INVISIBLE);
}
@@ -502,10 +478,6 @@ public class InternetDialog extends SystemUIDialog implements
}
private void setProgressBarVisible(boolean visible) {
- if (mWifiManager.isWifiEnabled() && mAdapter.mHolderView != null
- && mAdapter.mHolderView.isAttachedToWindow()) {
- mIsProgressBarVisible = true;
- }
mIsProgressBarVisible = visible;
mProgressBar.setVisibility(mIsProgressBarVisible ? View.VISIBLE : View.GONE);
mDivider.setVisibility(mIsProgressBarVisible ? View.GONE : View.VISIBLE);
@@ -609,12 +581,12 @@ public class InternetDialog extends SystemUIDialog implements
@WorkerThread
public void onAccessPointsChanged(@Nullable List<WifiEntry> wifiEntries,
@Nullable WifiEntry connectedEntry) {
- mConnectedWifiEntry = connectedEntry;
- mWifiEntriesCount = wifiEntries == null ? 0 : wifiEntries.size();
- mAdapter.setWifiEntries(wifiEntries, mWifiEntriesCount);
mHandler.post(() -> {
- mAdapter.notifyDataSetChanged();
+ mConnectedWifiEntry = connectedEntry;
+ mWifiEntriesCount = wifiEntries == null ? 0 : wifiEntries.size();
updateDialog(false /* shouldUpdateMobileNetwork */);
+ mAdapter.setWifiEntries(wifiEntries, mWifiEntriesCount);
+ mAdapter.notifyDataSetChanged();
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index 1ade5ce39c27..1c8bd784a00d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -71,13 +71,14 @@ import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.net.SignalStrengthUtil;
import com.android.settingslib.wifi.WifiUtils;
import com.android.systemui.R;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.statusbar.connectivity.NetworkController;
-import com.android.systemui.statusbar.connectivity.NetworkController.AccessPointController;
+import com.android.systemui.statusbar.connectivity.AccessPointController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.LocationController;
import com.android.systemui.toast.SystemUIToast;
import com.android.systemui.toast.ToastFactory;
import com.android.systemui.util.CarrierConfigTracker;
@@ -98,7 +99,7 @@ import java.util.stream.Stream;
import javax.inject.Inject;
public class InternetDialogController implements WifiEntry.DisconnectCallback,
- NetworkController.AccessPointController.AccessPointCallback {
+ AccessPointController.AccessPointCallback {
private static final String TAG = "InternetDialogController";
private static final String ACTION_NETWORK_PROVIDER_SETTINGS =
@@ -150,6 +151,8 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback,
private WindowManager mWindowManager;
private ToastFactory mToastFactory;
private SignalDrawable mSignalDrawable;
+ private LocationController mLocationController;
+ private DialogLaunchAnimator mDialogLaunchAnimator;
@VisibleForTesting
static final float TOAST_PARAMS_HORIZONTAL_WEIGHT = 1.0f;
@@ -199,7 +202,9 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback,
GlobalSettings globalSettings, KeyguardStateController keyguardStateController,
WindowManager windowManager, ToastFactory toastFactory,
@Background Handler workerHandler,
- CarrierConfigTracker carrierConfigTracker) {
+ CarrierConfigTracker carrierConfigTracker,
+ LocationController locationController,
+ DialogLaunchAnimator dialogLaunchAnimator) {
if (DEBUG) {
Log.d(TAG, "Init InternetDialogController");
}
@@ -227,6 +232,8 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback,
mWindowManager = windowManager;
mToastFactory = toastFactory;
mSignalDrawable = new SignalDrawable(mContext);
+ mLocationController = locationController;
+ mDialogLaunchAnimator = dialogLaunchAnimator;
}
void onStart(@NonNull InternetDialogCallback callback, boolean canConfigWifi) {
@@ -592,20 +599,32 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback,
}
void launchNetworkSetting() {
+ // Dismissing a dialog into its touch surface and starting an activity at the same time
+ // looks bad, so let's make sure the dialog just fades out quickly.
+ mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations();
mCallback.dismissDialog();
+
mActivityStarter.postStartActivityDismissingKeyguard(getSettingsIntent(), 0);
}
void launchWifiNetworkDetailsSetting(String key) {
Intent intent = getWifiDetailsSettingsIntent(key);
if (intent != null) {
+ // Dismissing a dialog into its touch surface and starting an activity at the same time
+ // looks bad, so let's make sure the dialog just fades out quickly.
+ mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations();
mCallback.dismissDialog();
+
mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
}
}
void launchWifiScanningSetting() {
+ // Dismissing a dialog into its touch surface and starting an activity at the same time
+ // looks bad, so let's make sure the dialog just fades out quickly.
+ mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations();
mCallback.dismissDialog();
+
final Intent intent = new Intent(ACTION_WIFI_SCANNING_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
@@ -788,6 +807,14 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback,
return false;
}
+ @WorkerThread
+ boolean isWifiScanEnabled() {
+ if (!mLocationController.isLocationEnabled()) {
+ return false;
+ }
+ return mWifiManager.isScanAlwaysAvailable();
+ }
+
static class WifiEntryConnectCallback implements WifiEntry.ConnectCallback {
final ActivityStarter mActivityStarter;
final WifiEntry mWifiEntry;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
index ea5df17bca58..79f7ac3aad3d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
@@ -18,9 +18,11 @@ package com.android.systemui.qs.tiles.dialog
import android.content.Context
import android.os.Handler
import android.util.Log
+import android.view.View
import com.android.internal.logging.UiEventLogger
+import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import java.util.concurrent.Executor
import javax.inject.Inject
@@ -37,14 +39,20 @@ class InternetDialogFactory @Inject constructor(
@Background private val executor: Executor,
private val internetDialogController: InternetDialogController,
private val context: Context,
- private val uiEventLogger: UiEventLogger
+ private val uiEventLogger: UiEventLogger,
+ private val dialogLaunchAnimator: DialogLaunchAnimator
) {
companion object {
var internetDialog: InternetDialog? = null
}
- /** Creates a [InternetDialog]. */
- fun create(aboveStatusBar: Boolean, canConfigMobileData: Boolean, canConfigWifi: Boolean) {
+ /** Creates a [InternetDialog]. The dialog will be animated from [view] if it is not null. */
+ fun create(
+ aboveStatusBar: Boolean,
+ canConfigMobileData: Boolean,
+ canConfigWifi: Boolean,
+ view: View?
+ ) {
if (internetDialog != null) {
if (DEBUG) {
Log.d(TAG, "InternetDialog is showing, do not create it twice.")
@@ -54,7 +62,12 @@ class InternetDialogFactory @Inject constructor(
internetDialog = InternetDialog(context, this, internetDialogController,
canConfigMobileData, canConfigWifi, aboveStatusBar, uiEventLogger, handler,
executor)
- internetDialog?.show()
+ if (view != null) {
+ dialogLaunchAnimator.showFromView(internetDialog!!, view,
+ animateBackgroundBoundsChange = true)
+ } else {
+ internetDialog?.show()
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt b/packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt
index 01afa56fc496..26d1bbde2a54 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/user/UserDialog.kt
@@ -71,10 +71,6 @@ class UserDialog(
setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL)
attributes.fitInsetsTypes = attributes.fitInsetsTypes or WindowInsets.Type.statusBars()
attributes.receiveInsetsIgnoringZOrder = true
- setLayout(
- context.resources.getDimensionPixelSize(R.dimen.notification_panel_width),
- ViewGroup.LayoutParams.WRAP_CONTENT
- )
setGravity(Gravity.CENTER)
}
setContentView(R.layout.qs_user_dialog_content)
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 721a6af37e21..fa874b19c2cc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;
@@ -24,6 +25,7 @@ import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_OVERVIEW;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_RECENT_TASKS;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
@@ -68,6 +70,7 @@ import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.accessibility.AccessibilityManager;
+import android.view.inputmethod.InputMethodManager;
import androidx.annotation.NonNull;
@@ -103,6 +106,7 @@ import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController;
+import com.android.wm.shell.recents.RecentTasks;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.transition.ShellTransitions;
@@ -156,6 +160,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
private final ShellTransitions mShellTransitions;
private final Optional<StartingSurface> mStartingSurface;
private final SmartspaceTransitionController mSmartspaceTransitionController;
+ private final Optional<RecentTasks> mRecentTasks;
private Region mActiveNavBarRegion;
@@ -237,6 +242,15 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
@Override
+ public void onImeSwitcherPressed() throws RemoteException {
+ // TODO(b/204901476) We're intentionally using DEFAULT_DISPLAY for now since
+ // Launcher/Taskbar isn't display aware.
+ mContext.getSystemService(InputMethodManager.class)
+ .showInputMethodPickerFromSystem(true /* showAuxiliarySubtypes */,
+ DEFAULT_DISPLAY);
+ }
+
+ @Override
public void setHomeRotationEnabled(boolean enabled) {
verifyCallerAndClearCallingIdentityPostMain("setHomeRotationEnabled", () ->
mHandler.post(() -> notifyHomeRotationEnabled(enabled)));
@@ -480,6 +494,9 @@ public class OverviewProxyService extends CurrentUserTracker implements
params.putBinder(
KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER,
mSmartspaceTransitionController.createExternalInterface().asBinder());
+ mRecentTasks.ifPresent(recentTasks -> params.putBinder(
+ KEY_EXTRA_RECENT_TASKS,
+ recentTasks.createExternalInterface().asBinder()));
try {
mOverviewProxy.onInitialize(params);
@@ -530,17 +547,18 @@ public class OverviewProxyService extends CurrentUserTracker implements
@Inject
public OverviewProxyService(Context context, CommandQueue commandQueue,
Lazy<NavigationBarController> navBarControllerLazy,
+ Lazy<Optional<StatusBar>> statusBarOptionalLazy,
NavigationModeController navModeController,
NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
Optional<Pip> pipOptional,
Optional<LegacySplitScreen> legacySplitScreenOptional,
Optional<SplitScreen> splitScreenOptional,
- Lazy<Optional<StatusBar>> statusBarOptionalLazy,
Optional<OneHanded> oneHandedOptional,
+ Optional<RecentTasks> recentTasks,
+ Optional<StartingSurface> startingSurface,
BroadcastDispatcher broadcastDispatcher,
ShellTransitions shellTransitions,
ScreenLifecycle screenLifecycle,
- Optional<StartingSurface> startingSurface,
SmartspaceTransitionController smartspaceTransitionController,
DumpManager dumpManager) {
super(broadcastDispatcher);
@@ -562,6 +580,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
mSysUiState.addCallback(this::notifySystemUiStateFlags);
mOneHandedOptional = oneHandedOptional;
mShellTransitions = shellTransitions;
+ mRecentTasks = recentTasks;
// Assumes device always starts with back button until launcher tells it that it does not
mNavBarButtonAlpha = 1.0f;
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
index 060d7b1a8ab8..1a08878cecfe 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
@@ -18,7 +18,6 @@ package com.android.systemui.screenrecord;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -27,10 +26,12 @@ import android.os.UserHandle;
import android.util.Log;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.policy.CallbackController;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -44,15 +45,13 @@ import javax.inject.Inject;
public class RecordingController
implements CallbackController<RecordingController.RecordingStateChangeCallback> {
private static final String TAG = "RecordingController";
- private static final String SYSUI_PACKAGE = "com.android.systemui";
- private static final String SYSUI_SCREENRECORD_LAUNCHER =
- "com.android.systemui.screenrecord.ScreenRecordDialog";
private boolean mIsStarting;
private boolean mIsRecording;
private PendingIntent mStopIntent;
private CountDownTimer mCountDownTimer = null;
private BroadcastDispatcher mBroadcastDispatcher;
+ private UserContextProvider mUserContextProvider;
protected static final String INTENT_UPDATE_STATE =
"com.android.systemui.screenrecord.UPDATE_STATE";
@@ -88,20 +87,16 @@ public class RecordingController
* Create a new RecordingController
*/
@Inject
- public RecordingController(BroadcastDispatcher broadcastDispatcher) {
+ public RecordingController(BroadcastDispatcher broadcastDispatcher,
+ UserContextProvider userContextProvider) {
mBroadcastDispatcher = broadcastDispatcher;
+ mUserContextProvider = userContextProvider;
}
- /**
- * Get an intent to show screen recording options to the user.
- */
- public Intent getPromptIntent() {
- final ComponentName launcherComponent = new ComponentName(SYSUI_PACKAGE,
- SYSUI_SCREENRECORD_LAUNCHER);
- final Intent intent = new Intent();
- intent.setComponent(launcherComponent);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- return intent;
+ /** Create a dialog to show screen recording options to the user. */
+ public ScreenRecordDialog createScreenRecordDialog(Context context,
+ @Nullable Runnable onStartRecordingClicked) {
+ return new ScreenRecordDialog(context, this, mUserContextProvider, onStartRecordingClicked);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
index df766f3625e4..1fb88dfe9b52 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
@@ -26,7 +26,6 @@ import android.app.PendingIntent;
import android.content.Context;
import android.os.Bundle;
import android.view.Gravity;
-import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ArrayAdapter;
@@ -34,34 +33,38 @@ import android.widget.Spinner;
import android.widget.Switch;
import android.widget.TextView;
+import androidx.annotation.Nullable;
+
import com.android.systemui.R;
import com.android.systemui.settings.UserContextProvider;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
-import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
-import javax.inject.Inject;
-
/**
- * Activity to select screen recording options
+ * Dialog to select screen recording options
*/
-public class ScreenRecordDialog extends Activity {
+public class ScreenRecordDialog extends SystemUIDialog {
+ private static final List<ScreenRecordingAudioSource> MODES = Arrays.asList(INTERNAL, MIC,
+ MIC_AND_INTERNAL);
private static final long DELAY_MS = 3000;
private static final long INTERVAL_MS = 1000;
- private static final String TAG = "ScreenRecordDialog";
private final RecordingController mController;
private final UserContextProvider mUserContextProvider;
+ @Nullable
+ private final Runnable mOnStartRecordingClicked;
private Switch mTapsSwitch;
private Switch mAudioSwitch;
private Spinner mOptions;
- private List<ScreenRecordingAudioSource> mModes;
- @Inject
- public ScreenRecordDialog(RecordingController controller,
- UserContextProvider userContextProvider) {
+ public ScreenRecordDialog(Context context, RecordingController controller,
+ UserContextProvider userContextProvider, @Nullable Runnable onStartRecordingClicked) {
+ super(context);
mController = controller;
mUserContextProvider = userContextProvider;
+ mOnStartRecordingClicked = onStartRecordingClicked;
}
@Override
@@ -69,37 +72,35 @@ public class ScreenRecordDialog extends Activity {
super.onCreate(savedInstanceState);
Window window = getWindow();
- // Inflate the decor view, so the attributes below are not overwritten by the theme.
- window.getDecorView();
- window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+
window.addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS);
- window.setGravity(Gravity.TOP);
+
+ window.setGravity(Gravity.CENTER);
setTitle(R.string.screenrecord_name);
setContentView(R.layout.screen_record_dialog);
TextView cancelBtn = findViewById(R.id.button_cancel);
- cancelBtn.setOnClickListener(v -> {
- finish();
- });
+ cancelBtn.setOnClickListener(v -> dismiss());
TextView startBtn = findViewById(R.id.button_start);
startBtn.setOnClickListener(v -> {
+ if (mOnStartRecordingClicked != null) {
+ // Note that it is important to run this callback before dismissing, so that the
+ // callback can disable the dialog exit animation if it wants to.
+ mOnStartRecordingClicked.run();
+ }
+
requestScreenCapture();
- finish();
+ dismiss();
});
- mModes = new ArrayList<>();
- mModes.add(INTERNAL);
- mModes.add(MIC);
- mModes.add(MIC_AND_INTERNAL);
-
mAudioSwitch = findViewById(R.id.screenrecord_audio_switch);
mTapsSwitch = findViewById(R.id.screenrecord_taps_switch);
mOptions = findViewById(R.id.screen_recording_options);
- ArrayAdapter a = new ScreenRecordingAdapter(getApplicationContext(),
+ ArrayAdapter a = new ScreenRecordingAdapter(getContext().getApplicationContext(),
android.R.layout.simple_spinner_dropdown_item,
- mModes);
+ MODES);
a.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mOptions.setAdapter(a);
mOptions.setOnItemClickListenerInt((parent, view, position, id) -> {
@@ -116,7 +117,7 @@ public class ScreenRecordDialog extends Activity {
PendingIntent startIntent = PendingIntent.getForegroundService(userContext,
RecordingService.REQUEST_CODE,
RecordingService.getStartIntent(
- userContext, RESULT_OK,
+ userContext, Activity.RESULT_OK,
audioMode.ordinal(), showTaps),
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
PendingIntent stopIntent = PendingIntent.getService(userContext,
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 5b4db1449b34..44b45401ad77 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -266,6 +266,7 @@ public class ScreenshotController {
private Animator mScreenshotAnimation;
private RequestCallback mCurrentRequestCallback;
+ private String mPackageName = "";
private final Handler mScreenshotHandler = new Handler(Looper.getMainLooper()) {
@Override
@@ -275,7 +276,8 @@ public class ScreenshotController {
if (DEBUG_UI) {
Log.d(TAG, "Corner timeout hit");
}
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_INTERACTION_TIMEOUT);
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_INTERACTION_TIMEOUT, 0,
+ mPackageName);
ScreenshotController.this.dismissScreenshot(false);
break;
default:
@@ -354,12 +356,13 @@ public class ScreenshotController {
mCameraSound.load(MediaActionSound.SHUTTER_CLICK);
}
- void takeScreenshotFullscreen(Consumer<Uri> finisher, RequestCallback requestCallback) {
+ void takeScreenshotFullscreen(ComponentName topComponent, Consumer<Uri> finisher,
+ RequestCallback requestCallback) {
mCurrentRequestCallback = requestCallback;
DisplayMetrics displayMetrics = new DisplayMetrics();
getDefaultDisplay().getRealMetrics(displayMetrics);
takeScreenshotInternal(
- finisher,
+ topComponent, finisher,
new Rect(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels));
}
@@ -383,13 +386,15 @@ public class ScreenshotController {
screenshotScreenBounds.set(0, 0, screenshot.getWidth(), screenshot.getHeight());
}
mCurrentRequestCallback = requestCallback;
- saveScreenshot(screenshot, finisher, screenshotScreenBounds, visibleInsets, showFlash);
+ saveScreenshot(screenshot, finisher, screenshotScreenBounds, visibleInsets, topComponent,
+ showFlash);
}
/**
* Displays a screenshot selector
*/
- void takeScreenshotPartial(final Consumer<Uri> finisher, RequestCallback requestCallback) {
+ void takeScreenshotPartial(ComponentName topComponent,
+ final Consumer<Uri> finisher, RequestCallback requestCallback) {
mScreenshotView.reset();
mCurrentRequestCallback = requestCallback;
@@ -398,7 +403,7 @@ public class ScreenshotController {
mScreenshotView.requestApplyInsets();
mScreenshotView.takePartialScreenshot(
- rect -> takeScreenshotInternal(finisher, rect));
+ rect -> takeScreenshotInternal(topComponent, finisher, rect));
}
/**
@@ -491,7 +496,8 @@ public class ScreenshotController {
/**
* Takes a screenshot of the current display and shows an animation.
*/
- private void takeScreenshotInternal(Consumer<Uri> finisher, Rect crop) {
+ private void takeScreenshotInternal(ComponentName topComponent, Consumer<Uri> finisher,
+ Rect crop) {
mScreenshotTakenInPortrait =
mContext.getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT;
@@ -509,7 +515,7 @@ public class ScreenshotController {
return;
}
- saveScreenshot(screenshot, finisher, screenRect, Insets.NONE, true);
+ saveScreenshot(screenshot, finisher, screenRect, Insets.NONE, topComponent, true);
}
private Bitmap captureScreenshot(Rect crop) {
@@ -539,7 +545,7 @@ public class ScreenshotController {
}
private void saveScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect,
- Insets screenInsets, boolean showFlash) {
+ Insets screenInsets, ComponentName topComponent, boolean showFlash) {
if (mAccessibilityManager.isEnabled()) {
AccessibilityEvent event =
new AccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
@@ -552,7 +558,7 @@ public class ScreenshotController {
if (mScreenshotView.isAttachedToWindow()) {
// if we didn't already dismiss for another reason
if (!mScreenshotView.isDismissing()) {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_REENTERED);
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_REENTERED, 0, mPackageName);
}
if (DEBUG_WINDOW) {
Log.d(TAG, "saveScreenshot: screenshotView is already attached, resetting. "
@@ -560,6 +566,8 @@ public class ScreenshotController {
}
mScreenshotView.reset();
}
+ mPackageName = topComponent == null ? "" : topComponent.getPackageName();
+ mScreenshotView.setPackageName(mPackageName);
mScreenshotView.updateOrientation(
mWindowManager.getCurrentWindowMetrics().getWindowInsets());
@@ -772,6 +780,10 @@ public class ScreenshotController {
}
mWindowManager.removeViewImmediate(decorView);
}
+ // Ensure that we remove the input monitor
+ if (mScreenshotView != null) {
+ mScreenshotView.stopInputListening();
+ }
}
/**
@@ -790,11 +802,11 @@ public class ScreenshotController {
}
finisher.accept(imageData.uri);
if (imageData.uri == null) {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED);
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED, 0, mPackageName);
mNotificationsController.notifyScreenshotError(
R.string.screenshot_failed_to_save_text);
} else {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED);
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED, 0, mPackageName);
mScreenshotHandler.post(() -> Toast.makeText(mContext,
R.string.screenshot_saved_title, Toast.LENGTH_SHORT).show());
}
@@ -959,11 +971,11 @@ public class ScreenshotController {
*/
private void logSuccessOnActionsReady(ScreenshotController.SavedImageData imageData) {
if (imageData.uri == null) {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED);
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED, 0, mPackageName);
mNotificationsController.notifyScreenshotError(
R.string.screenshot_failed_to_save_text);
} else {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED);
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED, 0, mPackageName);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 7222b0313fb4..ca63ec269bf4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -163,6 +163,7 @@ public class ScreenshotView extends FrameLayout implements
private SwipeDismissHandler mSwipeDismissHandler;
private InputMonitorCompat mInputMonitor;
private boolean mShowScrollablePreview;
+ private String mPackageName = "";
private final ArrayList<ScreenshotActionChip> mSmartChips = new ArrayList<>();
private PendingInteraction mPendingInteraction;
@@ -314,7 +315,7 @@ public class ScreenshotView extends FrameLayout implements
});
}
- private void stopInputListening() {
+ void stopInputListening() {
if (mInputMonitor != null) {
mInputMonitor.dispose();
mInputMonitor = null;
@@ -409,6 +410,10 @@ public class ScreenshotView extends FrameLayout implements
mScreenshotPreview.setImageDrawable(createScreenDrawable(mResources, bitmap, screenInsets));
}
+ void setPackageName(String packageName) {
+ mPackageName = packageName;
+ }
+
void updateInsets(WindowInsets insets) {
int orientation = mContext.getResources().getConfiguration().orientation;
mOrientationPortrait = (orientation == ORIENTATION_PORTRAIT);
@@ -585,7 +590,8 @@ public class ScreenshotView extends FrameLayout implements
if (DEBUG_INPUT) {
Log.d(TAG, "dismiss button clicked");
}
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EXPLICIT_DISMISSAL);
+ mUiEventLogger.log(
+ ScreenshotEvent.SCREENSHOT_EXPLICIT_DISMISSAL, 0, mPackageName);
animateDismissal();
});
mDismissButton.setAlpha(1);
@@ -621,7 +627,7 @@ public class ScreenshotView extends FrameLayout implements
ArrayList<ScreenshotActionChip> chips = new ArrayList<>();
- mShareChip.setContentDescription(mContext.getString(com.android.internal.R.string.share));
+ mShareChip.setContentDescription(mContext.getString(R.string.screenshot_share_description));
mShareChip.setIcon(Icon.createWithResource(mContext, R.drawable.ic_screenshot_share), true);
mShareChip.setOnClickListener(v -> {
mShareChip.setIsPending(true);
@@ -633,7 +639,7 @@ public class ScreenshotView extends FrameLayout implements
});
chips.add(mShareChip);
- mEditChip.setContentDescription(mContext.getString(R.string.screenshot_edit_label));
+ mEditChip.setContentDescription(mContext.getString(R.string.screenshot_edit_description));
mEditChip.setIcon(Icon.createWithResource(mContext, R.drawable.ic_screenshot_edit), true);
mEditChip.setOnClickListener(v -> {
mEditChip.setIsPending(true);
@@ -698,24 +704,25 @@ public class ScreenshotView extends FrameLayout implements
void setChipIntents(ScreenshotController.SavedImageData imageData) {
mShareChip.setOnClickListener(v -> {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SHARE_TAPPED);
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SHARE_TAPPED, 0, mPackageName);
startSharedTransition(
imageData.shareTransition.get());
});
mEditChip.setOnClickListener(v -> {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EDIT_TAPPED);
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EDIT_TAPPED, 0, mPackageName);
startSharedTransition(
imageData.editTransition.get());
});
mScreenshotPreview.setOnClickListener(v -> {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED);
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED, 0, mPackageName);
startSharedTransition(
imageData.editTransition.get());
});
if (mQuickShareChip != null) {
mQuickShareChip.setPendingIntent(imageData.quickShareAction.actionIntent,
() -> {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED);
+ mUiEventLogger.log(
+ ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED, 0, mPackageName);
animateDismissal();
});
}
@@ -745,7 +752,8 @@ public class ScreenshotView extends FrameLayout implements
actionChip.setIcon(smartAction.getIcon(), false);
actionChip.setPendingIntent(smartAction.actionIntent,
() -> {
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED);
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED,
+ 0, mPackageName);
animateDismissal();
});
actionChip.setAlpha(1);
@@ -1121,7 +1129,7 @@ public class ScreenshotView extends FrameLayout implements
if (DEBUG_INPUT) {
Log.d(TAG, "dismiss triggered via swipe gesture");
}
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SWIPE_DISMISSED);
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SWIPE_DISMISSED, 0, mPackageName);
animateDismissal(createSwipeDismissAnimation());
} else {
// if we've moved, but not past the threshold, start the return animation
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index daa9d099de86..f380911b6403 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -186,20 +186,22 @@ public class TakeScreenshotService extends Service {
ScreenshotHelper.ScreenshotRequest screenshotRequest =
(ScreenshotHelper.ScreenshotRequest) msg.obj;
- mUiEventLogger.log(ScreenshotEvent.getScreenshotSource(screenshotRequest.getSource()));
+ ComponentName topComponent = screenshotRequest.getTopComponent();
+ mUiEventLogger.log(ScreenshotEvent.getScreenshotSource(screenshotRequest.getSource()), 0,
+ topComponent == null ? "" : topComponent.getPackageName());
switch (msg.what) {
case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
if (DEBUG_SERVICE) {
Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_FULLSCREEN");
}
- mScreenshot.takeScreenshotFullscreen(uriConsumer, requestCallback);
+ mScreenshot.takeScreenshotFullscreen(topComponent, uriConsumer, requestCallback);
break;
case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:
if (DEBUG_SERVICE) {
Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_SELECTED_REGION");
}
- mScreenshot.takeScreenshotPartial(uriConsumer, requestCallback);
+ mScreenshot.takeScreenshotPartial(topComponent, uriConsumer, requestCallback);
break;
case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE:
if (DEBUG_SERVICE) {
@@ -211,7 +213,6 @@ public class TakeScreenshotService extends Service {
Insets insets = screenshotRequest.getInsets();
int taskId = screenshotRequest.getTaskId();
int userId = screenshotRequest.getUserId();
- ComponentName topComponent = screenshotRequest.getTopComponent();
if (screenshot == null) {
Log.e(TAG, "Got null bitmap from screenshot message");
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 acc6ee130539..d7d1de00c82d 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
@@ -51,8 +51,6 @@ import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
-import java.util.ArrayList;
-
import javax.inject.Inject;
public class BrightnessController implements ToggleSlider.Listener, MirroredBrightnessController {
@@ -92,13 +90,9 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig
@Override
public void onDisplayChanged(int displayId) {
mBackgroundHandler.post(mUpdateSliderRunnable);
- notifyCallbacks();
}
};
- private ArrayList<BrightnessStateChangeCallback> mChangeCallbacks =
- new ArrayList<BrightnessStateChangeCallback>();
-
private volatile boolean mAutomatic; // Brightness adjusted automatically using ambient light.
private volatile boolean mIsVrModeEnabled;
private boolean mListening;
@@ -114,11 +108,6 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig
mControl.setMirrorControllerAndMirror(controller);
}
- public interface BrightnessStateChangeCallback {
- /** Indicates that some of the brightness settings have changed */
- void onBrightnessLevelChanged();
- }
-
/** ContentObserver to watch brightness */
private class BrightnessObserver extends ContentObserver {
@@ -139,7 +128,6 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig
mBackgroundHandler.post(mUpdateModeRunnable);
mBackgroundHandler.post(mUpdateSliderRunnable);
}
- notifyCallbacks();
}
public void startObserving() {
@@ -317,14 +305,6 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig
Context.VR_SERVICE));
}
- public void addStateChangedCallback(BrightnessStateChangeCallback cb) {
- mChangeCallbacks.add(cb);
- }
-
- public boolean removeStateChangedCallback(BrightnessStateChangeCallback cb) {
- return mChangeCallbacks.remove(cb);
- }
-
public void registerCallbacks() {
mBackgroundHandler.post(mStartListeningRunnable);
}
@@ -375,10 +355,6 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig
}
});
}
-
- for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
- cb.onBrightnessLevelChanged();
- }
}
public void checkRestrictionAndSetEnabled() {
@@ -435,8 +411,12 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig
}
private void animateSliderTo(int target) {
- if (!mControlValueInitialized) {
+ if (!mControlValueInitialized || !mControl.isVisible()) {
// Don't animate the first value since its default state isn't meaningful to users.
+ // We also don't want to animate slider if it's not visible - especially important when
+ // two sliders are active at the same time in split shade (one in QS and one in QQS),
+ // as this negatively affects transition between them and they share mirror slider -
+ // animating it from two different sources causes janky motion
mControl.setValue(target);
mControlValueInitialized = true;
}
@@ -455,13 +435,6 @@ public class BrightnessController implements ToggleSlider.Listener, MirroredBrig
mSliderAnimator.start();
}
- private void notifyCallbacks() {
- final int size = mChangeCallbacks.size();
- for (int i = 0; i < size; i++) {
- mChangeCallbacks.get(i).onBrightnessLevelChanged();
- }
- }
-
/** Factory for creating a {@link BrightnessController}. */
public static class Factory {
private final Context mContext;
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 8fc831a7ce4d..c9c1a9b55c3f 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
@@ -41,14 +41,14 @@ import javax.inject.Inject;
public class BrightnessDialog extends Activity {
private BrightnessController mBrightnessController;
- private final BrightnessSlider.Factory mToggleSliderFactory;
+ private final BrightnessSliderController.Factory mToggleSliderFactory;
private final BroadcastDispatcher mBroadcastDispatcher;
private final Handler mBackgroundHandler;
@Inject
public BrightnessDialog(
BroadcastDispatcher broadcastDispatcher,
- BrightnessSlider.Factory factory,
+ BrightnessSliderController.Factory factory,
@Background Handler bgHandler) {
mBroadcastDispatcher = broadcastDispatcher;
mToggleSliderFactory = factory;
@@ -77,7 +77,7 @@ public class BrightnessDialog extends Activity {
// The brightness mirror container is INVISIBLE by default.
frame.setVisibility(View.VISIBLE);
- BrightnessSlider controller = mToggleSliderFactory.create(this, frame);
+ BrightnessSliderController controller = mToggleSliderFactory.create(this, frame);
controller.init();
frame.addView(controller.getRootView(), MATCH_PARENT, WRAP_CONTENT);
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
index b0e320ad1e2f..6c8190af27f7 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
@@ -44,7 +44,8 @@ import javax.inject.Inject;
*
* @see BrightnessMirrorController
*/
-public class BrightnessSlider extends ViewController<BrightnessSliderView> implements ToggleSlider {
+public class BrightnessSliderController extends ViewController<BrightnessSliderView> implements
+ ToggleSlider {
private Listener mListener;
private ToggleSlider mMirror;
@@ -69,7 +70,7 @@ public class BrightnessSlider extends ViewController<BrightnessSliderView> imple
}
};
- BrightnessSlider(
+ BrightnessSliderController(
BrightnessSliderView brightnessSliderView,
FalsingManager falsingManager) {
super(brightnessSliderView);
@@ -184,6 +185,15 @@ public class BrightnessSlider extends ViewController<BrightnessSliderView> imple
mView.setVisibility(View.VISIBLE);
}
+ @Override
+ public boolean isVisible() {
+ // this should be called rarely - once or twice per slider's value change, but not for
+ // every value change when user slides finger - only the final one.
+ // If view is not visible this call is quick (around 50 µs) as it sees parent is not visible
+ // otherwise it's slightly longer (70 µs) because there are more checks to be done
+ return mView.isVisibleToUser();
+ }
+
private final SeekBar.OnSeekBarChangeListener mSeekListener =
new SeekBar.OnSeekBarChangeListener() {
@Override
@@ -222,7 +232,7 @@ public class BrightnessSlider extends ViewController<BrightnessSliderView> imple
};
/**
- * Creates a {@link BrightnessSlider} with its associated view.
+ * Creates a {@link BrightnessSliderController} with its associated view.
*/
public static class Factory {
@@ -240,11 +250,11 @@ public class BrightnessSlider extends ViewController<BrightnessSliderView> imple
* @param viewRoot the {@link ViewGroup} that will contain the hierarchy. The inflated
* hierarchy will not be attached
*/
- public BrightnessSlider create(Context context, @Nullable ViewGroup viewRoot) {
+ public BrightnessSliderController create(Context context, @Nullable ViewGroup viewRoot) {
int layout = getLayout();
BrightnessSliderView root = (BrightnessSliderView) LayoutInflater.from(context)
.inflate(layout, viewRoot, false);
- return new BrightnessSlider(root, mFalsingManager);
+ return new BrightnessSliderController(root, mFalsingManager);
}
/** Get the layout to inflate based on what slider to use */
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java
index 15aa2b730adf..0e037ad56257 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java
@@ -60,6 +60,7 @@ public class BrightnessSliderView extends FrameLayout {
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ setLayerType(LAYER_TYPE_HARDWARE, null);
mSlider = requireViewById(R.id.slider);
mSlider.setAccessibilityLabel(getContentDescription().toString());
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 5de22d43a21b..648e33b1d228 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSlider.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSlider.java
@@ -38,4 +38,5 @@ public interface ToggleSlider {
void showView();
void hideView();
+ boolean isVisible();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
index cfbe3b29783a..cf2328f5af97 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
@@ -80,22 +80,23 @@ open class BlurUtils @Inject constructor(
* @param opaque if surface is opaque, regardless or having blurs or no.
*/
fun applyBlur(viewRootImpl: ViewRootImpl?, radius: Int, opaque: Boolean) {
- if (viewRootImpl == null || !viewRootImpl.surfaceControl.isValid ||
- !supportsBlursOnWindows()) {
+ if (viewRootImpl == null || !viewRootImpl.surfaceControl.isValid) {
return
}
createTransaction().use {
- it.setBackgroundBlurRadius(viewRootImpl.surfaceControl, radius)
- it.setOpaque(viewRootImpl.surfaceControl, opaque)
- if (lastAppliedBlur == 0 && radius != 0) {
- it.setEarlyWakeupStart()
- }
- if (lastAppliedBlur != 0 && radius == 0) {
- it.setEarlyWakeupEnd()
+ if (supportsBlursOnWindows()) {
+ it.setBackgroundBlurRadius(viewRootImpl.surfaceControl, radius)
+ if (lastAppliedBlur == 0 && radius != 0) {
+ it.setEarlyWakeupStart()
+ }
+ if (lastAppliedBlur != 0 && radius == 0) {
+ it.setEarlyWakeupEnd()
+ }
+ lastAppliedBlur = radius
}
+ it.setOpaque(viewRootImpl.surfaceControl, opaque)
it.apply()
}
- lastAppliedBlur = radius
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DisableFlagsLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/DisableFlagsLogger.kt
index cf34db233b06..4272bb14ff3a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DisableFlagsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DisableFlagsLogger.kt
@@ -85,24 +85,30 @@ class DisableFlagsLogger constructor(
* is no difference. the new-after-modification state also won't be included if there's no
* difference from the new state.
*
- * @param old the disable state that had been previously sent.
+ * @param old the disable state that had been previously sent. Null if we don't need to log the
+ * previously sent state.
* @param new the new disable state that has just been sent.
* @param newAfterLocalModification the new disable states after a class has locally modified
* them. Null if the class does not locally modify.
*/
fun getDisableFlagsString(
- old: DisableState,
+ old: DisableState? = null,
new: DisableState,
newAfterLocalModification: DisableState? = null
): String {
val builder = StringBuilder("Received new disable state. ")
- builder.append("Old: ")
- builder.append(getFlagsString(old))
- builder.append(" | New: ")
- if (old != new) {
+
+ old?.let {
+ builder.append("Old: ")
+ builder.append(getFlagsString(old))
+ builder.append(" | ")
+ }
+
+ builder.append("New: ")
+ if (old != null && old != new) {
builder.append(getFlagsStringWithDiff(old, new))
} else {
- builder.append(getFlagsString(old))
+ builder.append(getFlagsString(new))
}
if (newAfterLocalModification != null && new != newAfterLocalModification) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 74ebfe5ad5e4..ed36a27fcb35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -818,7 +818,7 @@ public class KeyguardIndicationController {
}
private void showTryFingerprintMsg(int msgId, String a11yString) {
- if (mKeyguardUpdateMonitor.isUdfpsAvailable()) {
+ if (mKeyguardUpdateMonitor.isUdfpsSupported()) {
// if udfps available, there will always be a tappable affordance to unlock
// For example, the lock icon
if (mKeyguardBypassController.getUserHasDeviceEntryIntent()) {
@@ -912,7 +912,11 @@ public class KeyguardIndicationController {
} else if (mKeyguardUpdateMonitor.isScreenOn()) {
if (biometricSourceType == BiometricSourceType.FACE
&& shouldSuppressFaceMsgAndShowTryFingerprintMsg()) {
- showTryFingerprintMsg(msgId, helpString);
+ // don't show any help messages, b/c they can come in right before a success
+ // However, continue to announce help messages for a11y
+ if (!TextUtils.isEmpty(helpString)) {
+ mLockScreenIndicationView.announceForAccessibility(helpString);
+ }
return;
}
showTransientIndication(helpString, false /* isError */, showActionToUnlock);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index 77e329f94a36..03d8e7e03c0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -208,11 +208,6 @@ class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context,
lateinit var isScrimOpaqueChangedListener: Consumer<Boolean>
/**
- * A runnable to call when the scrim has been fully revealed. This is only invoked once
- */
- var fullyRevealedRunnable: Runnable? = null
-
- /**
* How much of the underlying views are revealed, in percent. 0 means they will be completely
* obscured and 1 means they'll be fully visible.
*/
@@ -223,20 +218,10 @@ class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context,
revealEffect.setRevealAmountOnScrim(value, this)
updateScrimOpaque()
- maybeTriggerFullyRevealedRunnable()
invalidate()
}
}
- private fun maybeTriggerFullyRevealedRunnable() {
- if (revealAmount == 1.0f) {
- fullyRevealedRunnable?.let {
- it.run()
- fullyRevealedRunnable = null
- }
- }
- }
-
/**
* The [LightRevealEffect] used to manipulate the radial gradient whenever [revealAmount]
* changes.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index db7d5c113031..856052e1a4d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -19,8 +19,8 @@ import static android.app.Notification.VISIBILITY_SECRET;
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
import static com.android.systemui.DejankUtils.whitelistIpcs;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_MEDIA_CONTROLS;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_MEDIA_CONTROLS;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
import android.app.ActivityManager;
import android.app.KeyguardManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 18a3d86589da..1ce7f0350019 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -15,21 +15,16 @@
*/
package com.android.systemui.statusbar;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.RemoteInput;
-import android.app.RemoteInputHistoryItem;
import android.content.Context;
import android.content.Intent;
import android.content.pm.UserInfo;
-import android.net.Uri;
import android.os.Handler;
-import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -48,6 +43,9 @@ import android.widget.RemoteViews;
import android.widget.RemoteViews.InteractionHandler;
import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
@@ -55,6 +53,7 @@ import com.android.systemui.Dumpable;
import com.android.systemui.R;
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.statusbar.dagger.StatusBarDependenciesModule;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
@@ -70,12 +69,10 @@ import com.android.systemui.statusbar.policy.RemoteInputView;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
-import java.util.stream.Stream;
import dagger.Lazy;
@@ -93,27 +90,7 @@ public class NotificationRemoteInputManager implements Dumpable {
private static final boolean DEBUG = false;
private static final String TAG = "NotifRemoteInputManager";
- /**
- * How long to wait before auto-dismissing a notification that was kept for remote input, and
- * has now sent a remote input. We auto-dismiss, because the app may not see a reason to cancel
- * these given that they technically don't exist anymore. We wait a bit in case the app issues
- * an update.
- */
- private static final int REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY = 200;
-
- /**
- * Notifications that are already removed but are kept around because we want to show the
- * remote input history. See {@link RemoteInputHistoryExtender} and
- * {@link SmartReplyHistoryExtender}.
- */
- protected final ArraySet<String> mKeysKeptForRemoteInputHistory = new ArraySet<>();
-
- /**
- * Notifications that are already removed but are kept around because the remote input is
- * actively being used (i.e. user is typing in it). See {@link RemoteInputActiveExtender}.
- */
- protected final ArraySet<NotificationEntry> mEntriesKeptForRemoteInputActive =
- new ArraySet<>();
+ private RemoteInputListener mRemoteInputListener;
// Dependencies:
private final NotificationLockscreenUserManager mLockscreenUserManager;
@@ -125,18 +102,17 @@ public class NotificationRemoteInputManager implements Dumpable {
private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy;
protected final Context mContext;
+ protected final FeatureFlags mFeatureFlags;
private final UserManager mUserManager;
private final KeyguardManager mKeyguardManager;
+ private final RemoteInputNotificationRebuilder mRebuilder;
private final StatusBarStateController mStatusBarStateController;
private final RemoteInputUriController mRemoteInputUriController;
private final NotificationClickNotifier mClickNotifier;
protected RemoteInputController mRemoteInputController;
- protected NotificationLifetimeExtender.NotificationSafeToRemoveCallback
- mNotificationLifetimeFinishedCallback;
protected IStatusBarService mBarService;
protected Callback mCallback;
- protected final ArrayList<NotificationLifetimeExtender> mLifetimeExtenders = new ArrayList<>();
private final List<RemoteInputController.Callback> mControllerCallbacks = new ArrayList<>();
@@ -226,6 +202,7 @@ public class NotificationRemoteInputManager implements Dumpable {
ViewGroup actionGroup = (ViewGroup) parent;
buttonIndex = actionGroup.indexOfChild(view);
}
+ // TODO(b/204183781): get this from the current pipeline
final int count = mEntryManager.getActiveNotificationsCount();
final int rank = entry.getRanking().getRank();
@@ -283,9 +260,11 @@ public class NotificationRemoteInputManager implements Dumpable {
*/
public NotificationRemoteInputManager(
Context context,
+ FeatureFlags featureFlags,
NotificationLockscreenUserManager lockscreenUserManager,
SmartReplyController smartReplyController,
NotificationEntryManager notificationEntryManager,
+ RemoteInputNotificationRebuilder rebuilder,
Lazy<Optional<StatusBar>> statusBarOptionalLazy,
StatusBarStateController statusBarStateController,
@Main Handler mainHandler,
@@ -294,6 +273,7 @@ public class NotificationRemoteInputManager implements Dumpable {
ActionClickLogger logger,
DumpManager dumpManager) {
mContext = context;
+ mFeatureFlags = featureFlags;
mLockscreenUserManager = lockscreenUserManager;
mSmartReplyController = smartReplyController;
mEntryManager = notificationEntryManager;
@@ -303,7 +283,11 @@ public class NotificationRemoteInputManager implements Dumpable {
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- addLifetimeExtenders();
+ mRebuilder = rebuilder;
+ if (!featureFlags.isNewNotifPipelineRenderingEnabled()) {
+ mRemoteInputListener = createLegacyRemoteInputLifetimeExtender(mainHandler,
+ notificationEntryManager, smartReplyController);
+ }
mKeyguardManager = context.getSystemService(KeyguardManager.class);
mStatusBarStateController = statusBarStateController;
mRemoteInputUriController = remoteInputUriController;
@@ -335,10 +319,35 @@ public class NotificationRemoteInputManager implements Dumpable {
});
}
+ /** Add a listener for various remote input events. Works with NEW pipeline only. */
+ public void setRemoteInputListener(@NonNull RemoteInputListener remoteInputListener) {
+ if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+ if (mRemoteInputListener != null) {
+ throw new IllegalStateException("mRemoteInputListener is already set");
+ }
+ mRemoteInputListener = remoteInputListener;
+ if (mRemoteInputController != null) {
+ mRemoteInputListener.setRemoteInputController(mRemoteInputController);
+ }
+ }
+ }
+
+ @NonNull
+ @VisibleForTesting
+ protected LegacyRemoteInputLifetimeExtender createLegacyRemoteInputLifetimeExtender(
+ Handler mainHandler,
+ NotificationEntryManager notificationEntryManager,
+ SmartReplyController smartReplyController) {
+ return new LegacyRemoteInputLifetimeExtender();
+ }
+
/** Initializes this component with the provided dependencies. */
public void setUpWithCallback(Callback callback, RemoteInputController.Delegate delegate) {
mCallback = callback;
mRemoteInputController = new RemoteInputController(delegate, mRemoteInputUriController);
+ if (mRemoteInputListener != null) {
+ mRemoteInputListener.setRemoteInputController(mRemoteInputController);
+ }
// Register all stored callbacks from before the Controller was initialized.
for (RemoteInputController.Callback cb : mControllerCallbacks) {
mRemoteInputController.addCallback(cb);
@@ -347,19 +356,8 @@ public class NotificationRemoteInputManager implements Dumpable {
mRemoteInputController.addCallback(new RemoteInputController.Callback() {
@Override
public void onRemoteInputSent(NotificationEntry entry) {
- if (FORCE_REMOTE_INPUT_HISTORY
- && isNotificationKeptForRemoteInputHistory(entry.getKey())) {
- mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.getKey());
- } else if (mEntriesKeptForRemoteInputActive.contains(entry)) {
- // We're currently holding onto this notification, but from the apps point of
- // view it is already canceled, so we'll need to cancel it on the apps behalf
- // after sending - unless the app posts an update in the mean time, so wait a
- // bit.
- mMainHandler.postDelayed(() -> {
- if (mEntriesKeptForRemoteInputActive.remove(entry)) {
- mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.getKey());
- }
- }, REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY);
+ if (mRemoteInputListener != null) {
+ mRemoteInputListener.onRemoteInputSent(entry);
}
try {
mBarService.onNotificationDirectReplied(entry.getSbn().getKey());
@@ -381,12 +379,12 @@ public class NotificationRemoteInputManager implements Dumpable {
}
}
});
- mSmartReplyController.setCallback((entry, reply) -> {
- StatusBarNotification newSbn =
- rebuildNotificationWithRemoteInputInserted(entry, reply, true /* showSpinner */,
- null /* mimeType */, null /* uri */);
- mEntryManager.updateNotification(newSbn, null /* ranking */);
- });
+ if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+ mSmartReplyController.setCallback((entry, reply) -> {
+ StatusBarNotification newSbn = mRebuilder.rebuildForSendingSmartReply(entry, reply);
+ mEntryManager.updateNotification(newSbn, null /* ranking */);
+ });
+ }
}
public void addControllerCallback(RemoteInputController.Callback callback) {
@@ -574,51 +572,47 @@ public class NotificationRemoteInputManager implements Dumpable {
if (v == null) {
return null;
}
- return (RemoteInputView) v.findViewWithTag(RemoteInputView.VIEW_TAG);
- }
-
- /**
- * Adds all the notification lifetime extenders. Each extender represents a reason for the
- * NotificationRemoteInputManager to keep a notification lifetime extended.
- */
- protected void addLifetimeExtenders() {
- mLifetimeExtenders.add(new RemoteInputHistoryExtender());
- mLifetimeExtenders.add(new SmartReplyHistoryExtender());
- mLifetimeExtenders.add(new RemoteInputActiveExtender());
+ return v.findViewWithTag(RemoteInputView.VIEW_TAG);
}
public ArrayList<NotificationLifetimeExtender> getLifetimeExtenders() {
- return mLifetimeExtenders;
+ // OLD pipeline code ONLY; can assume implementation
+ return ((LegacyRemoteInputLifetimeExtender) mRemoteInputListener).mLifetimeExtenders;
}
@VisibleForTesting
void onPerformRemoveNotification(NotificationEntry entry, final String key) {
- if (mKeysKeptForRemoteInputHistory.contains(key)) {
- mKeysKeptForRemoteInputHistory.remove(key);
- }
+ // OLD pipeline code ONLY; can assume implementation
+ ((LegacyRemoteInputLifetimeExtender) mRemoteInputListener)
+ .mKeysKeptForRemoteInputHistory.remove(key);
+ cleanUpRemoteInputForUserRemoval(entry);
+ }
+
+ /**
+ * Disable remote input on the entry and remove the remote input view.
+ * This should be called when a user dismisses a notification that won't be lifetime extended.
+ */
+ public void cleanUpRemoteInputForUserRemoval(NotificationEntry entry) {
if (isRemoteInputActive(entry)) {
entry.mRemoteEditImeVisible = false;
mRemoteInputController.removeRemoteInput(entry, null);
}
}
+ /** Informs the remote input system that the panel has collapsed */
public void onPanelCollapsed() {
- for (int i = 0; i < mEntriesKeptForRemoteInputActive.size(); i++) {
- NotificationEntry entry = mEntriesKeptForRemoteInputActive.valueAt(i);
- if (mRemoteInputController != null) {
- mRemoteInputController.removeRemoteInput(entry, null);
- }
- if (mNotificationLifetimeFinishedCallback != null) {
- mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.getKey());
- }
+ if (mRemoteInputListener != null) {
+ mRemoteInputListener.onPanelCollapsed();
}
- mEntriesKeptForRemoteInputActive.clear();
}
+ /** Returns whether the given notification is lifetime extended because of remote input */
public boolean isNotificationKeptForRemoteInputHistory(String key) {
- return mKeysKeptForRemoteInputHistory.contains(key);
+ return mRemoteInputListener != null
+ && mRemoteInputListener.isNotificationKeptForRemoteInputHistory(key);
}
+ /** Returns whether the notification should be lifetime extended for remote input history */
public boolean shouldKeepForRemoteInputHistory(NotificationEntry entry) {
if (!FORCE_REMOTE_INPUT_HISTORY) {
return false;
@@ -636,16 +630,12 @@ public class NotificationRemoteInputManager implements Dumpable {
if (entry == null) {
return;
}
- final String key = entry.getKey();
- if (isNotificationKeptForRemoteInputHistory(key)) {
- mMainHandler.postDelayed(() -> {
- if (isNotificationKeptForRemoteInputHistory(key)) {
- mNotificationLifetimeFinishedCallback.onSafeToRemove(key);
- }
- }, REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY);
+ if (mRemoteInputListener != null) {
+ mRemoteInputListener.releaseNotificationIfKeptForRemoteInputHistory(entry);
}
}
+ /** Returns whether the notification should be lifetime extended for smart reply history */
public boolean shouldKeepForSmartReplyHistory(NotificationEntry entry) {
if (!FORCE_REMOTE_INPUT_HISTORY) {
return false;
@@ -661,64 +651,11 @@ public class NotificationRemoteInputManager implements Dumpable {
}
}
- @VisibleForTesting
- StatusBarNotification rebuildNotificationForCanceledSmartReplies(
- NotificationEntry entry) {
- return rebuildNotificationWithRemoteInputInserted(entry, null /* remoteInputTest */,
- false /* showSpinner */, null /* mimeType */, null /* uri */);
- }
-
- @VisibleForTesting
- StatusBarNotification rebuildNotificationWithRemoteInputInserted(NotificationEntry entry,
- CharSequence remoteInputText, boolean showSpinner, String mimeType, Uri uri) {
- StatusBarNotification sbn = entry.getSbn();
-
- Notification.Builder b = Notification.Builder
- .recoverBuilder(mContext, sbn.getNotification().clone());
- if (remoteInputText != null || uri != null) {
- RemoteInputHistoryItem newItem = uri != null
- ? new RemoteInputHistoryItem(mimeType, uri, remoteInputText)
- : new RemoteInputHistoryItem(remoteInputText);
- Parcelable[] oldHistoryItems = sbn.getNotification().extras
- .getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
- RemoteInputHistoryItem[] newHistoryItems = oldHistoryItems != null
- ? Stream.concat(
- Stream.of(newItem),
- Arrays.stream(oldHistoryItems).map(p -> (RemoteInputHistoryItem) p))
- .toArray(RemoteInputHistoryItem[]::new)
- : new RemoteInputHistoryItem[] { newItem };
- b.setRemoteInputHistory(newHistoryItems);
- }
- b.setShowRemoteInputSpinner(showSpinner);
- b.setHideSmartReplies(true);
-
- Notification newNotification = b.build();
-
- // Undo any compatibility view inflation
- newNotification.contentView = sbn.getNotification().contentView;
- newNotification.bigContentView = sbn.getNotification().bigContentView;
- newNotification.headsUpContentView = sbn.getNotification().headsUpContentView;
-
- return new StatusBarNotification(
- sbn.getPackageName(),
- sbn.getOpPkg(),
- sbn.getId(),
- sbn.getTag(),
- sbn.getUid(),
- sbn.getInitialPid(),
- newNotification,
- sbn.getUser(),
- sbn.getOverrideGroupKey(),
- sbn.getPostTime());
- }
-
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("NotificationRemoteInputManager state:");
- pw.print(" mKeysKeptForRemoteInputHistory: ");
- pw.println(mKeysKeptForRemoteInputHistory);
- pw.print(" mEntriesKeptForRemoteInputActive: ");
- pw.println(mEntriesKeptForRemoteInputActive);
+ if (mRemoteInputListener instanceof Dumpable) {
+ ((Dumpable) mRemoteInputListener).dump(fd, pw, args);
+ }
}
public void bindRow(ExpandableNotificationRow row) {
@@ -734,11 +671,6 @@ public class NotificationRemoteInputManager implements Dumpable {
return mInteractionHandler;
}
- @VisibleForTesting
- public Set<NotificationEntry> getEntriesKeptForRemoteInputActive() {
- return mEntriesKeptForRemoteInputActive;
- }
-
public boolean isRemoteInputActive() {
return mRemoteInputController != null && mRemoteInputController.isRemoteInputActive();
}
@@ -758,131 +690,6 @@ public class NotificationRemoteInputManager implements Dumpable {
}
/**
- * NotificationRemoteInputManager has multiple reasons to keep notification lifetime extended
- * so we implement multiple NotificationLifetimeExtenders
- */
- protected abstract class RemoteInputExtender implements NotificationLifetimeExtender {
- @Override
- public void setCallback(NotificationSafeToRemoveCallback callback) {
- if (mNotificationLifetimeFinishedCallback == null) {
- mNotificationLifetimeFinishedCallback = callback;
- }
- }
- }
-
- /**
- * Notification is kept alive as it was cancelled in response to a remote input interaction.
- * This allows us to show what you replied and allows you to continue typing into it.
- */
- protected class RemoteInputHistoryExtender extends RemoteInputExtender {
- @Override
- public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
- return shouldKeepForRemoteInputHistory(entry);
- }
-
- @Override
- public void setShouldManageLifetime(NotificationEntry entry,
- boolean shouldExtend) {
- if (shouldExtend) {
- CharSequence remoteInputText = entry.remoteInputText;
- if (TextUtils.isEmpty(remoteInputText)) {
- remoteInputText = entry.remoteInputTextWhenReset;
- }
- String remoteInputMimeType = entry.remoteInputMimeType;
- Uri remoteInputUri = entry.remoteInputUri;
- StatusBarNotification newSbn = rebuildNotificationWithRemoteInputInserted(entry,
- remoteInputText, false /* showSpinner */, remoteInputMimeType,
- remoteInputUri);
- entry.onRemoteInputInserted();
-
- if (newSbn == null) {
- return;
- }
-
- mEntryManager.updateNotification(newSbn, null);
-
- // Ensure the entry hasn't already been removed. This can happen if there is an
- // inflation exception while updating the remote history
- if (entry.isRemoved()) {
- return;
- }
-
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Keeping notification around after sending remote input "
- + entry.getKey());
- }
-
- mKeysKeptForRemoteInputHistory.add(entry.getKey());
- } else {
- mKeysKeptForRemoteInputHistory.remove(entry.getKey());
- }
- }
- }
-
- /**
- * Notification is kept alive for smart reply history. Similar to REMOTE_INPUT_HISTORY but with
- * {@link SmartReplyController} specific logic
- */
- protected class SmartReplyHistoryExtender extends RemoteInputExtender {
- @Override
- public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
- return shouldKeepForSmartReplyHistory(entry);
- }
-
- @Override
- public void setShouldManageLifetime(NotificationEntry entry,
- boolean shouldExtend) {
- if (shouldExtend) {
- StatusBarNotification newSbn = rebuildNotificationForCanceledSmartReplies(entry);
-
- if (newSbn == null) {
- return;
- }
-
- mEntryManager.updateNotification(newSbn, null);
-
- if (entry.isRemoved()) {
- return;
- }
-
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Keeping notification around after sending smart reply "
- + entry.getKey());
- }
-
- mKeysKeptForRemoteInputHistory.add(entry.getKey());
- } else {
- mKeysKeptForRemoteInputHistory.remove(entry.getKey());
- mSmartReplyController.stopSending(entry);
- }
- }
- }
-
- /**
- * Notification is kept alive because the user is still using the remote input
- */
- protected class RemoteInputActiveExtender extends RemoteInputExtender {
- @Override
- public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
- return isRemoteInputActive(entry);
- }
-
- @Override
- public void setShouldManageLifetime(NotificationEntry entry,
- boolean shouldExtend) {
- if (shouldExtend) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Keeping notification around while remote input active "
- + entry.getKey());
- }
- mEntriesKeptForRemoteInputActive.add(entry);
- } else {
- mEntriesKeptForRemoteInputActive.remove(entry);
- }
- }
- }
-
- /**
* Callback for various remote input related events, or for providing information that
* NotificationRemoteInputManager needs to know to decide what to do.
*/
@@ -975,4 +782,256 @@ public class NotificationRemoteInputManager implements Dumpable {
*/
boolean showBouncerIfNecessary();
}
+
+ /** An interface for listening to remote input events that relate to notification lifetime */
+ public interface RemoteInputListener {
+ /** Called when remote input pending intent has been sent */
+ void onRemoteInputSent(@NonNull NotificationEntry entry);
+
+ /** Called when the notification shade becomes fully closed */
+ void onPanelCollapsed();
+
+ /** @return whether lifetime of a notification is being extended by the listener */
+ boolean isNotificationKeptForRemoteInputHistory(@NonNull String key);
+
+ /** Called on user interaction to end lifetime extension for history */
+ void releaseNotificationIfKeptForRemoteInputHistory(@NonNull NotificationEntry entry);
+
+ /** Called when the RemoteInputController is attached to the manager */
+ void setRemoteInputController(@NonNull RemoteInputController remoteInputController);
+ }
+
+ @VisibleForTesting
+ protected class LegacyRemoteInputLifetimeExtender implements RemoteInputListener, Dumpable {
+
+ /**
+ * How long to wait before auto-dismissing a notification that was kept for remote input,
+ * and has now sent a remote input. We auto-dismiss, because the app may not see a reason to
+ * cancel these given that they technically don't exist anymore. We wait a bit in case the
+ * app issues an update.
+ */
+ private static final int REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY = 200;
+
+ /**
+ * Notifications that are already removed but are kept around because we want to show the
+ * remote input history. See {@link RemoteInputHistoryExtender} and
+ * {@link SmartReplyHistoryExtender}.
+ */
+ protected final ArraySet<String> mKeysKeptForRemoteInputHistory = new ArraySet<>();
+
+ /**
+ * Notifications that are already removed but are kept around because the remote input is
+ * actively being used (i.e. user is typing in it). See {@link RemoteInputActiveExtender}.
+ */
+ protected final ArraySet<NotificationEntry> mEntriesKeptForRemoteInputActive =
+ new ArraySet<>();
+
+ protected NotificationLifetimeExtender.NotificationSafeToRemoveCallback
+ mNotificationLifetimeFinishedCallback;
+
+ protected final ArrayList<NotificationLifetimeExtender> mLifetimeExtenders =
+ new ArrayList<>();
+ private RemoteInputController mRemoteInputController;
+
+ LegacyRemoteInputLifetimeExtender() {
+ addLifetimeExtenders();
+ }
+
+ /**
+ * Adds all the notification lifetime extenders. Each extender represents a reason for the
+ * NotificationRemoteInputManager to keep a notification lifetime extended.
+ */
+ protected void addLifetimeExtenders() {
+ mLifetimeExtenders.add(new RemoteInputHistoryExtender());
+ mLifetimeExtenders.add(new SmartReplyHistoryExtender());
+ mLifetimeExtenders.add(new RemoteInputActiveExtender());
+ }
+
+ @Override
+ public void setRemoteInputController(@NonNull RemoteInputController remoteInputController) {
+ mRemoteInputController= remoteInputController;
+ }
+
+ @Override
+ public void onRemoteInputSent(@NonNull NotificationEntry entry) {
+ if (FORCE_REMOTE_INPUT_HISTORY
+ && isNotificationKeptForRemoteInputHistory(entry.getKey())) {
+ mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.getKey());
+ } else if (mEntriesKeptForRemoteInputActive.contains(entry)) {
+ // We're currently holding onto this notification, but from the apps point of
+ // view it is already canceled, so we'll need to cancel it on the apps behalf
+ // after sending - unless the app posts an update in the mean time, so wait a
+ // bit.
+ mMainHandler.postDelayed(() -> {
+ if (mEntriesKeptForRemoteInputActive.remove(entry)) {
+ mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.getKey());
+ }
+ }, REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY);
+ }
+ }
+
+ @Override
+ public void onPanelCollapsed() {
+ for (int i = 0; i < mEntriesKeptForRemoteInputActive.size(); i++) {
+ NotificationEntry entry = mEntriesKeptForRemoteInputActive.valueAt(i);
+ if (mRemoteInputController != null) {
+ mRemoteInputController.removeRemoteInput(entry, null);
+ }
+ if (mNotificationLifetimeFinishedCallback != null) {
+ mNotificationLifetimeFinishedCallback.onSafeToRemove(entry.getKey());
+ }
+ }
+ mEntriesKeptForRemoteInputActive.clear();
+ }
+
+ @Override
+ public boolean isNotificationKeptForRemoteInputHistory(@NonNull String key) {
+ return mKeysKeptForRemoteInputHistory.contains(key);
+ }
+
+ @Override
+ public void releaseNotificationIfKeptForRemoteInputHistory(
+ @NonNull NotificationEntry entry) {
+ final String key = entry.getKey();
+ if (isNotificationKeptForRemoteInputHistory(key)) {
+ mMainHandler.postDelayed(() -> {
+ if (isNotificationKeptForRemoteInputHistory(key)) {
+ mNotificationLifetimeFinishedCallback.onSafeToRemove(key);
+ }
+ }, REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY);
+ }
+ }
+
+ @VisibleForTesting
+ public Set<NotificationEntry> getEntriesKeptForRemoteInputActive() {
+ return mEntriesKeptForRemoteInputActive;
+ }
+
+ @Override
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
+ @NonNull String[] args) {
+ pw.println("LegacyRemoteInputLifetimeExtender:");
+ pw.print(" mKeysKeptForRemoteInputHistory: ");
+ pw.println(mKeysKeptForRemoteInputHistory);
+ pw.print(" mEntriesKeptForRemoteInputActive: ");
+ pw.println(mEntriesKeptForRemoteInputActive);
+ }
+
+ /**
+ * NotificationRemoteInputManager has multiple reasons to keep notification lifetime
+ * extended so we implement multiple NotificationLifetimeExtenders
+ */
+ protected abstract class RemoteInputExtender implements NotificationLifetimeExtender {
+ @Override
+ public void setCallback(NotificationSafeToRemoveCallback callback) {
+ if (mNotificationLifetimeFinishedCallback == null) {
+ mNotificationLifetimeFinishedCallback = callback;
+ }
+ }
+ }
+
+ /**
+ * Notification is kept alive as it was cancelled in response to a remote input interaction.
+ * This allows us to show what you replied and allows you to continue typing into it.
+ */
+ protected class RemoteInputHistoryExtender extends RemoteInputExtender {
+ @Override
+ public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
+ return shouldKeepForRemoteInputHistory(entry);
+ }
+
+ @Override
+ public void setShouldManageLifetime(NotificationEntry entry,
+ boolean shouldExtend) {
+ if (shouldExtend) {
+ StatusBarNotification newSbn = mRebuilder.rebuildForRemoteInputReply(entry);
+ entry.onRemoteInputInserted();
+
+ if (newSbn == null) {
+ return;
+ }
+
+ mEntryManager.updateNotification(newSbn, null);
+
+ // Ensure the entry hasn't already been removed. This can happen if there is an
+ // inflation exception while updating the remote history
+ if (entry.isRemoved()) {
+ return;
+ }
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Keeping notification around after sending remote input "
+ + entry.getKey());
+ }
+
+ mKeysKeptForRemoteInputHistory.add(entry.getKey());
+ } else {
+ mKeysKeptForRemoteInputHistory.remove(entry.getKey());
+ }
+ }
+ }
+
+ /**
+ * Notification is kept alive for smart reply history. Similar to REMOTE_INPUT_HISTORY but
+ * with {@link SmartReplyController} specific logic
+ */
+ protected class SmartReplyHistoryExtender extends RemoteInputExtender {
+ @Override
+ public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
+ return shouldKeepForSmartReplyHistory(entry);
+ }
+
+ @Override
+ public void setShouldManageLifetime(NotificationEntry entry,
+ boolean shouldExtend) {
+ if (shouldExtend) {
+ StatusBarNotification newSbn = mRebuilder.rebuildForCanceledSmartReplies(entry);
+
+ if (newSbn == null) {
+ return;
+ }
+
+ mEntryManager.updateNotification(newSbn, null);
+
+ if (entry.isRemoved()) {
+ return;
+ }
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Keeping notification around after sending smart reply "
+ + entry.getKey());
+ }
+
+ mKeysKeptForRemoteInputHistory.add(entry.getKey());
+ } else {
+ mKeysKeptForRemoteInputHistory.remove(entry.getKey());
+ mSmartReplyController.stopSending(entry);
+ }
+ }
+ }
+
+ /**
+ * Notification is kept alive because the user is still using the remote input
+ */
+ protected class RemoteInputActiveExtender extends RemoteInputExtender {
+ @Override
+ public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
+ return isRemoteInputActive(entry);
+ }
+
+ @Override
+ public void setShouldManageLifetime(NotificationEntry entry,
+ boolean shouldExtend) {
+ if (shouldExtend) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Keeping notification around while remote input active "
+ + entry.getKey());
+ }
+ mEntriesKeptForRemoteInputActive.add(entry);
+ } else {
+ mEntriesKeptForRemoteInputActive.remove(entry);
+ }
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index 5648741e3caf..46004db3067a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -37,9 +37,10 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.phone.BiometricUnlockController
+import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK
import com.android.systemui.statusbar.phone.DozeParameters
-import com.android.systemui.statusbar.phone.PanelExpansionListener
import com.android.systemui.statusbar.phone.ScrimController
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.WallpaperController
import java.io.FileDescriptor
@@ -73,10 +74,6 @@ class NotificationShadeDepthController @Inject constructor(
private const val TAG = "DepthController"
}
- /**
- * Did we already unblur while dozing?
- */
- private var alreadyUnblurredWhileDozing = false
lateinit var root: View
private var blurRoot: View? = null
private var keyguardAnimator: Animator? = null
@@ -233,11 +230,9 @@ class NotificationShadeDepthController @Inject constructor(
private val keyguardStateCallback = object : KeyguardStateController.Callback {
override fun onKeyguardFadingAwayChanged() {
if (!keyguardStateController.isKeyguardFadingAway ||
- !biometricUnlockController.isWakeAndUnlock) {
+ biometricUnlockController.mode != MODE_WAKE_AND_UNLOCK) {
return
}
- // When wakeAndUnlocking the screen remains dozing, so we have to manually trigger
- // the unblur earlier
keyguardAnimator?.cancel()
keyguardAnimator = ValueAnimator.ofFloat(1f, 0f).apply {
@@ -259,7 +254,6 @@ class NotificationShadeDepthController @Inject constructor(
})
start()
}
- alreadyUnblurredWhileDozing = statusBarStateController.dozeAmount != 0.0f
}
override fun onKeyguardShowingChanged() {
@@ -281,24 +275,10 @@ class NotificationShadeDepthController @Inject constructor(
if (isDozing) {
shadeAnimation.finishIfRunning()
brightnessMirrorSpring.finishIfRunning()
-
- // unset this for safety, to be ready for the next wakeup
- alreadyUnblurredWhileDozing = false
}
}
override fun onDozeAmountChanged(linear: Float, eased: Float) {
- if (alreadyUnblurredWhileDozing) {
- if (linear == 0.0f) {
- // We finished waking up, let's reset
- alreadyUnblurredWhileDozing = false
- } else {
- // We've already handled the unbluring from the keyguardAnimator above.
- // if we would continue, we'd play another unzoom / blur animation from the
- // dozing changing.
- return
- }
- }
wakeAndUnlockBlurRadius = blurUtils.blurRadiusOfRatio(eased)
scheduleUpdate()
}
@@ -329,10 +309,12 @@ class NotificationShadeDepthController @Inject constructor(
/**
* Update blurs when pulling down the shade
*/
- override fun onPanelExpansionChanged(rawExpansion: Float, tracking: Boolean) {
+ override fun onPanelExpansionChanged(
+ rawFraction: Float, expanded: Boolean, tracking: Boolean
+ ) {
val timestamp = SystemClock.elapsedRealtimeNanos()
val expansion = MathUtils.saturate(
- (rawExpansion - panelPullDownMinFraction) / (1f - panelPullDownMinFraction))
+ (rawFraction - panelPullDownMinFraction) / (1f - panelPullDownMinFraction))
if (shadeExpansion == expansion && prevTracking == tracking) {
prevTimestamp = timestamp
@@ -456,7 +438,6 @@ class NotificationShadeDepthController @Inject constructor(
it.println("blursDisabledForAppLaunch: $blursDisabledForAppLaunch")
it.println("qsPanelExpansion: $qsPanelExpansion")
it.println("transitionToFullShadeProgress: $transitionToFullShadeProgress")
- it.println("alreadyUnblurredWhileDozing: $alreadyUnblurredWhileDozing")
it.println("lastAppliedBlur: $lastAppliedBlur")
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 396d86bab825..464b2b69c58e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -27,6 +27,7 @@ import android.view.ViewGroup;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.dagger.StatusBarModule;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
@@ -72,6 +73,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
// Dependencies:
private final DynamicChildBindController mDynamicChildBindController;
+ private final FeatureFlags mFeatureFlags;
protected final NotificationLockscreenUserManager mLockscreenUserManager;
protected final NotificationGroupManagerLegacy mGroupManager;
protected final VisualStabilityManager mVisualStabilityManager;
@@ -107,6 +109,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
public NotificationViewHierarchyManager(
Context context,
@Main Handler mainHandler,
+ FeatureFlags featureFlags,
NotificationLockscreenUserManager notificationLockscreenUserManager,
NotificationGroupManagerLegacy groupManager,
VisualStabilityManager visualStabilityManager,
@@ -121,6 +124,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
AssistantFeedbackController assistantFeedbackController) {
mContext = context;
mHandler = mainHandler;
+ mFeatureFlags = featureFlags;
mLockscreenUserManager = notificationLockscreenUserManager;
mBypassController = bypassController;
mGroupManager = groupManager;
@@ -142,7 +146,9 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
NotificationListContainer listContainer) {
mPresenter = presenter;
mListContainer = listContainer;
- mDynamicPrivacyController.addListener(this);
+ if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+ mDynamicPrivacyController.addListener(this);
+ }
}
/**
@@ -151,6 +157,10 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
//TODO: Rewrite this to focus on Entries, or some other data object instead of views
public void updateNotificationViews() {
Assert.isMainThread();
+ if (!mFeatureFlags.checkLegacyPipelineEnabled()) {
+ return;
+ }
+
beginUpdate();
List<NotificationEntry> activeNotifications = mEntryManager.getVisibleNotifications();
@@ -425,6 +435,10 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
*/
public void updateRowStates() {
Assert.isMainThread();
+ if (!mFeatureFlags.checkLegacyPipelineEnabled()) {
+ return;
+ }
+
beginUpdate();
updateRowStatesInternal();
endUpdate();
@@ -510,6 +524,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
@Override
public void onDynamicPrivacyChanged() {
+ mFeatureFlags.assertLegacyPipelineEnabled();
if (mPerformingUpdate) {
Log.w(TAG, "onDynamicPrivacyChanged made a re-entrant call");
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java
index bcba5cc09c5d..8a4c4b5ac5c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar;
+import android.annotation.NonNull;
import android.os.Bundle;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
@@ -26,7 +27,9 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.demomode.DemoModeCommandReceiver;
import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.statusbar.connectivity.IconState;
import com.android.systemui.statusbar.connectivity.NetworkController;
+import com.android.systemui.statusbar.connectivity.SignalCallback;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.ViewController;
@@ -135,10 +138,9 @@ public class OperatorNameViewController extends ViewController<OperatorNameView>
(area, darkIntensity, tint) ->
mView.setTextColor(DarkIconDispatcher.getTint(area, mView, tint));
- private final NetworkController.SignalCallback mSignalCallback =
- new NetworkController.SignalCallback() {
+ private final SignalCallback mSignalCallback = new SignalCallback() {
@Override
- public void setIsAirplaneMode(NetworkController.IconState icon) {
+ public void setIsAirplaneMode(@NonNull IconState icon) {
update();
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index 83701a040f24..cde3b0e2e76b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -299,6 +299,9 @@ public class RemoteInputController {
default void onRemoteInputSent(NotificationEntry entry) {}
}
+ /**
+ * This is a delegate which implements some view controller pieces of the remote input process
+ */
public interface Delegate {
/**
* Activate remote input if necessary.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilder.java
new file mode 100644
index 000000000000..90abec17771c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilder.java
@@ -0,0 +1,141 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.app.Notification;
+import android.app.RemoteInputHistoryItem;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Parcelable;
+import android.service.notification.StatusBarNotification;
+import android.text.TextUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+import javax.inject.Inject;
+
+/**
+ * A helper class which will augment the notifications using arguments and other information
+ * accessible to the entry in order to provide intermediate remote input states.
+ */
+@SysUISingleton
+public class RemoteInputNotificationRebuilder {
+
+ private final Context mContext;
+
+ @Inject
+ RemoteInputNotificationRebuilder(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * When a smart reply is sent off to the app, we insert the text into the remote input history,
+ * and show a spinner to indicate that the app has yet to respond.
+ */
+ @NonNull
+ public StatusBarNotification rebuildForSendingSmartReply(NotificationEntry entry,
+ CharSequence reply) {
+ return rebuildWithRemoteInputInserted(entry, reply,
+ true /* showSpinner */,
+ null /* mimeType */, null /* uri */);
+ }
+
+ /**
+ * When the app cancels a notification in response to a smart reply, we remove the spinner
+ * and leave the previously-added reply. This is the lifetime-extended appearance of the
+ * notification.
+ */
+ @NonNull
+ public StatusBarNotification rebuildForCanceledSmartReplies(
+ NotificationEntry entry) {
+ return rebuildWithRemoteInputInserted(entry, null /* remoteInputTest */,
+ false /* showSpinner */, null /* mimeType */, null /* uri */);
+ }
+
+ /**
+ * When the app cancels a notification in response to a remote input reply, we update the
+ * notification with the reply text and/or attachment. This is the lifetime-extended
+ * appearance of the notification.
+ */
+ @NonNull
+ public StatusBarNotification rebuildForRemoteInputReply(NotificationEntry entry) {
+ CharSequence remoteInputText = entry.remoteInputText;
+ if (TextUtils.isEmpty(remoteInputText)) {
+ remoteInputText = entry.remoteInputTextWhenReset;
+ }
+ String remoteInputMimeType = entry.remoteInputMimeType;
+ Uri remoteInputUri = entry.remoteInputUri;
+ StatusBarNotification newSbn = rebuildWithRemoteInputInserted(entry,
+ remoteInputText, false /* showSpinner */, remoteInputMimeType,
+ remoteInputUri);
+ return newSbn;
+ }
+
+ /** Inner method for generating the SBN */
+ @VisibleForTesting
+ @NonNull
+ StatusBarNotification rebuildWithRemoteInputInserted(NotificationEntry entry,
+ CharSequence remoteInputText, boolean showSpinner, String mimeType, Uri uri) {
+ StatusBarNotification sbn = entry.getSbn();
+
+ Notification.Builder b = Notification.Builder
+ .recoverBuilder(mContext, sbn.getNotification().clone());
+ if (remoteInputText != null || uri != null) {
+ RemoteInputHistoryItem newItem = uri != null
+ ? new RemoteInputHistoryItem(mimeType, uri, remoteInputText)
+ : new RemoteInputHistoryItem(remoteInputText);
+ Parcelable[] oldHistoryItems = sbn.getNotification().extras
+ .getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
+ RemoteInputHistoryItem[] newHistoryItems = oldHistoryItems != null
+ ? Stream.concat(
+ Stream.of(newItem),
+ Arrays.stream(oldHistoryItems).map(p -> (RemoteInputHistoryItem) p))
+ .toArray(RemoteInputHistoryItem[]::new)
+ : new RemoteInputHistoryItem[] { newItem };
+ b.setRemoteInputHistory(newHistoryItems);
+ }
+ b.setShowRemoteInputSpinner(showSpinner);
+ b.setHideSmartReplies(true);
+
+ Notification newNotification = b.build();
+
+ // Undo any compatibility view inflation
+ newNotification.contentView = sbn.getNotification().contentView;
+ newNotification.bigContentView = sbn.getNotification().bigContentView;
+ newNotification.headsUpContentView = sbn.getNotification().headsUpContentView;
+
+ return new StatusBarNotification(
+ sbn.getPackageName(),
+ sbn.getOpPkg(),
+ sbn.getId(),
+ sbn.getTag(),
+ sbn.getUid(),
+ sbn.getInitialPid(),
+ newNotification,
+ sbn.getUser(),
+ sbn.getOverrideGroupKey(),
+ sbn.getPostTime());
+ }
+
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
index 7fc18b753d40..e288b1530d4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
@@ -19,35 +19,44 @@ import android.app.Notification;
import android.os.RemoteException;
import android.util.ArraySet;
+import androidx.annotation.NonNull;
+
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.Dumpable;
+import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.dagger.StatusBarModule;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.Set;
/**
* Handles when smart replies are added to a notification
* and clicked upon.
*/
-public class SmartReplyController {
+public class SmartReplyController implements Dumpable {
private final IStatusBarService mBarService;
private final NotificationEntryManager mEntryManager;
private final NotificationClickNotifier mClickNotifier;
- private Set<String> mSendingKeys = new ArraySet<>();
+ private final Set<String> mSendingKeys = new ArraySet<>();
private Callback mCallback;
/**
* Injected constructor. See {@link StatusBarModule}.
*/
- public SmartReplyController(NotificationEntryManager entryManager,
+ public SmartReplyController(
+ DumpManager dumpManager,
+ NotificationEntryManager entryManager,
IStatusBarService statusBarService,
NotificationClickNotifier clickNotifier) {
mBarService = statusBarService;
mEntryManager = entryManager;
mClickNotifier = clickNotifier;
+ dumpManager.registerDumpable(this);
}
public void setCallback(Callback callback) {
@@ -75,6 +84,7 @@ public class SmartReplyController {
public void smartActionClicked(
NotificationEntry entry, int actionIndex, Notification.Action action,
boolean generatedByAssistant) {
+ // TODO(b/204183781): get this from the current pipeline
final int count = mEntryManager.getActiveNotificationsCount();
final int rank = entry.getRanking().getRank();
NotificationVisibility.NotificationLocation location =
@@ -112,6 +122,14 @@ public class SmartReplyController {
}
}
+ @Override
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.println("mSendingKeys: " + mSendingKeys.size());
+ for (String key : mSendingKeys) {
+ pw.println(" * " + key);
+ }
+ }
+
/**
* Callback for any class that needs to do something in response to a smart reply being sent.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 6da981b72428..da2b85ee0b61 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -28,7 +28,6 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.os.SystemProperties;
-import android.os.Trace;
import android.text.format.DateFormat;
import android.util.FloatProperty;
import android.util.Log;
@@ -174,7 +173,7 @@ public class StatusBarStateControllerImpl implements
}
// Record the to-be mState and mLastState
- recordHistoricalState(state, mState);
+ recordHistoricalState(state /* newState */, mState /* lastState */, false);
// b/139259891
if (mState == StatusBarState.SHADE && state == StatusBarState.SHADE_LOCKED) {
@@ -182,7 +181,6 @@ public class StatusBarStateControllerImpl implements
}
synchronized (mListeners) {
- Trace.beginSection(TAG + "#setState(" + StatusBarState.toShortString(state) + ")");
String tag = getClass().getSimpleName() + "#setState(" + state + ")";
DejankUtils.startDetectingBlockingIpcs(tag);
for (RankedListener rl : new ArrayList<>(mListeners)) {
@@ -200,7 +198,6 @@ public class StatusBarStateControllerImpl implements
rl.mListener.onStatePostChange();
}
DejankUtils.stopDetectingBlockingIpcs(tag);
- Trace.endSection();
}
return true;
@@ -209,6 +206,7 @@ public class StatusBarStateControllerImpl implements
@Override
public void setUpcomingState(int nextState) {
mUpcomingState = nextState;
+ recordHistoricalState(mUpcomingState /* newState */, mState /* lastState */, true);
}
@Override
@@ -265,14 +263,12 @@ public class StatusBarStateControllerImpl implements
mIsDozing = isDozing;
synchronized (mListeners) {
- Trace.beginSection(TAG + "#setDozing(" + isDozing + ")");
String tag = getClass().getSimpleName() + "#setIsDozing";
DejankUtils.startDetectingBlockingIpcs(tag);
for (RankedListener rl : new ArrayList<>(mListeners)) {
rl.mListener.onDozingChanged(isDozing);
}
DejankUtils.stopDetectingBlockingIpcs(tag);
- Trace.endSection();
}
return true;
@@ -338,14 +334,12 @@ public class StatusBarStateControllerImpl implements
mDozeAmount = dozeAmount;
float interpolatedAmount = mDozeInterpolator.getInterpolation(dozeAmount);
synchronized (mListeners) {
- Trace.beginSection(TAG + "#setDozeAmount");
String tag = getClass().getSimpleName() + "#setDozeAmount";
DejankUtils.startDetectingBlockingIpcs(tag);
for (RankedListener rl : new ArrayList<>(mListeners)) {
rl.mListener.onDozeAmountChanged(mDozeAmount, interpolatedAmount);
}
DejankUtils.stopDetectingBlockingIpcs(tag);
- Trace.endSection();
}
}
@@ -476,13 +470,11 @@ public class StatusBarStateControllerImpl implements
public void setPulsing(boolean pulsing) {
if (mPulsing != pulsing) {
mPulsing = pulsing;
- Trace.beginSection(TAG + "#setPulsing(" + pulsing + ")");
synchronized (mListeners) {
for (RankedListener rl : new ArrayList<>(mListeners)) {
rl.mListener.onPulsingChanged(pulsing);
}
}
- Trace.endSection();
}
}
@@ -514,31 +506,36 @@ public class StatusBarStateControllerImpl implements
}
}
- private void recordHistoricalState(int currentState, int lastState) {
+ private void recordHistoricalState(int newState, int lastState, boolean upcoming) {
mHistoryIndex = (mHistoryIndex + 1) % HISTORY_SIZE;
HistoricalState state = mHistoricalRecords[mHistoryIndex];
- state.mState = currentState;
+ state.mNewState = newState;
state.mLastState = lastState;
state.mTimestamp = System.currentTimeMillis();
+ state.mUpcoming = upcoming;
}
/**
* For keeping track of our previous state to help with debugging
*/
private static class HistoricalState {
- int mState;
+ int mNewState;
int mLastState;
long mTimestamp;
+ boolean mUpcoming;
@Override
public String toString() {
if (mTimestamp != 0) {
StringBuilder sb = new StringBuilder();
- sb.append("state=").append(mState)
- .append(" (").append(describe(mState)).append(")");
- sb.append("lastState=").append(mLastState).append(" (").append(describe(mLastState))
+ if (mUpcoming) {
+ sb.append("upcoming-");
+ }
+ sb.append("newState=").append(mNewState)
+ .append("(").append(describe(mNewState)).append(")");
+ sb.append(" lastState=").append(mLastState).append("(").append(describe(mLastState))
.append(")");
- sb.append("timestamp=")
+ sb.append(" timestamp=")
.append(DateFormat.format("MM-dd HH:mm:ss", mTimestamp));
return sb.toString();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointController.kt
new file mode 100644
index 000000000000..490994d805fe
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointController.kt
@@ -0,0 +1,93 @@
+/*
+ * 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.connectivity
+
+import android.content.Intent
+import android.os.UserManager
+import android.provider.Settings
+
+import com.android.wifitrackerlib.MergedCarrierEntry
+import com.android.wifitrackerlib.WifiEntry
+
+/**
+ * Tracks changes in access points. Allows listening for changes, scanning for new APs,
+ * and connecting to new ones.
+ */
+interface AccessPointController {
+ fun addAccessPointCallback(callback: AccessPointCallback)
+ fun removeAccessPointCallback(callback: AccessPointCallback)
+
+ /**
+ * Request an updated list of available access points
+ *
+ * This method will trigger a call to [AccessPointCallback.onAccessPointsChanged]
+ */
+ fun scanForAccessPoints()
+
+ /**
+ * Gets the current [MergedCarrierEntry]. If null, this call generates a call to
+ * [AccessPointCallback.onAccessPointsChanged]
+ *
+ * @return the current [MergedCarrierEntry], if one exists
+ */
+ fun getMergedCarrierEntry(): MergedCarrierEntry?
+
+ /** @return the appropriate icon id for the given [WifiEntry]'s level */
+ fun getIcon(ap: WifiEntry): Int
+
+ /**
+ * Connects to a [WifiEntry] if it's saved or does not require security.
+ *
+ * If the entry is not saved and requires security, will trigger
+ * [AccessPointCallback.onSettingsActivityTriggered].
+ *
+ * @param ap
+ * @return `true` if [AccessPointCallback.onSettingsActivityTriggered] is triggered
+ */
+ fun connect(ap: WifiEntry?): Boolean
+
+ /**
+ * `true` if the current user does not have the [UserManager.DISALLOW_CONFIG_WIFI] restriction
+ */
+ fun canConfigWifi(): Boolean
+
+ /**
+ * `true` if the current user does not have the [UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS]
+ * restriction set
+ */
+ fun canConfigMobileData(): Boolean
+
+ interface AccessPointCallback {
+ /**
+ * Called whenever [scanForAccessPoints] is called, or [getMergedCarrierEntry] is called
+ * with a null entry
+ *
+ * @param accessPoints the list of available access points, including the current connected
+ * one if it exists
+ */
+ fun onAccessPointsChanged(accessPoints: List<@JvmSuppressWildcards WifiEntry>)
+
+ /**
+ * Called whenever [connecting][connect] to an unknown access point which has security.
+ * Implementers should launch the intent in the appropriate context
+ *
+ * @param settingsIntent an intent for [Settings.ACTION_WIFI_SETTINGS] with
+ * "wifi_start_connect_ssid" set as an extra
+ */
+ fun onSettingsActivityTriggered(settingsIntent: Intent?)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImpl.java
index a23d73d7ed84..893b836dedfc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImpl.java
@@ -56,9 +56,9 @@ import java.util.concurrent.Executor;
import javax.inject.Inject;
/** */
-public class AccessPointControllerImpl
- implements NetworkController.AccessPointController,
- WifiPickerTracker.WifiPickerTrackerCallback, LifecycleOwner {
+public class AccessPointControllerImpl implements AccessPointController,
+ WifiPickerTracker.WifiPickerTrackerCallback,
+ LifecycleOwner {
private static final String TAG = "AccessPointController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -117,13 +117,11 @@ public class AccessPointControllerImpl
super.finalize();
}
- /** */
public boolean canConfigWifi() {
return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI,
new UserHandle(mCurrentUser));
}
- /** */
public boolean canConfigMobileData() {
return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
UserHandle.of(mCurrentUser)) && mUserTracker.getUserInfo().isAdmin();
@@ -156,7 +154,7 @@ public class AccessPointControllerImpl
@Override
public void scanForAccessPoints() {
if (mWifiPickerTracker == null) {
- fireAcccessPointsCallback(Collections.emptyList());
+ fireAccessPointsCallback(Collections.emptyList());
return;
}
List<WifiEntry> entries = mWifiPickerTracker.getWifiEntries();
@@ -164,13 +162,13 @@ public class AccessPointControllerImpl
if (connectedEntry != null) {
entries.add(0, connectedEntry);
}
- fireAcccessPointsCallback(entries);
+ fireAccessPointsCallback(entries);
}
@Override
public MergedCarrierEntry getMergedCarrierEntry() {
if (mWifiPickerTracker == null) {
- fireAcccessPointsCallback(Collections.emptyList());
+ fireAccessPointsCallback(Collections.emptyList());
return null;
}
return mWifiPickerTracker.getMergedCarrierEntry();
@@ -190,7 +188,7 @@ public class AccessPointControllerImpl
* @param ap
* @return {@code true} if {@link AccessPointCallback#onSettingsActivityTriggered} is triggered
*/
- public boolean connect(WifiEntry ap) {
+ public boolean connect(@Nullable WifiEntry ap) {
if (ap == null) return false;
if (DEBUG) {
if (ap.getWifiConfiguration() != null) {
@@ -222,7 +220,7 @@ public class AccessPointControllerImpl
}
}
- private void fireAcccessPointsCallback(List<WifiEntry> aps) {
+ private void fireAccessPointsCallback(List<WifiEntry> aps) {
for (AccessPointCallback callback : mCallbacks) {
callback.onAccessPointsChanged(aps);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/CallbackHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/CallbackHandler.java
index 052a789200e6..6914ae67f4ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/CallbackHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/CallbackHandler.java
@@ -23,10 +23,6 @@ import android.telephony.SubscriptionInfo;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.connectivity.NetworkController.EmergencyListener;
-import com.android.systemui.statusbar.connectivity.NetworkController.IconState;
-import com.android.systemui.statusbar.connectivity.NetworkController.MobileDataIndicators;
-import com.android.systemui.statusbar.connectivity.NetworkController.SignalCallback;
-import com.android.systemui.statusbar.connectivity.NetworkController.WifiIndicators;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityState.kt b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityState.kt
new file mode 100644
index 000000000000..9c3c10c9219b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityState.kt
@@ -0,0 +1,104 @@
+/*
+ * 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.connectivity
+
+import android.annotation.SuppressLint
+import com.android.settingslib.SignalIcon.IconGroup
+import java.text.SimpleDateFormat
+
+/**
+ * Base type for various connectivity states, for use with [SignalController] and its subtypes
+ */
+open class ConnectivityState {
+ @JvmField var connected = false
+ @JvmField var enabled = false
+ @JvmField var activityIn = false
+ @JvmField var activityOut = false
+ @JvmField var level = 0
+ @JvmField var iconGroup: IconGroup? = null
+ @JvmField var inetCondition = 0
+ // Only for logging.
+ @JvmField var rssi = 0
+ // Not used for comparison, just used for logging.
+ @JvmField var time: Long = 0
+
+ override fun toString(): String {
+ return if (time != 0L) {
+ val builder = StringBuilder()
+ toString(builder)
+ builder.toString()
+ } else {
+ "Empty " + javaClass.simpleName
+ }
+ }
+
+ protected open fun copyFrom(other: ConnectivityState) {
+ connected = other.connected
+ enabled = other.enabled
+ activityIn = other.activityIn
+ activityOut = other.activityOut
+ level = other.level
+ iconGroup = other.iconGroup
+ inetCondition = other.inetCondition
+ rssi = other.rssi
+ time = other.time
+ }
+
+ protected open fun toString(builder: StringBuilder) {
+ builder.append("connected=$connected,")
+ .append("enabled=$enabled,")
+ .append("level=$level,")
+ .append("inetCondition=$inetCondition,")
+ .append("iconGroup=$iconGroup,")
+ .append("activityIn=$activityIn,")
+ .append("activityOut=$activityOut,")
+ .append("rssi=$rssi,")
+ .append("lastModified=${sSDF.format(time)}")
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (other == null) return false
+ if (other.javaClass != javaClass) return false
+
+ val o = other as ConnectivityState
+ return o.connected == connected &&
+ o.enabled == enabled &&
+ o.level == level &&
+ o.inetCondition == inetCondition &&
+ o.iconGroup === iconGroup &&
+ o.activityIn == activityIn &&
+ o.activityOut == activityOut &&
+ o.rssi == rssi
+ }
+
+ override fun hashCode(): Int {
+ var result = connected.hashCode()
+ result = 31 * result + enabled.hashCode()
+ result = 31 * result + activityIn.hashCode()
+ result = 31 * result + activityOut.hashCode()
+ result = 31 * result + level
+ result = 31 * result + (iconGroup?.hashCode() ?: 0)
+ result = 31 * result + inetCondition
+ result = 31 * result + rssi
+ result = 31 * result + time.hashCode()
+ return result
+ }
+}
+
+// No locale as it's only used for logging purposes
+@SuppressLint("SimpleDateFormat")
+private val sSDF = SimpleDateFormat("MM-dd HH:mm:ss.SSS")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/EthernetSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/EthernetSignalController.java
index c9d40adde644..acd97795c128 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/EthernetSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/EthernetSignalController.java
@@ -20,15 +20,12 @@ import android.net.NetworkCapabilities;
import com.android.settingslib.AccessibilityContentDescriptions;
import com.android.settingslib.SignalIcon.IconGroup;
-import com.android.settingslib.SignalIcon.State;
-import com.android.systemui.statusbar.connectivity.NetworkController.IconState;
-import com.android.systemui.statusbar.connectivity.NetworkController.SignalCallback;
import java.util.BitSet;
/** */
public class EthernetSignalController extends
- SignalController<State, IconGroup> {
+ SignalController<ConnectivityState, IconGroup> {
public EthernetSignalController(Context context,
CallbackHandler callbackHandler, NetworkControllerImpl networkController) {
@@ -68,7 +65,7 @@ public class EthernetSignalController extends
}
@Override
- public State cleanState() {
- return new State();
+ public ConnectivityState cleanState() {
+ return new ConnectivityState();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalController.java
index 20ef4eec0b97..9ae7ea2bdded 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalController.java
@@ -33,7 +33,6 @@ import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyDisplayInfo;
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsException;
import android.telephony.ims.ImsMmTelManager;
@@ -47,8 +46,6 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.AccessibilityContentDescriptions;
import com.android.settingslib.SignalIcon.MobileIconGroup;
-import com.android.settingslib.SignalIcon.MobileState;
-import com.android.settingslib.Utils;
import com.android.settingslib.graph.SignalDrawable;
import com.android.settingslib.mobile.MobileMappings.Config;
import com.android.settingslib.mobile.MobileStatusTracker;
@@ -58,9 +55,6 @@ import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.net.SignalStrengthUtil;
import com.android.systemui.R;
import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.statusbar.connectivity.NetworkController.IconState;
-import com.android.systemui.statusbar.connectivity.NetworkController.MobileDataIndicators;
-import com.android.systemui.statusbar.connectivity.NetworkController.SignalCallback;
import com.android.systemui.util.CarrierConfigTracker;
import java.io.PrintWriter;
@@ -93,15 +87,6 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
final SubscriptionInfo mSubscriptionInfo;
private Map<String, MobileIconGroup> mNetworkToIconLookup;
- // Since some pieces of the phone state are interdependent we store it locally,
- // this could potentially become part of MobileState for simplification/complication
- // of code.
- private int mDataState = TelephonyManager.DATA_DISCONNECTED;
- private TelephonyDisplayInfo mTelephonyDisplayInfo =
- new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_UNKNOWN,
- TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE);
- private ServiceState mServiceState;
- private SignalStrength mSignalStrength;
private int mLastLevel;
private MobileIconGroup mDefaultIcons;
private Config mConfig;
@@ -468,16 +453,8 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
return new MobileState();
}
- private boolean isCdma() {
- return (mSignalStrength != null) && !mSignalStrength.isGsm();
- }
-
- public boolean isEmergencyOnly() {
- return (mServiceState != null && mServiceState.isEmergencyOnly());
- }
-
public boolean isInService() {
- return Utils.isInService(mServiceState);
+ return mCurrentState.isInService();
}
String getNetworkNameForCarrierWiFi() {
@@ -485,15 +462,15 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
}
private boolean isRoaming() {
- // During a carrier change, roaming indications need to be supressed.
+ // During a carrier change, roaming indications need to be suppressed.
if (isCarrierNetworkChangeActive()) {
return false;
}
- if (isCdma()) {
+ if (mCurrentState.isCdma()) {
return mPhone.getCdmaEnhancedRoamingIndicatorDisplayNumber()
!= TelephonyManager.ERI_OFF;
} else {
- return mServiceState != null && mServiceState.getRoaming();
+ return mCurrentState.isRoaming();
}
}
@@ -585,27 +562,29 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
}
private void updateMobileStatus(MobileStatus mobileStatus) {
- mCurrentState.activityIn = mobileStatus.activityIn;
- mCurrentState.activityOut = mobileStatus.activityOut;
- mCurrentState.dataSim = mobileStatus.dataSim;
- mCurrentState.carrierNetworkChangeMode = mobileStatus.carrierNetworkChangeMode;
- mDataState = mobileStatus.dataState;
+ int lastVoiceState = mCurrentState.getVoiceServiceState();
+ mCurrentState.setFromMobileStatus(mobileStatus);
+
notifyMobileLevelChangeIfNecessary(mobileStatus.signalStrength);
- mSignalStrength = mobileStatus.signalStrength;
- mTelephonyDisplayInfo = mobileStatus.telephonyDisplayInfo;
- int lastVoiceState = mServiceState != null ? mServiceState.getState() : -1;
- mServiceState = mobileStatus.serviceState;
- int currentVoiceState = mServiceState != null ? mServiceState.getState() : -1;
+ if (mProviderModelBehavior) {
+ maybeNotifyCallStateChanged(lastVoiceState);
+ }
+ }
+
+ /** Call state changed is only applicable when provider model behavior is true */
+ private void maybeNotifyCallStateChanged(int lastVoiceState) {
+ int currentVoiceState = mCurrentState.getVoiceServiceState();
+ if (lastVoiceState == currentVoiceState) {
+ return;
+ }
// Only update the no calling Status in the below scenarios
// 1. The first valid voice state has been received
// 2. The voice state has been changed and either the last or current state is
// ServiceState.STATE_IN_SERVICE
- if (mProviderModelBehavior
- && lastVoiceState != currentVoiceState
- && (lastVoiceState == -1
- || (lastVoiceState == ServiceState.STATE_IN_SERVICE
- || currentVoiceState == ServiceState.STATE_IN_SERVICE))) {
- boolean isNoCalling = currentVoiceState != ServiceState.STATE_IN_SERVICE;
+ if (lastVoiceState == -1
+ || (lastVoiceState == ServiceState.STATE_IN_SERVICE
+ || currentVoiceState == ServiceState.STATE_IN_SERVICE)) {
+ boolean isNoCalling = mCurrentState.isNoCalling();
isNoCalling &= !hideNoCalling();
IconState statusIcon = new IconState(isNoCalling,
R.drawable.ic_qs_no_calling_sms,
@@ -615,7 +594,7 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
}
void updateNoCallingState() {
- int currentVoiceState = mServiceState != null ? mServiceState.getState() : -1;
+ int currentVoiceState = mCurrentState.getVoiceServiceState();
boolean isNoCalling = currentVoiceState != ServiceState.STATE_IN_SERVICE;
isNoCalling &= !hideNoCalling();
IconState statusIcon = new IconState(isNoCalling,
@@ -643,8 +622,7 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
}
void refreshCallIndicator(SignalCallback callback) {
- boolean isNoCalling = mServiceState != null
- && mServiceState.getState() != ServiceState.STATE_IN_SERVICE;
+ boolean isNoCalling = mCurrentState.isNoCalling();
isNoCalling &= !hideNoCalling();
IconState statusIcon = new IconState(isNoCalling,
R.drawable.ic_qs_no_calling_sms,
@@ -736,30 +714,30 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
}
/**
- * Updates the current state based on mServiceState, mSignalStrength, mDataState,
- * mTelephonyDisplayInfo, and mSimState. It should be called any time one of these is updated.
+ * Updates the current state based on ServiceState, SignalStrength, DataState,
+ * TelephonyDisplayInfo, and sim state. It should be called any time one of these is updated.
* This will call listeners if necessary.
*/
private void updateTelephony() {
if (Log.isLoggable(mTag, Log.DEBUG)) {
Log.d(mTag, "updateTelephonySignalStrength: hasService="
- + Utils.isInService(mServiceState) + " ss=" + mSignalStrength
- + " displayInfo=" + mTelephonyDisplayInfo);
+ + mCurrentState.isInService()
+ + " ss=" + mCurrentState.signalStrength
+ + " displayInfo=" + mCurrentState.telephonyDisplayInfo);
}
checkDefaultData();
- mCurrentState.connected = Utils.isInService(mServiceState) && mSignalStrength != null;
+ mCurrentState.connected = mCurrentState.isInService();
if (mCurrentState.connected) {
- mCurrentState.level = getSignalLevel(mSignalStrength);
+ mCurrentState.level = getSignalLevel(mCurrentState.signalStrength);
}
- String iconKey = getIconKey(mTelephonyDisplayInfo);
+ String iconKey = getIconKey(mCurrentState.telephonyDisplayInfo);
if (mNetworkToIconLookup.get(iconKey) != null) {
mCurrentState.iconGroup = mNetworkToIconLookup.get(iconKey);
} else {
mCurrentState.iconGroup = mDefaultIcons;
}
- mCurrentState.dataConnected = mCurrentState.connected
- && mDataState == TelephonyManager.DATA_CONNECTED;
+ mCurrentState.dataConnected = mCurrentState.isDataConnected();
mCurrentState.roaming = isRoaming();
if (isCarrierNetworkChangeActive()) {
@@ -771,20 +749,20 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED;
}
}
- if (isEmergencyOnly() != mCurrentState.isEmergency) {
- mCurrentState.isEmergency = isEmergencyOnly();
+ if (mCurrentState.isEmergencyOnly() != mCurrentState.isEmergency) {
+ mCurrentState.isEmergency = mCurrentState.isEmergencyOnly();
mNetworkController.recalculateEmergency();
}
// Fill in the network name if we think we have it.
- if (mCurrentState.networkName.equals(mNetworkNameDefault) && mServiceState != null
- && !TextUtils.isEmpty(mServiceState.getOperatorAlphaShort())) {
- mCurrentState.networkName = mServiceState.getOperatorAlphaShort();
+ if (mCurrentState.networkName.equals(mNetworkNameDefault)
+ && !TextUtils.isEmpty(mCurrentState.getOperatorAlphaShort())) {
+ mCurrentState.networkName = mCurrentState.getOperatorAlphaShort();
}
// If this is the data subscription, update the currentState data name
- if (mCurrentState.networkNameData.equals(mNetworkNameDefault) && mServiceState != null
+ if (mCurrentState.networkNameData.equals(mNetworkNameDefault)
&& mCurrentState.dataSim
- && !TextUtils.isEmpty(mServiceState.getOperatorAlphaShort())) {
- mCurrentState.networkNameData = mServiceState.getOperatorAlphaShort();
+ && !TextUtils.isEmpty(mCurrentState.getOperatorAlphaShort())) {
+ mCurrentState.networkNameData = mCurrentState.getOperatorAlphaShort();
}
notifyListenersIfNecessary();
@@ -836,10 +814,6 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
pw.println(" mSubscription=" + mSubscriptionInfo + ",");
pw.println(" mProviderModelSetting=" + mProviderModelSetting + ",");
pw.println(" mProviderModelBehavior=" + mProviderModelBehavior + ",");
- pw.println(" mServiceState=" + mServiceState + ",");
- pw.println(" mSignalStrength=" + mSignalStrength + ",");
- pw.println(" mTelephonyDisplayInfo=" + mTelephonyDisplayInfo + ",");
- pw.println(" mDataState=" + mDataState + ",");
pw.println(" mInflateSignalStrengths=" + mInflateSignalStrengths + ",");
pw.println(" isDataDisabled=" + isDataDisabled() + ",");
pw.println(" mNetworkToIconLookup=" + mNetworkToIconLookup + ",");
@@ -884,5 +858,4 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
icon = iconState;
}
}
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileState.kt b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileState.kt
new file mode 100644
index 000000000000..8a3b00662900
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileState.kt
@@ -0,0 +1,225 @@
+/*
+ * 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.connectivity
+
+import android.telephony.ServiceState
+import android.telephony.SignalStrength
+import android.telephony.TelephonyDisplayInfo
+import android.telephony.TelephonyManager
+import com.android.settingslib.Utils
+import com.android.settingslib.mobile.MobileStatusTracker.MobileStatus
+import com.android.settingslib.mobile.TelephonyIcons
+import java.lang.IllegalArgumentException
+
+/**
+ * Box for all policy-related state used in [MobileSignalController]
+ */
+internal class MobileState(
+ @JvmField var networkName: String? = null,
+ @JvmField var networkNameData: String? = null,
+ @JvmField var dataSim: Boolean = false,
+ @JvmField var dataConnected: Boolean = false,
+ @JvmField var isEmergency: Boolean = false,
+ @JvmField var airplaneMode: Boolean = false,
+ @JvmField var carrierNetworkChangeMode: Boolean = false,
+ @JvmField var isDefault: Boolean = false,
+ @JvmField var userSetup: Boolean = false,
+ @JvmField var roaming: Boolean = false,
+ @JvmField var dataState: Int = TelephonyManager.DATA_DISCONNECTED,
+ // Tracks the on/off state of the defaultDataSubscription
+ @JvmField var defaultDataOff: Boolean = false
+) : ConnectivityState() {
+
+ @JvmField var telephonyDisplayInfo = TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE)
+ @JvmField var serviceState: ServiceState? = null
+ @JvmField var signalStrength: SignalStrength? = null
+
+ /** @return true if this state is disabled or not default data */
+ val isDataDisabledOrNotDefault: Boolean
+ get() = (iconGroup === TelephonyIcons.DATA_DISABLED ||
+ iconGroup === TelephonyIcons.NOT_DEFAULT_DATA) && userSetup
+
+ /** @return if this state is considered to have inbound activity */
+ fun hasActivityIn(): Boolean {
+ return dataConnected && !carrierNetworkChangeMode && activityIn
+ }
+
+ /** @return if this state is considered to have outbound activity */
+ fun hasActivityOut(): Boolean {
+ return dataConnected && !carrierNetworkChangeMode && activityOut
+ }
+
+ /** @return true if this state should show a RAT icon in quick settings */
+ fun showQuickSettingsRatIcon(): Boolean {
+ return dataConnected || isDataDisabledOrNotDefault
+ }
+
+ override fun copyFrom(other: ConnectivityState) {
+ val o = other as? MobileState ?: throw IllegalArgumentException(
+ "MobileState can only update from another MobileState")
+
+ super.copyFrom(o)
+ networkName = o.networkName
+ networkNameData = o.networkNameData
+ dataSim = o.dataSim
+ dataConnected = o.dataConnected
+ isEmergency = o.isEmergency
+ airplaneMode = o.airplaneMode
+ carrierNetworkChangeMode = o.carrierNetworkChangeMode
+ isDefault = o.isDefault
+ userSetup = o.userSetup
+ roaming = o.roaming
+ dataState = o.dataState
+ defaultDataOff = o.defaultDataOff
+
+ telephonyDisplayInfo = o.telephonyDisplayInfo
+ serviceState = o.serviceState
+ signalStrength = o.signalStrength
+ }
+
+ fun isDataConnected(): Boolean {
+ return connected && dataState == TelephonyManager.DATA_CONNECTED
+ }
+
+ /** @return the current voice service state, or -1 if null */
+ fun getVoiceServiceState(): Int {
+ return serviceState?.state ?: -1
+ }
+
+ fun isNoCalling(): Boolean {
+ return serviceState?.state != ServiceState.STATE_IN_SERVICE
+ }
+
+ fun getOperatorAlphaShort(): String {
+ return serviceState?.operatorAlphaShort ?: ""
+ }
+
+ fun isCdma(): Boolean {
+ return signalStrength != null && !signalStrength!!.isGsm
+ }
+
+ fun isEmergencyOnly(): Boolean {
+ return serviceState != null && serviceState!!.isEmergencyOnly
+ }
+
+ fun isInService(): Boolean {
+ return Utils.isInService(serviceState)
+ }
+
+ fun isRoaming(): Boolean {
+ return serviceState != null && serviceState!!.roaming
+ }
+
+ fun setFromMobileStatus(mobileStatus: MobileStatus) {
+ activityIn = mobileStatus.activityIn
+ activityOut = mobileStatus.activityOut
+ dataSim = mobileStatus.dataSim
+ carrierNetworkChangeMode = mobileStatus.carrierNetworkChangeMode
+ dataState = mobileStatus.dataState
+ signalStrength = mobileStatus.signalStrength
+ telephonyDisplayInfo = mobileStatus.telephonyDisplayInfo
+ serviceState = mobileStatus.serviceState
+ }
+
+ override fun toString(builder: StringBuilder) {
+ super.toString(builder)
+ builder.append(',')
+ builder.append("dataSim=$dataSim,")
+ builder.append("networkName=$networkName,")
+ builder.append("networkNameData=$networkNameData,")
+ builder.append("dataConnected=$dataConnected,")
+ builder.append("roaming=$roaming,")
+ builder.append("isDefault=$isDefault,")
+ builder.append("isEmergency=$isEmergency,")
+ builder.append("airplaneMode=$airplaneMode,")
+ builder.append("carrierNetworkChangeMode=$carrierNetworkChangeMode,")
+ builder.append("userSetup=$userSetup,")
+ builder.append("dataState=$dataState,")
+ builder.append("defaultDataOff=$defaultDataOff,")
+
+ // Computed properties
+ builder.append("showQuickSettingsRatIcon=${showQuickSettingsRatIcon()},")
+ builder.append("voiceServiceState=${getVoiceServiceState()},")
+ builder.append("isInService=${isInService()},")
+
+ builder.append("serviceState=${serviceState?.minLog() ?: "(null)"},")
+ builder.append("signalStrength=${signalStrength?.minLog() ?: "(null)"},")
+ builder.append("displayInfo=$telephonyDisplayInfo")
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+ if (!super.equals(other)) return false
+
+ other as MobileState
+
+ if (networkName != other.networkName) return false
+ if (networkNameData != other.networkNameData) return false
+ if (dataSim != other.dataSim) return false
+ if (dataConnected != other.dataConnected) return false
+ if (isEmergency != other.isEmergency) return false
+ if (airplaneMode != other.airplaneMode) return false
+ if (carrierNetworkChangeMode != other.carrierNetworkChangeMode) return false
+ if (isDefault != other.isDefault) return false
+ if (userSetup != other.userSetup) return false
+ if (roaming != other.roaming) return false
+ if (dataState != other.dataState) return false
+ if (defaultDataOff != other.defaultDataOff) return false
+ if (telephonyDisplayInfo != other.telephonyDisplayInfo) return false
+ if (serviceState != other.serviceState) return false
+ if (signalStrength != other.signalStrength) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = super.hashCode()
+ result = 31 * result + (networkName?.hashCode() ?: 0)
+ result = 31 * result + (networkNameData?.hashCode() ?: 0)
+ result = 31 * result + dataSim.hashCode()
+ result = 31 * result + dataConnected.hashCode()
+ result = 31 * result + isEmergency.hashCode()
+ result = 31 * result + airplaneMode.hashCode()
+ result = 31 * result + carrierNetworkChangeMode.hashCode()
+ result = 31 * result + isDefault.hashCode()
+ result = 31 * result + userSetup.hashCode()
+ result = 31 * result + roaming.hashCode()
+ result = 31 * result + dataState
+ result = 31 * result + defaultDataOff.hashCode()
+ result = 31 * result + telephonyDisplayInfo.hashCode()
+ result = 31 * result + (serviceState?.hashCode() ?: 0)
+ result = 31 * result + (signalStrength?.hashCode() ?: 0)
+ return result
+ }
+}
+
+/** toString() is a little more verbose than we need. Just log the fields we read */
+private fun ServiceState.minLog(): String {
+ return "serviceState={" +
+ "state=$state," +
+ "isEmergencyOnly=$isEmergencyOnly," +
+ "roaming=$roaming," +
+ "operatorNameAlphaShort=$operatorAlphaShort}"
+}
+
+private fun SignalStrength.minLog(): String {
+ return "signalStrength={" +
+ "isGsm=$isGsm," +
+ "level=$level}"
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkController.java
index 143309658779..f960eb7b6e9b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkController.java
@@ -16,19 +16,10 @@
package com.android.systemui.statusbar.connectivity;
-import android.content.Context;
-import android.content.Intent;
-import android.telephony.SubscriptionInfo;
-
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.demomode.DemoMode;
-import com.android.systemui.statusbar.connectivity.NetworkController.SignalCallback;
import com.android.systemui.statusbar.policy.CallbackController;
import com.android.systemui.statusbar.policy.DataSaverController;
-import com.android.wifitrackerlib.MergedCarrierEntry;
-import com.android.wifitrackerlib.WifiEntry;
-
-import java.util.List;
/** */
public interface NetworkController extends CallbackController<SignalCallback>, DemoMode {
@@ -62,197 +53,8 @@ public interface NetworkController extends CallbackController<SignalCallback>, D
/** */
boolean isRadioOn();
- /**
- * Wrapper class for all the WiFi signals used for WiFi indicators.
- */
- final class WifiIndicators {
- public boolean enabled;
- public IconState statusIcon;
- public IconState qsIcon;
- public boolean activityIn;
- public boolean activityOut;
- public String description;
- public boolean isTransient;
- public String statusLabel;
-
- public WifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
- boolean activityIn, boolean activityOut, String description,
- boolean isTransient, String statusLabel) {
- this.enabled = enabled;
- this.statusIcon = statusIcon;
- this.qsIcon = qsIcon;
- this.activityIn = activityIn;
- this.activityOut = activityOut;
- this.description = description;
- this.isTransient = isTransient;
- this.statusLabel = statusLabel;
- }
-
- @Override
- public String toString() {
- return new StringBuilder("WifiIndicators[")
- .append("enabled=").append(enabled)
- .append(",statusIcon=").append(statusIcon == null ? "" : statusIcon.toString())
- .append(",qsIcon=").append(qsIcon == null ? "" : qsIcon.toString())
- .append(",activityIn=").append(activityIn)
- .append(",activityOut=").append(activityOut)
- .append(",qsDescription=").append(description)
- .append(",isTransient=").append(isTransient)
- .append(",statusLabel=").append(statusLabel)
- .append(']').toString();
- }
- }
-
- /**
- * Wrapper class for all the mobile signals used for mobile data indicators.
- */
- final class MobileDataIndicators {
- public IconState statusIcon;
- public IconState qsIcon;
- public int statusType;
- public int qsType;
- public boolean activityIn;
- public boolean activityOut;
- public CharSequence typeContentDescription;
- public CharSequence typeContentDescriptionHtml;
- public CharSequence qsDescription;
- public int subId;
- public boolean roaming;
- public boolean showTriangle;
-
- public MobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
- int qsType, boolean activityIn, boolean activityOut,
- CharSequence typeContentDescription, CharSequence typeContentDescriptionHtml,
- CharSequence qsDescription, int subId, boolean roaming,
- boolean showTriangle) {
- this.statusIcon = statusIcon;
- this.qsIcon = qsIcon;
- this.statusType = statusType;
- this.qsType = qsType;
- this.activityIn = activityIn;
- this.activityOut = activityOut;
- this.typeContentDescription = typeContentDescription;
- this.typeContentDescriptionHtml = typeContentDescriptionHtml;
- this.qsDescription = qsDescription;
- this.subId = subId;
- this.roaming = roaming;
- this.showTriangle = showTriangle;
- }
-
- @Override
- public String toString() {
- return new StringBuilder("MobileDataIndicators[")
- .append("statusIcon=").append(statusIcon == null ? "" : statusIcon.toString())
- .append(",qsIcon=").append(qsIcon == null ? "" : qsIcon.toString())
- .append(",statusType=").append(statusType)
- .append(",qsType=").append(qsType)
- .append(",activityIn=").append(activityIn)
- .append(",activityOut=").append(activityOut)
- .append(",typeContentDescription=").append(typeContentDescription)
- .append(",typeContentDescriptionHtml=").append(typeContentDescriptionHtml)
- .append(",description=").append(qsDescription)
- .append(",subId=").append(subId)
- .append(",roaming=").append(roaming)
- .append(",showTriangle=").append(showTriangle)
- .append(']').toString();
- }
- }
-
- /** */
- interface SignalCallback {
- /**
- * Callback for listeners to be able to update the state of any UI tracking connectivity of
- * WiFi networks.
- */
- default void setWifiIndicators(WifiIndicators wifiIndicators) {}
-
- /**
- * Callback for listeners to be able to update the state of any UI tracking connectivity
- * of Mobile networks.
- */
- default void setMobileDataIndicators(MobileDataIndicators mobileDataIndicators) {}
-
- /** */
- default void setSubs(List<SubscriptionInfo> subs) {}
-
- /** */
- default void setNoSims(boolean show, boolean simDetected) {}
-
- /** */
- default void setEthernetIndicators(IconState icon) {}
-
- /** */
- default void setIsAirplaneMode(IconState icon) {}
-
- /** */
- default void setMobileDataEnabled(boolean enabled) {}
-
- /**
- * Callback for listeners to be able to update the connectivity status
- * @param noDefaultNetwork whether there is any default network.
- * @param noValidatedNetwork whether there is any validated network.
- * @param noNetworksAvailable whether there is any WiFi networks available.
- */
- default void setConnectivityStatus(boolean noDefaultNetwork, boolean noValidatedNetwork,
- boolean noNetworksAvailable) {}
-
- /**
- * Callback for listeners to be able to update the call indicator
- * @param statusIcon the icon for the call indicator
- * @param subId subscription ID for which to update the UI
- */
- default void setCallIndicator(IconState statusIcon, int subId) {}
- }
-
/** */
interface EmergencyListener {
void setEmergencyCallsOnly(boolean emergencyOnly);
}
-
- /** */
- class IconState {
- public final boolean visible;
- public final int icon;
- public final String contentDescription;
-
- public IconState(boolean visible, int icon, String contentDescription) {
- this.visible = visible;
- this.icon = icon;
- this.contentDescription = contentDescription;
- }
-
- public IconState(boolean visible, int icon, int contentDescription,
- Context context) {
- this(visible, icon, context.getString(contentDescription));
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- return builder.append("[visible=").append(visible).append(',')
- .append("icon=").append(icon).append(',')
- .append("contentDescription=").append(contentDescription).append(']')
- .toString();
- }
- }
-
- /**
- * Tracks changes in access points. Allows listening for changes, scanning for new APs,
- * and connecting to new ones.
- */
- interface AccessPointController {
- void addAccessPointCallback(AccessPointCallback callback);
- void removeAccessPointCallback(AccessPointCallback callback);
- void scanForAccessPoints();
- MergedCarrierEntry getMergedCarrierEntry();
- int getIcon(WifiEntry ap);
- boolean connect(WifiEntry ap);
- boolean canConfigWifi();
- boolean canConfigMobileData();
-
- interface AccessPointCallback {
- void onAccessPointsChanged(List<WifiEntry> accessPoints);
- void onSettingsActivityTriggered(Intent settingsIntent);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
index f72178f0c8b0..3f5ef4806a1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
@@ -721,8 +721,11 @@ public class NetworkControllerImpl extends BroadcastReceiver
@Override
public void addCallback(@NonNull SignalCallback cb) {
cb.setSubs(mCurrentSubscriptions);
- cb.setIsAirplaneMode(new IconState(mAirplaneMode,
- TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext));
+ cb.setIsAirplaneMode(
+ new IconState(
+ mAirplaneMode,
+ TelephonyIcons.FLIGHT_MODE_ICON,
+ mContext.getString(R.string.accessibility_airplane_mode)));
cb.setNoSims(mHasNoSubs, mSimDetected);
if (mProviderModelSetting) {
cb.setConnectivityStatus(mNoDefaultNetwork, !mInetCondition, mNoNetworksAvailable);
@@ -811,7 +814,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
break;
case Settings.Panel.ACTION_INTERNET_CONNECTIVITY:
mMainHandler.post(() -> mInternetDialogFactory.create(true,
- mAccessPoints.canConfigMobileData(), mAccessPoints.canConfigWifi()));
+ mAccessPoints.canConfigMobileData(), mAccessPoints.canConfigWifi(),
+ null /* view */));
break;
default:
int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
@@ -1055,8 +1059,11 @@ public class NetworkControllerImpl extends BroadcastReceiver
* notifyAllListeners.
*/
private void notifyListeners() {
- mCallbackHandler.setIsAirplaneMode(new IconState(mAirplaneMode,
- TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext));
+ mCallbackHandler.setIsAirplaneMode(
+ new IconState(
+ mAirplaneMode,
+ TelephonyIcons.FLIGHT_MODE_ICON,
+ mContext.getString(R.string.accessibility_airplane_mode)));
mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected);
}
@@ -1205,7 +1212,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
}
private boolean mDemoInetCondition;
- private WifiSignalController.WifiState mDemoWifiState;
+ private WifiState mDemoWifiState;
@Override
public void onDemoModeStarted() {
@@ -1240,9 +1247,11 @@ public class NetworkControllerImpl extends BroadcastReceiver
String airplane = args.getString("airplane");
if (airplane != null) {
boolean show = airplane.equals("show");
- mCallbackHandler.setIsAirplaneMode(new IconState(show,
- TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode,
- mContext));
+ mCallbackHandler.setIsAirplaneMode(
+ new IconState(
+ show,
+ TelephonyIcons.FLIGHT_MODE_ICON,
+ mContext.getString(R.string.accessibility_airplane_mode)));
}
String fully = args.getString("fully");
if (fully != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/SignalCallback.kt b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/SignalCallback.kt
new file mode 100644
index 000000000000..599beecb0e00
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/SignalCallback.kt
@@ -0,0 +1,187 @@
+/*
+ * 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.connectivity
+
+import android.telephony.SubscriptionInfo
+
+/**
+ * SignalCallback contains all of the connectivity updates from [NetworkController]. Implement this
+ * interface to be able to draw iconography for Wi-Fi, mobile data, ethernet, call strength
+ * indicators, etc.
+ */
+interface SignalCallback {
+ /**
+ * Called when the Wi-Fi iconography has been updated. Implement this method to draw Wi-Fi icons
+ *
+ * @param wifiIndicators a box type containing enough information to properly draw a Wi-Fi icon
+ */
+ @JvmDefault
+ fun setWifiIndicators(wifiIndicators: WifiIndicators) {}
+
+ /**
+ * Called when the mobile iconography has been updated. Implement this method to draw mobile
+ * indicators
+ *
+ * @param mobileDataIndicators a box type containing enough information to properly draw
+ * mobile data icons
+ *
+ * NOTE: phones can have multiple subscriptions, so this [mobileDataIndicators] object should be
+ * indexed based on its [subId][MobileDataIndicators.subId]
+ */
+ @JvmDefault
+ fun setMobileDataIndicators(mobileDataIndicators: MobileDataIndicators) {}
+
+ /**
+ * Called when the list of mobile data subscriptions has changed. Use this method as a chance
+ * to remove views that are no longer needed, or to make room for new icons to come in
+ *
+ * @param subs a [SubscriptionInfo] for each subscription that we know about
+ */
+ @JvmDefault
+ fun setSubs(subs: List<@JvmSuppressWildcards SubscriptionInfo>) {}
+
+ /**
+ * Called when:
+ * 1. The number of [MobileSignalController]s goes to 0 while mobile data is enabled
+ * OR
+ * 2. The presence of any SIM changes
+ *
+ * @param show whether or not to show a "no sim" view
+ * @param simDetected whether any SIM is detected or not
+ */
+ @JvmDefault
+ fun setNoSims(show: Boolean, simDetected: Boolean) {}
+
+ /**
+ * Called when there is any update to the ethernet iconography. Implement this method to set an
+ * ethernet icon
+ *
+ * @param icon an [IconState] for the current ethernet status
+ */
+ @JvmDefault
+ fun setEthernetIndicators(icon: IconState) {}
+
+ /**
+ * Called whenever airplane mode changes
+ *
+ * @param icon an [IconState] for the current airplane mode status
+ */
+ @JvmDefault
+ fun setIsAirplaneMode(icon: IconState) {}
+
+ /**
+ * Called whenever the mobile data feature enabled state changes
+ *
+ * @param enabled the current mobile data feature ennabled state
+ */
+ @JvmDefault
+ fun setMobileDataEnabled(enabled: Boolean) {}
+
+ /**
+ * Callback for listeners to be able to update the connectivity status
+ * @param noDefaultNetwork whether there is any default network.
+ * @param noValidatedNetwork whether there is any validated network.
+ * @param noNetworksAvailable whether there is any WiFi networks available.
+ */
+ @JvmDefault
+ fun setConnectivityStatus(
+ noDefaultNetwork: Boolean,
+ noValidatedNetwork: Boolean,
+ noNetworksAvailable: Boolean
+ ) { }
+
+ /**
+ * Callback for listeners to be able to update the call indicator
+ * @param statusIcon the icon for the call indicator
+ * @param subId subscription ID for which to update the UI
+ */
+ @JvmDefault
+ fun setCallIndicator(statusIcon: IconState, subId: Int) {}
+}
+
+/** Box type for [SignalCallback.setWifiIndicators] */
+data class WifiIndicators(
+ @JvmField val enabled: Boolean,
+ @JvmField val statusIcon: IconState?,
+ @JvmField val qsIcon: IconState?,
+ @JvmField val activityIn: Boolean,
+ @JvmField val activityOut: Boolean,
+ @JvmField val description: String?,
+ @JvmField val isTransient: Boolean,
+ @JvmField val statusLabel: String?
+) {
+ override fun toString(): String {
+ return StringBuilder("WifiIndicators[")
+ .append("enabled=").append(enabled)
+ .append(",statusIcon=").append(statusIcon?.toString() ?: "")
+ .append(",qsIcon=").append(qsIcon?.toString() ?: "")
+ .append(",activityIn=").append(activityIn)
+ .append(",activityOut=").append(activityOut)
+ .append(",qsDescription=").append(description)
+ .append(",isTransient=").append(isTransient)
+ .append(",statusLabel=").append(statusLabel)
+ .append(']').toString()
+ }
+}
+
+/** Box type for [SignalCallback.setMobileDataIndicators] */
+data class MobileDataIndicators(
+ @JvmField val statusIcon: IconState?,
+ @JvmField val qsIcon: IconState?,
+ @JvmField val statusType: Int,
+ @JvmField val qsType: Int,
+ @JvmField val activityIn: Boolean,
+ @JvmField val activityOut: Boolean,
+ @JvmField val typeContentDescription: CharSequence?,
+ @JvmField val typeContentDescriptionHtml: CharSequence?,
+ @JvmField val qsDescription: CharSequence?,
+ @JvmField val subId: Int,
+ @JvmField val roaming: Boolean,
+ @JvmField val showTriangle: Boolean
+) {
+ override fun toString(): String {
+ return java.lang.StringBuilder("MobileDataIndicators[")
+ .append("statusIcon=").append(statusIcon?.toString() ?: "")
+ .append(",qsIcon=").append(qsIcon?.toString() ?: "")
+ .append(",statusType=").append(statusType)
+ .append(",qsType=").append(qsType)
+ .append(",activityIn=").append(activityIn)
+ .append(",activityOut=").append(activityOut)
+ .append(",typeContentDescription=").append(typeContentDescription)
+ .append(",typeContentDescriptionHtml=").append(typeContentDescriptionHtml)
+ .append(",description=").append(qsDescription)
+ .append(",subId=").append(subId)
+ .append(",roaming=").append(roaming)
+ .append(",showTriangle=").append(showTriangle)
+ .append(']').toString()
+ }
+}
+
+/** Box for an icon with its visibility and content description */
+data class IconState(
+ @JvmField val visible: Boolean,
+ @JvmField val icon: Int,
+ @JvmField val contentDescription: String
+) {
+ override fun toString(): String {
+ val builder = java.lang.StringBuilder()
+ return builder.append("[visible=").append(visible).append(',')
+ .append("icon=").append(icon).append(',')
+ .append("contentDescription=").append(contentDescription).append(']')
+ .toString()
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/SignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/SignalController.java
index d23dba579be6..cd2006899cfc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/SignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/SignalController.java
@@ -22,9 +22,6 @@ import android.content.Context;
import android.util.Log;
import com.android.settingslib.SignalIcon.IconGroup;
-import com.android.settingslib.SignalIcon.State;
-import com.android.systemui.statusbar.connectivity.NetworkController.IconState;
-import com.android.systemui.statusbar.connectivity.NetworkController.SignalCallback;
import java.io.PrintWriter;
import java.util.BitSet;
@@ -36,7 +33,7 @@ import java.util.BitSet;
* @param <T> State of the SysUI controller.
* @param <I> Icon groups of the SysUI controller for a given State.
*/
-public abstract class SignalController<T extends State, I extends IconGroup> {
+public abstract class SignalController<T extends ConnectivityState, I extends IconGroup> {
// Save the previous SignalController.States of all SignalControllers for dumps.
static final boolean RECORD_HISTORY = true;
// If RECORD_HISTORY how many to save, must be a power of 2.
@@ -58,7 +55,7 @@ public abstract class SignalController<T extends State, I extends IconGroup> {
private final CallbackHandler mCallbackHandler;
// Save the previous HISTORY_SIZE states for logging.
- private final State[] mHistory;
+ private final ConnectivityState[] mHistory;
// Where to copy the next state into.
private int mHistoryIndex;
@@ -72,7 +69,7 @@ public abstract class SignalController<T extends State, I extends IconGroup> {
mCurrentState = cleanState();
mLastState = cleanState();
if (RECORD_HISTORY) {
- mHistory = new State[HISTORY_SIZE];
+ mHistory = new ConnectivityState[HISTORY_SIZE];
for (int i = 0; i < HISTORY_SIZE; i++) {
mHistory[i] = cleanState();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java
index 3622a66767a3..103ca0ebc6ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java
@@ -26,28 +26,20 @@ import android.net.NetworkCapabilities;
import android.net.NetworkScoreManager;
import android.net.wifi.WifiManager;
import android.text.Html;
-import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.SignalIcon.IconGroup;
import com.android.settingslib.SignalIcon.MobileIconGroup;
-import com.android.settingslib.SignalIcon.State;
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.flags.FeatureFlags;
-import com.android.systemui.statusbar.connectivity.NetworkController.IconState;
-import com.android.systemui.statusbar.connectivity.NetworkController.MobileDataIndicators;
-import com.android.systemui.statusbar.connectivity.NetworkController.SignalCallback;
-import com.android.systemui.statusbar.connectivity.NetworkController.WifiIndicators;
import java.io.PrintWriter;
-import java.util.Objects;
/** */
-public class WifiSignalController extends
- SignalController<WifiSignalController.WifiState, IconGroup> {
+public class WifiSignalController extends SignalController<WifiState, IconGroup> {
private final boolean mHasMobileDataFeature;
private final WifiStatusTracker mWifiTracker;
private final IconGroup mUnmergedWifiIconGroup = WifiIcons.UNMERGED_WIFI;
@@ -272,50 +264,4 @@ public class WifiSignalController extends
setActivity(state);
}
}
-
- static class WifiState extends State {
- public String ssid;
- public boolean isTransient;
- public boolean isDefault;
- public String statusLabel;
- public boolean isCarrierMerged;
- public int subId;
-
- @Override
- public void copyFrom(State s) {
- super.copyFrom(s);
- WifiState state = (WifiState) s;
- ssid = state.ssid;
- isTransient = state.isTransient;
- isDefault = state.isDefault;
- statusLabel = state.statusLabel;
- isCarrierMerged = state.isCarrierMerged;
- subId = state.subId;
- }
-
- @Override
- protected void toString(StringBuilder builder) {
- super.toString(builder);
- builder.append(",ssid=").append(ssid)
- .append(",isTransient=").append(isTransient)
- .append(",isDefault=").append(isDefault)
- .append(",statusLabel=").append(statusLabel)
- .append(",isCarrierMerged=").append(isCarrierMerged)
- .append(",subId=").append(subId);
- }
-
- @Override
- public boolean equals(Object o) {
- if (!super.equals(o)) {
- return false;
- }
- WifiState other = (WifiState) o;
- return Objects.equals(other.ssid, ssid)
- && other.isTransient == isTransient
- && other.isDefault == isDefault
- && TextUtils.equals(other.statusLabel, statusLabel)
- && other.isCarrierMerged == isCarrierMerged
- && other.subId == subId;
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiState.kt b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiState.kt
new file mode 100644
index 000000000000..ac15f78191f6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiState.kt
@@ -0,0 +1,78 @@
+/*
+ * 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.connectivity
+
+import java.lang.StringBuilder
+
+internal class WifiState(
+ @JvmField var ssid: String? = null,
+ @JvmField var isTransient: Boolean = false,
+ @JvmField var isDefault: Boolean = false,
+ @JvmField var statusLabel: String? = null,
+ @JvmField var isCarrierMerged: Boolean = false,
+ @JvmField var subId: Int = 0
+) : ConnectivityState() {
+
+ public override fun copyFrom(s: ConnectivityState) {
+ super.copyFrom(s)
+ val state = s as WifiState
+ ssid = state.ssid
+ isTransient = state.isTransient
+ isDefault = state.isDefault
+ statusLabel = state.statusLabel
+ isCarrierMerged = state.isCarrierMerged
+ subId = state.subId
+ }
+
+ override fun toString(builder: StringBuilder) {
+ super.toString(builder)
+ builder.append(",ssid=").append(ssid)
+ .append(",isTransient=").append(isTransient)
+ .append(",isDefault=").append(isDefault)
+ .append(",statusLabel=").append(statusLabel)
+ .append(",isCarrierMerged=").append(isCarrierMerged)
+ .append(",subId=").append(subId)
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+ if (!super.equals(other)) return false
+
+ other as WifiState
+
+ if (ssid != other.ssid) return false
+ if (isTransient != other.isTransient) return false
+ if (isDefault != other.isDefault) return false
+ if (statusLabel != other.statusLabel) return false
+ if (isCarrierMerged != other.isCarrierMerged) return false
+ if (subId != other.subId) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = super.hashCode()
+ result = 31 * result + (ssid?.hashCode() ?: 0)
+ result = 31 * result + isTransient.hashCode()
+ result = 31 * result + isDefault.hashCode()
+ result = 31 * result + (statusLabel?.hashCode() ?: 0)
+ result = 31 * result + isCarrierMerged.hashCode()
+ result = 31 * result + subId
+ return result
+ }
+}
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 d297d9581d6a..74ea19f4ca22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -43,6 +43,7 @@ import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
+import com.android.systemui.statusbar.RemoteInputNotificationRebuilder;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -66,11 +67,13 @@ import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
-import com.android.systemui.statusbar.phone.StatusBarWindowController;
import com.android.systemui.statusbar.phone.SystemUIHostDialogProvider;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLogger;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowModule;
+import com.android.systemui.statusbar.window.StatusBarWindowView;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.time.SystemClock;
@@ -96,9 +99,11 @@ public interface StatusBarDependenciesModule {
@Provides
static NotificationRemoteInputManager provideNotificationRemoteInputManager(
Context context,
+ FeatureFlags featureFlags,
NotificationLockscreenUserManager lockscreenUserManager,
SmartReplyController smartReplyController,
NotificationEntryManager notificationEntryManager,
+ RemoteInputNotificationRebuilder rebuilder,
Lazy<Optional<StatusBar>> statusBarOptionalLazy,
StatusBarStateController statusBarStateController,
Handler mainHandler,
@@ -108,9 +113,11 @@ public interface StatusBarDependenciesModule {
DumpManager dumpManager) {
return new NotificationRemoteInputManager(
context,
+ featureFlags,
lockscreenUserManager,
smartReplyController,
notificationEntryManager,
+ rebuilder,
statusBarOptionalLazy,
statusBarStateController,
mainHandler,
@@ -166,10 +173,11 @@ public interface StatusBarDependenciesModule {
@SysUISingleton
@Provides
static SmartReplyController provideSmartReplyController(
+ DumpManager dumpManager,
NotificationEntryManager entryManager,
IStatusBarService statusBarService,
NotificationClickNotifier clickNotifier) {
- return new SmartReplyController(entryManager, statusBarService, clickNotifier);
+ return new SmartReplyController(dumpManager, entryManager, statusBarService, clickNotifier);
}
@@ -184,6 +192,7 @@ public interface StatusBarDependenciesModule {
static NotificationViewHierarchyManager provideNotificationViewHierarchyManager(
Context context,
@Main Handler mainHandler,
+ FeatureFlags featureFlags,
NotificationLockscreenUserManager notificationLockscreenUserManager,
NotificationGroupManagerLegacy groupManager,
VisualStabilityManager visualStabilityManager,
@@ -199,6 +208,7 @@ public interface StatusBarDependenciesModule {
return new NotificationViewHierarchyManager(
context,
mainHandler,
+ featureFlags,
notificationLockscreenUserManager,
groupManager,
visualStabilityManager,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
index b97bac261ff0..3b118a34b5be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
@@ -393,11 +393,11 @@ class PrivacyDotViewController @Inject constructor(
animationScheduler.addCallback(systemStatusAnimationCallback)
}
- val left = contentInsetsProvider.getStatusBarContentInsetsForRotation(ROTATION_SEASCAPE)
- val top = contentInsetsProvider.getStatusBarContentInsetsForRotation(ROTATION_NONE)
- val right = contentInsetsProvider.getStatusBarContentInsetsForRotation(ROTATION_LANDSCAPE)
+ val left = contentInsetsProvider.getStatusBarContentAreaForRotation(ROTATION_SEASCAPE)
+ val top = contentInsetsProvider.getStatusBarContentAreaForRotation(ROTATION_NONE)
+ val right = contentInsetsProvider.getStatusBarContentAreaForRotation(ROTATION_LANDSCAPE)
val bottom = contentInsetsProvider
- .getStatusBarContentInsetsForRotation(ROTATION_UPSIDE_DOWN)
+ .getStatusBarContentAreaForRotation(ROTATION_UPSIDE_DOWN)
val paddingTop = contentInsetsProvider.getStatusBarPaddingTop()
synchronized(lock) {
@@ -528,11 +528,11 @@ class PrivacyDotViewController @Inject constructor(
// Returns [left, top, right, bottom] aka [seascape, none, landscape, upside-down]
private fun getLayoutRects(): List<Rect> {
- val left = contentInsetsProvider.getStatusBarContentInsetsForRotation(ROTATION_SEASCAPE)
- val top = contentInsetsProvider.getStatusBarContentInsetsForRotation(ROTATION_NONE)
- val right = contentInsetsProvider.getStatusBarContentInsetsForRotation(ROTATION_LANDSCAPE)
+ val left = contentInsetsProvider.getStatusBarContentAreaForRotation(ROTATION_SEASCAPE)
+ val top = contentInsetsProvider.getStatusBarContentAreaForRotation(ROTATION_NONE)
+ val right = contentInsetsProvider.getStatusBarContentAreaForRotation(ROTATION_LANDSCAPE)
val bottom = contentInsetsProvider
- .getStatusBarContentInsetsForRotation(ROTATION_UPSIDE_DOWN)
+ .getStatusBarContentAreaForRotation(ROTATION_UPSIDE_DOWN)
return listOf(left, top, right, bottom)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
index 589446f3b075..d5a0467c9b9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
@@ -26,8 +26,7 @@ import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.widget.FrameLayout
import com.android.systemui.R
import com.android.systemui.statusbar.phone.StatusBarLocationPublisher
-import com.android.systemui.statusbar.phone.StatusBarWindowController
-import com.android.systemui.statusbar.phone.StatusBarWindowView
+import com.android.systemui.statusbar.window.StatusBarWindowController
import javax.inject.Inject
/**
@@ -35,7 +34,6 @@ import javax.inject.Inject
*/
class SystemEventChipAnimationController @Inject constructor(
private val context: Context,
- private val statusBarWindowView: StatusBarWindowView,
private val statusBarWindowController: StatusBarWindowController,
private val locationPublisher: StatusBarLocationPublisher
) : SystemStatusChipAnimationCallback {
@@ -126,7 +124,7 @@ class SystemEventChipAnimationController @Inject constructor(
animationDotView = animationWindowView.findViewById(R.id.dot_view)
val lp = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
lp.gravity = Gravity.END or Gravity.CENTER_VERTICAL
- statusBarWindowView.addView(animationWindowView, lp)
+ statusBarWindowController.addViewToWindow(animationWindowView, lp)
}
private fun start() = if (animationWindowView.isLayoutRtl) right() else left()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
index dcf8e739a76e..5a273294e87c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
@@ -31,8 +31,8 @@ import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
-import com.android.systemui.statusbar.phone.StatusBarWindowController
import com.android.systemui.statusbar.policy.CallbackController
+import com.android.systemui.statusbar.window.StatusBarWindowController
import com.android.systemui.util.Assert
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.time.SystemClock
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
index 80577ee24317..7cdf69d1ecbf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
@@ -26,7 +26,7 @@ import android.view.MotionEvent.*
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.shared.system.InputChannelCompat
import com.android.systemui.shared.system.InputMonitorCompat
-import com.android.systemui.statusbar.phone.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowController
import javax.inject.Inject
/**
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 bacb85ae89df..4e5bc8e7d099 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -188,13 +188,23 @@ class LockscreenSmartspaceController @Inject constructor(
val ssView = plugin.getView(parent)
ssView.registerDataProvider(plugin)
+
ssView.setIntentStarter(object : BcSmartspaceDataPlugin.IntentStarter {
- override fun startIntent(v: View?, i: Intent?) {
- activityStarter.startActivity(i, true /* dismissShade */)
+ override fun startIntent(view: View, intent: Intent, showOnLockscreen: Boolean) {
+ activityStarter.startActivity(
+ intent,
+ true, /* dismissShade */
+ null, /* launch animator - looks bad with the transparent smartspace bg */
+ showOnLockscreen
+ )
}
- override fun startPendingIntent(pi: PendingIntent?) {
- activityStarter.startPendingIntentDismissingKeyguard(pi)
+ override fun startPendingIntent(pi: PendingIntent, showOnLockscreen: Boolean) {
+ if (showOnLockscreen) {
+ pi.send()
+ } else {
+ activityStarter.startPendingIntentDismissingKeyguard(pi)
+ }
}
})
ssView.setFalsingManager(falsingManager)
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 60f44a0d4fca..8bc41c20caaf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -689,8 +689,9 @@ public class NotificationEntryManager implements
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onPreEntryUpdated(entry);
}
+ final boolean fromSystem = ranking != null;
for (NotifCollectionListener listener : mNotifCollectionListeners) {
- listener.onEntryUpdated(entry);
+ listener.onEntryUpdated(entry, fromSystem);
}
if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index a2c9ffc6bdc4..38b5ee88c5ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -27,8 +27,8 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.phone.KeyguardBypassController
-import com.android.systemui.statusbar.phone.PanelExpansionListener
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener
import com.android.systemui.statusbar.policy.HeadsUpManager
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
import javax.inject.Inject
@@ -294,8 +294,8 @@ class NotificationWakeUpCoordinator @Inject constructor(
this.state = newState
}
- override fun onPanelExpansionChanged(expansion: Float, tracking: Boolean) {
- val collapsedEnough = expansion <= 0.9f
+ override fun onPanelExpansionChanged(fraction: Float, expanded: Boolean, tracking: Boolean) {
+ val collapsedEnough = fraction <= 0.9f
if (collapsedEnough != this.collapsedEnoughToHide) {
val couldShowPulsingHuns = canShowPulsingHuns
this.collapsedEnoughToHide = collapsedEnough
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
index fd0476b76a9a..37eacada19fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
@@ -36,7 +36,7 @@ public abstract class ListEntry {
private final ListAttachState mPreviousAttachState = ListAttachState.create();
private final ListAttachState mAttachState = ListAttachState.create();
- ListEntry(String key, long creationTime) {
+ protected ListEntry(String key, long creationTime) {
mKey = key;
mCreationTime = creationTime;
}
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 277b4acb3237..f36f430fc29b 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
@@ -47,7 +47,9 @@ import android.annotation.MainThread;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.Notification;
+import android.os.Handler;
import android.os.RemoteException;
+import android.os.Trace;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking;
@@ -61,6 +63,7 @@ import androidx.annotation.NonNull;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.dump.LogBufferEulogizer;
import com.android.systemui.flags.FeatureFlags;
@@ -75,6 +78,7 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.En
import com.android.systemui.statusbar.notification.collection.notifcollection.EntryRemovedEvent;
import com.android.systemui.statusbar.notification.collection.notifcollection.EntryUpdatedEvent;
import com.android.systemui.statusbar.notification.collection.notifcollection.InitEntryEvent;
+import com.android.systemui.statusbar.notification.collection.notifcollection.InternalNotifUpdater;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionLogger;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
@@ -130,6 +134,7 @@ public class NotifCollection implements Dumpable {
private final SystemClock mClock;
private final FeatureFlags mFeatureFlags;
private final NotifCollectionLogger mLogger;
+ private final Handler mMainHandler;
private final LogBufferEulogizer mEulogizer;
private final Map<String, NotificationEntry> mNotificationSet = new ArrayMap<>();
@@ -153,6 +158,7 @@ public class NotifCollection implements Dumpable {
SystemClock clock,
FeatureFlags featureFlags,
NotifCollectionLogger logger,
+ @Main Handler mainHandler,
LogBufferEulogizer logBufferEulogizer,
DumpManager dumpManager) {
Assert.isMainThread();
@@ -160,6 +166,7 @@ public class NotifCollection implements Dumpable {
mClock = clock;
mFeatureFlags = featureFlags;
mLogger = logger;
+ mMainHandler = mainHandler;
mEulogizer = logBufferEulogizer;
dumpManager.registerDumpable(TAG, this);
@@ -441,7 +448,7 @@ public class NotifCollection implements Dumpable {
mEventQueue.add(new BindEntryEvent(entry, sbn));
mLogger.logNotifUpdated(sbn.getKey());
- mEventQueue.add(new EntryUpdatedEvent(entry));
+ mEventQueue.add(new EntryUpdatedEvent(entry, true /* fromSystem */));
}
}
@@ -512,6 +519,7 @@ public class NotifCollection implements Dumpable {
}
private void dispatchEventsAndRebuildList() {
+ Trace.beginSection("NotifCollection.dispatchEventsAndRebuildList");
mAmDispatchingToOtherCode = true;
while (!mEventQueue.isEmpty()) {
mEventQueue.remove().dispatchTo(mNotifCollectionListeners);
@@ -521,9 +529,12 @@ public class NotifCollection implements Dumpable {
if (mBuildListener != null) {
mBuildListener.onBuildList(mReadOnlyNotificationSet);
}
+ Trace.endSection();
}
- private void onEndLifetimeExtension(NotifLifetimeExtender extender, NotificationEntry entry) {
+ private void onEndLifetimeExtension(
+ @NonNull NotifLifetimeExtender extender,
+ @NonNull NotificationEntry entry) {
Assert.isMainThread();
if (!mAttached) {
return;
@@ -786,6 +797,51 @@ public class NotifCollection implements Dumpable {
private static final String TAG = "NotifCollection";
+ /**
+ * Get an object which can be used to update a notification (internally to the pipeline)
+ * in response to a user action.
+ *
+ * @param name the name of the component that will update notifiations
+ * @return an updater
+ */
+ public InternalNotifUpdater getInternalNotifUpdater(String name) {
+ return (sbn, reason) -> mMainHandler.post(
+ () -> updateNotificationInternally(sbn, name, reason));
+ }
+
+ /**
+ * Provide an updated StatusBarNotification for an existing entry. If no entry exists for the
+ * given notification key, this method does nothing.
+ *
+ * @param sbn the updated notification
+ * @param name the component which is updating the notification
+ * @param reason the reason the notification is being updated
+ */
+ private void updateNotificationInternally(StatusBarNotification sbn, String name,
+ String reason) {
+ Assert.isMainThread();
+ checkForReentrantCall();
+
+ // Make sure we have the notification to update
+ NotificationEntry entry = mNotificationSet.get(sbn.getKey());
+ if (entry == null) {
+ mLogger.logNotifInternalUpdateFailed(sbn.getKey(), name, reason);
+ return;
+ }
+ mLogger.logNotifInternalUpdate(sbn.getKey(), name, reason);
+
+ // First do the pieces of postNotification which are not about assuming the notification
+ // was sent by the app
+ entry.setSbn(sbn);
+ mEventQueue.add(new BindEntryEvent(entry, sbn));
+
+ mLogger.logNotifUpdated(sbn.getKey());
+ mEventQueue.add(new EntryUpdatedEvent(entry, false /* fromSystem */));
+
+ // Skip the applyRanking step and go straight to dispatching the events
+ dispatchEventsAndRebuildList();
+ }
+
@IntDef(prefix = { "REASON_" }, value = {
REASON_NOT_CANCELED,
REASON_UNKNOWN,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
index 47939f0579f5..27ba4c23db88 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.collection;
+import android.os.Handler;
+
import androidx.annotation.Nullable;
import com.android.systemui.dagger.SysUISingleton;
@@ -23,12 +25,14 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.OnBefo
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
+import com.android.systemui.statusbar.notification.collection.notifcollection.InternalNotifUpdater;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
@@ -216,6 +220,22 @@ public class NotifPipeline implements CommonNotifCollection {
mShadeListBuilder.addOnBeforeRenderListListener(listener);
}
+ /** Registers an invalidator that can be used to invalidate the entire notif list. */
+ public void addPreRenderInvalidator(Invalidator invalidator) {
+ mShadeListBuilder.addPreRenderInvalidator(invalidator);
+ }
+
+ /**
+ * Get an object which can be used to update a notification (internally to the pipeline)
+ * in response to a user action.
+ *
+ * @param name the name of the component that will update notifiations
+ * @return an updater
+ */
+ public InternalNotifUpdater getInternalNotifUpdater(String name) {
+ return mNotifCollection.getInternalNotifUpdater(name);
+ }
+
/**
* Returns a read-only view in to the current shade list, i.e. the list of notifications that
* are currently present in the shade. If this method is called during pipeline execution it
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 94ee868ceebc..66d019e778bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -31,7 +31,7 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_NOT_CANCELED;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_ALERTING;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_ALERTING;
import static java.util.Objects.requireNonNull;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index e26fa045d297..6d38389713a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -30,6 +30,7 @@ import static com.android.systemui.statusbar.notification.collection.listbuilder
import android.annotation.MainThread;
import android.annotation.Nullable;
+import android.os.Trace;
import android.util.ArrayMap;
import androidx.annotation.NonNull;
@@ -45,6 +46,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.OnBefo
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState;
import com.android.systemui.statusbar.notification.collection.listbuilder.ShadeListBuilderLogger;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
@@ -52,6 +54,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
+import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
import com.android.systemui.util.Assert;
import com.android.systemui.util.time.SystemClock;
@@ -78,6 +81,8 @@ public class ShadeListBuilder implements Dumpable {
private final SystemClock mSystemClock;
private final ShadeListBuilderLogger mLogger;
private final NotificationInteractionTracker mInteractionTracker;
+ // used exclusivly by ShadeListBuilder#notifySectionEntriesUpdated
+ private final ArrayList<ListEntry> mTempSectionMembers = new ArrayList<>();
private List<ListEntry> mNotifList = new ArrayList<>();
private List<ListEntry> mNewNotifList = new ArrayList<>();
@@ -171,6 +176,13 @@ public class ShadeListBuilder implements Dumpable {
mOnBeforeRenderListListeners.add(listener);
}
+ void addPreRenderInvalidator(Invalidator invalidator) {
+ Assert.isMainThread();
+
+ mPipelineState.requireState(STATE_IDLE);
+ invalidator.setInvalidationListener(this::onPreRenderInvalidated);
+ }
+
void addPreGroupFilter(NotifFilter filter) {
Assert.isMainThread();
mPipelineState.requireState(STATE_IDLE);
@@ -253,6 +265,14 @@ public class ShadeListBuilder implements Dumpable {
}
};
+ private void onPreRenderInvalidated(Invalidator invalidator) {
+ Assert.isMainThread();
+
+ mLogger.logPreRenderInvalidated(invalidator.getName(), mPipelineState.getState());
+
+ rebuildListIfBefore(STATE_FINALIZING);
+ }
+
private void onPreGroupFilterInvalidated(NotifFilter filter) {
Assert.isMainThread();
@@ -313,6 +333,7 @@ public class ShadeListBuilder implements Dumpable {
* if we detect that behavior, we should crash instantly.
*/
private void buildList() {
+ Trace.beginSection("ShadeListBuilder.buildList");
mPipelineState.requireIsBefore(STATE_BUILD_STARTED);
mPipelineState.setState(STATE_BUILD_STARTED);
@@ -356,7 +377,7 @@ public class ShadeListBuilder implements Dumpable {
// section by our list of custom comparators
dispatchOnBeforeSort(mReadOnlyNotifList);
mPipelineState.incrementTo(STATE_SORTING);
- sortList();
+ sortListAndNotifySections();
// Step 7: Lock in our group structure and log anything that's changed since the last run
mPipelineState.incrementTo(STATE_FINALIZING);
@@ -366,9 +387,11 @@ public class ShadeListBuilder implements Dumpable {
// Step 8: Dispatch the new list, first to any listeners and then to the view layer
dispatchOnBeforeRenderList(mReadOnlyNotifList);
+ Trace.beginSection("ShadeListBuilder.onRenderList");
if (mOnRenderListListener != null) {
mOnRenderListListener.onRenderList(mReadOnlyNotifList);
}
+ Trace.endSection();
// Step 9: We're done!
mLogger.logEndBuildList(
@@ -380,6 +403,25 @@ public class ShadeListBuilder implements Dumpable {
}
mPipelineState.setState(STATE_IDLE);
mIterationCount++;
+ Trace.endSection();
+ }
+
+ private void notifySectionEntriesUpdated() {
+ Trace.beginSection("ShadeListBuilder.notifySectionEntriesUpdated");
+ NotifSection currentSection = null;
+ mTempSectionMembers.clear();
+ for (int i = 0; i < mNotifList.size(); i++) {
+ ListEntry currentEntry = mNotifList.get(i);
+ if (currentSection != currentEntry.getSection()) {
+ if (currentSection != null) {
+ currentSection.getSectioner().onEntriesUpdated(mTempSectionMembers);
+ mTempSectionMembers.clear();
+ }
+ currentSection = currentEntry.getSection();
+ }
+ mTempSectionMembers.add(currentEntry);
+ }
+ Trace.endSection();
}
/**
@@ -421,6 +463,7 @@ public class ShadeListBuilder implements Dumpable {
Collection<? extends ListEntry> entries,
List<ListEntry> out,
List<NotifFilter> filters) {
+ Trace.beginSection("ShadeListBuilder.filterNotifs");
final long now = mSystemClock.uptimeMillis();
for (ListEntry entry : entries) {
if (entry instanceof GroupEntry) {
@@ -452,9 +495,11 @@ public class ShadeListBuilder implements Dumpable {
}
}
}
+ Trace.endSection();
}
private void groupNotifs(List<ListEntry> entries, List<ListEntry> out) {
+ Trace.beginSection("ShadeListBuilder.groupNotifs");
for (ListEntry listEntry : entries) {
// since grouping hasn't happened yet, all notifs are NotificationEntries
NotificationEntry entry = (NotificationEntry) listEntry;
@@ -510,12 +555,14 @@ public class ShadeListBuilder implements Dumpable {
}
}
}
+ Trace.endSection();
}
private void stabilizeGroupingNotifs(List<ListEntry> topLevelList) {
if (mNotifStabilityManager == null) {
return;
}
+ Trace.beginSection("ShadeListBuilder.stabilizeGroupingNotifs");
for (int i = 0; i < topLevelList.size(); i++) {
final ListEntry tle = topLevelList.get(i);
@@ -541,6 +588,7 @@ public class ShadeListBuilder implements Dumpable {
}
}
}
+ Trace.endSection();
}
/**
@@ -573,6 +621,7 @@ public class ShadeListBuilder implements Dumpable {
}
private void promoteNotifs(List<ListEntry> list) {
+ Trace.beginSection("ShadeListBuilder.promoteNotifs");
for (int i = 0; i < list.size(); i++) {
final ListEntry tle = list.get(i);
@@ -591,9 +640,11 @@ public class ShadeListBuilder implements Dumpable {
});
}
}
+ Trace.endSection();
}
private void pruneIncompleteGroups(List<ListEntry> shadeList) {
+ Trace.beginSection("ShadeListBuilder.pruneIncompleteGroups");
for (int i = 0; i < shadeList.size(); i++) {
final ListEntry tle = shadeList.get(i);
@@ -648,6 +699,7 @@ public class ShadeListBuilder implements Dumpable {
}
}
}
+ Trace.endSection();
}
/**
@@ -713,14 +765,15 @@ public class ShadeListBuilder implements Dumpable {
}
}
- private void sortList() {
+ private void sortListAndNotifySections() {
+ Trace.beginSection("ShadeListBuilder.sortListAndNotifySections");
// Assign sections to top-level elements and sort their children
for (ListEntry entry : mNotifList) {
NotifSection section = applySections(entry);
if (entry instanceof GroupEntry) {
GroupEntry parent = (GroupEntry) entry;
for (NotificationEntry child : parent.getChildren()) {
- child.getAttachState().setSection(section);
+ setEntrySection(child, section);
}
parent.sortChildren(sChildComparator);
}
@@ -728,6 +781,10 @@ public class ShadeListBuilder implements Dumpable {
// Finally, sort all top-level elements
mNotifList.sort(mTopLevelComparator);
+
+ // notify sections since the list is sorted now
+ notifySectionEntriesUpdated();
+ Trace.endSection();
}
private void freeEmptyGroups() {
@@ -936,11 +993,18 @@ public class ShadeListBuilder implements Dumpable {
}
}
- entry.getAttachState().setSection(finalSection);
-
+ setEntrySection(entry, finalSection);
return finalSection;
}
+ private void setEntrySection(ListEntry entry, NotifSection finalSection) {
+ entry.getAttachState().setSection(finalSection);
+ NotificationEntry representativeEntry = entry.getRepresentativeEntry();
+ if (representativeEntry != null && finalSection != null) {
+ representativeEntry.setBucket(finalSection.getBucket());
+ }
+ }
+
@NonNull
private NotifSection findSection(ListEntry entry) {
for (int i = 0; i < mNotifSections.size(); i++) {
@@ -971,27 +1035,35 @@ public class ShadeListBuilder implements Dumpable {
}
private void dispatchOnBeforeTransformGroups(List<ListEntry> entries) {
+ Trace.beginSection("ShadeListBuilder.dispatchOnBeforeTransformGroups");
for (int i = 0; i < mOnBeforeTransformGroupsListeners.size(); i++) {
mOnBeforeTransformGroupsListeners.get(i).onBeforeTransformGroups(entries);
}
+ Trace.endSection();
}
private void dispatchOnBeforeSort(List<ListEntry> entries) {
+ Trace.beginSection("ShadeListBuilder.dispatchOnBeforeSort");
for (int i = 0; i < mOnBeforeSortListeners.size(); i++) {
mOnBeforeSortListeners.get(i).onBeforeSort(entries);
}
+ Trace.endSection();
}
private void dispatchOnBeforeFinalizeFilter(List<ListEntry> entries) {
+ Trace.beginSection("ShadeListBuilder.dispatchOnBeforeFinalizeFilter");
for (int i = 0; i < mOnBeforeFinalizeFilterListeners.size(); i++) {
mOnBeforeFinalizeFilterListeners.get(i).onBeforeFinalizeFilter(entries);
}
+ Trace.endSection();
}
private void dispatchOnBeforeRenderList(List<ListEntry> entries) {
+ Trace.beginSection("ShadeListBuilder.dispatchOnBeforeRenderList");
for (int i = 0; i < mOnBeforeRenderListListeners.size(); i++) {
mOnBeforeRenderListListeners.get(i).onBeforeRenderList(entries);
}
+ Trace.endSection();
}
@Override
@@ -1019,13 +1091,13 @@ public class ShadeListBuilder implements Dumpable {
void onRenderList(@NonNull List<ListEntry> entries);
}
- private static final NotifSectioner DEFAULT_SECTIONER =
- new NotifSectioner("UnknownSection") {
- @Override
- public boolean isInSection(ListEntry entry) {
- return true;
- }
- };
+ private static final NotifSectioner DEFAULT_SECTIONER = new NotifSectioner("UnknownSection",
+ NotificationPriorityBucketKt.BUCKET_UNKNOWN) {
+ @Override
+ public boolean isInSection(ListEntry entry) {
+ return true;
+ }
+ };
private static final int MIN_CHILDREN_FOR_GROUP = 2;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
index 3a87f6853bcf..3a39c39cfb20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
@@ -23,13 +23,14 @@ import android.service.notification.StatusBarNotification;
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.appops.AppOpsController;
-import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
+import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
import com.android.systemui.util.concurrency.DelayableExecutor;
import javax.inject.Inject;
@@ -47,7 +48,7 @@ import javax.inject.Inject;
* frameworks/base/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener
* frameworks/base/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender
*/
-@SysUISingleton
+@CoordinatorScope
public class AppOpsCoordinator implements Coordinator {
private static final String TAG = "AppOpsCoordinator";
@@ -102,7 +103,8 @@ public class AppOpsCoordinator implements Coordinator {
/**
* Puts foreground service notifications into its own section.
*/
- private final NotifSectioner mNotifSectioner = new NotifSectioner("ForegroundService") {
+ private final NotifSectioner mNotifSectioner = new NotifSectioner("ForegroundService",
+ NotificationPriorityBucketKt.BUCKET_FOREGROUND_SERVICE) {
@Override
public boolean isInSection(ListEntry entry) {
NotificationEntry notificationEntry = entry.getRepresentativeEntry();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
index 29a030f910a4..15f0d885c2fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
@@ -16,10 +16,10 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
-import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
@@ -53,7 +53,7 @@ import javax.inject.Inject;
* respond to app-cancellations (ie: remove the bubble if the app cancels the notification).
*
*/
-@SysUISingleton
+@CoordinatorScope
public class BubbleCoordinator implements Coordinator {
private static final String TAG = "BubbleCoordinator";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
index f0eb084ea8ef..e59f4a62f9b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
@@ -16,16 +16,17 @@
package com.android.systemui.statusbar.notification.collection.coordinator
-import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
import com.android.systemui.statusbar.notification.collection.render.NodeController
import com.android.systemui.statusbar.notification.dagger.PeopleHeader
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
+import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE
import javax.inject.Inject
/**
@@ -33,7 +34,7 @@ import javax.inject.Inject
* - Elevates important conversation notifications
* - Puts conversations into its own people section. @see [NotifCoordinators] for section ordering.
*/
-@SysUISingleton
+@CoordinatorScope
class ConversationCoordinator @Inject constructor(
private val peopleNotificationIdentifier: PeopleNotificationIdentifier,
@PeopleHeader peopleHeaderController: NodeController
@@ -45,10 +46,12 @@ class ConversationCoordinator @Inject constructor(
}
}
- val sectioner = object : NotifSectioner("People") {
+ val sectioner = object : NotifSectioner("People", BUCKET_PEOPLE) {
override fun isInSection(entry: ListEntry): Boolean =
isConversation(entry.representativeEntry!!)
- override fun getHeaderNodeController() = peopleHeaderController
+ override fun getHeaderNodeController() =
+ // TODO: remove SHOW_ALL_SECTIONS, this redundant method, and peopleHeaderController
+ if (RankingCoordinator.SHOW_ALL_SECTIONS) peopleHeaderController else null
}
override fun attach(pipeline: NotifPipeline) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
index 47928b42ed5e..e8652493da6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
@@ -23,9 +23,9 @@ import android.content.pm.PackageManager;
import android.os.RemoteException;
import android.service.notification.StatusBarNotification;
-import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -36,7 +36,7 @@ import javax.inject.Inject;
* Special notifications with extra permissions and tags won't be filtered out even when the
* device is unprovisioned.
*/
-@SysUISingleton
+@CoordinatorScope
public class DeviceProvisionedCoordinator implements Coordinator {
private static final String TAG = "DeviceProvisionedCoordinator";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt
new file mode 100644
index 000000000000..dbecf1cc28d7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt
@@ -0,0 +1,126 @@
+/*
+ * 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.collection.coordinator
+
+import android.util.ArraySet
+import com.android.systemui.Dumpable
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender.OnEndLifetimeExtensionCallback
+import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewListener
+import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager
+import com.android.systemui.statusbar.notification.row.NotificationGuts
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager
+import java.io.FileDescriptor
+import java.io.PrintWriter
+import javax.inject.Inject
+
+private const val TAG = "GutsCoordinator"
+
+/**
+ * Coordinates the guts displayed by the [NotificationGutsManager] with the pipeline.
+ * Specifically, this just adds the lifetime extension necessary to keep guts from disappearing.
+ */
+@CoordinatorScope
+class GutsCoordinator @Inject constructor(
+ private val notifGutsViewManager: NotifGutsViewManager,
+ private val logger: GutsCoordinatorLogger,
+ dumpManager: DumpManager
+) : Coordinator, Dumpable {
+
+ /** Keys of any Notifications for which we've been told the guts are open */
+ private val notifsWithOpenGuts = ArraySet<String>()
+
+ /** Keys of any Notifications we've extended the lifetime for, based on guts */
+ private val notifsExtendingLifetime = ArraySet<String>()
+
+ /** Callback for ending lifetime extension */
+ private var onEndLifetimeExtensionCallback: OnEndLifetimeExtensionCallback? = null
+
+ init {
+ dumpManager.registerDumpable(TAG, this)
+ }
+
+ override fun attach(pipeline: NotifPipeline) {
+ notifGutsViewManager.setGutsListener(mGutsListener)
+ pipeline.addNotificationLifetimeExtender(mLifetimeExtender)
+ }
+
+ override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
+ pw.println(" notifsWithOpenGuts: ${notifsWithOpenGuts.size}")
+ for (key in notifsWithOpenGuts) {
+ pw.println(" * $key")
+ }
+ pw.println(" notifsExtendingLifetime: ${notifsExtendingLifetime.size}")
+ for (key in notifsExtendingLifetime) {
+ pw.println(" * $key")
+ }
+ pw.println(" onEndLifetimeExtensionCallback: $onEndLifetimeExtensionCallback")
+ }
+
+ private val mLifetimeExtender: NotifLifetimeExtender = object : NotifLifetimeExtender {
+ override fun getName(): String {
+ return TAG
+ }
+
+ override fun setCallback(callback: OnEndLifetimeExtensionCallback) {
+ onEndLifetimeExtensionCallback = callback
+ }
+
+ override fun shouldExtendLifetime(entry: NotificationEntry, reason: Int): Boolean {
+ val isShowingGuts = isCurrentlyShowingGuts(entry)
+ if (isShowingGuts) {
+ notifsExtendingLifetime.add(entry.key)
+ }
+ return isShowingGuts
+ }
+
+ override fun cancelLifetimeExtension(entry: NotificationEntry) {
+ notifsExtendingLifetime.remove(entry.key)
+ }
+ }
+
+ private val mGutsListener: NotifGutsViewListener = object : NotifGutsViewListener {
+ override fun onGutsOpen(entry: NotificationEntry, guts: NotificationGuts) {
+ logger.logGutsOpened(entry.key, guts)
+ if (guts.isLeavebehind) {
+ // leave-behind guts should not extend the lifetime of the notification
+ closeGutsAndEndLifetimeExtension(entry)
+ } else {
+ notifsWithOpenGuts.add(entry.key)
+ }
+ }
+
+ override fun onGutsClose(entry: NotificationEntry) {
+ logger.logGutsClosed(entry.key)
+ closeGutsAndEndLifetimeExtension(entry)
+ }
+ }
+
+ private fun isCurrentlyShowingGuts(entry: ListEntry) =
+ notifsWithOpenGuts.contains(entry.key)
+
+ private fun closeGutsAndEndLifetimeExtension(entry: NotificationEntry) {
+ notifsWithOpenGuts.remove(entry.key)
+ if (notifsExtendingLifetime.remove(entry.key)) {
+ onEndLifetimeExtensionCallback?.onEndLifetimeExtension(mLifetimeExtender, entry)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt
new file mode 100644
index 000000000000..e8f352f60da0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt
@@ -0,0 +1,32 @@
+package com.android.systemui.statusbar.notification.collection.coordinator
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.dagger.NotificationLog
+import com.android.systemui.statusbar.notification.row.NotificationGuts
+import javax.inject.Inject
+
+private const val TAG = "GutsCoordinator"
+
+class GutsCoordinatorLogger @Inject constructor(
+ @NotificationLog private val buffer: LogBuffer
+) {
+
+ fun logGutsOpened(key: String, guts: NotificationGuts) {
+ buffer.log(TAG, LogLevel.DEBUG, {
+ str1 = key
+ str2 = guts.gutsContent::class.simpleName
+ bool1 = guts.isLeavebehind
+ }, {
+ "Guts of type $str2 (leave behind: $bool1) opened for class $str1"
+ })
+ }
+
+ fun logGutsClosed(key: String) {
+ buffer.log(TAG, LogLevel.DEBUG, {
+ str1 = key
+ }, {
+ "Guts closed for class $str1"
+ })
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
index 6e98c27fe9a9..f8b4274188f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
@@ -19,13 +19,14 @@ package com.android.systemui.statusbar.notification.collection.coordinator;
import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY;
import static com.android.systemui.statusbar.notification.interruption.HeadsUpController.alertAgain;
-import android.annotation.Nullable;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
-import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
@@ -34,6 +35,7 @@ import com.android.systemui.statusbar.notification.collection.render.NodeControl
import com.android.systemui.statusbar.notification.dagger.IncomingHeader;
import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
+import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -55,7 +57,7 @@ import javax.inject.Inject;
*
* Note: The inflation callback in {@link PreparationCoordinator} handles showing HUNs.
*/
-@SysUISingleton
+@CoordinatorScope
public class HeadsUpCoordinator implements Coordinator {
private static final String TAG = "HeadsUpCoordinator";
@@ -163,17 +165,17 @@ public class HeadsUpCoordinator implements Coordinator {
private final NotifLifetimeExtender mLifetimeExtender = new NotifLifetimeExtender() {
@Override
- public String getName() {
+ public @NonNull String getName() {
return TAG;
}
@Override
- public void setCallback(OnEndLifetimeExtensionCallback callback) {
+ public void setCallback(@NonNull OnEndLifetimeExtensionCallback callback) {
mEndLifetimeExtension = callback;
}
@Override
- public boolean shouldExtendLifetime(NotificationEntry entry, int reason) {
+ public boolean shouldExtendLifetime(@NonNull NotificationEntry entry, int reason) {
boolean isShowingHun = isCurrentlyShowingHun(entry);
if (isShowingHun) {
mNotifExtendingLifetime = entry;
@@ -182,7 +184,7 @@ public class HeadsUpCoordinator implements Coordinator {
}
@Override
- public void cancelLifetimeExtension(NotificationEntry entry) {
+ public void cancelLifetimeExtension(@NonNull NotificationEntry entry) {
if (Objects.equals(mNotifExtendingLifetime, entry)) {
mNotifExtendingLifetime = null;
}
@@ -196,7 +198,8 @@ public class HeadsUpCoordinator implements Coordinator {
}
};
- private final NotifSectioner mNotifSectioner = new NotifSectioner("HeadsUp") {
+ private final NotifSectioner mNotifSectioner = new NotifSectioner("HeadsUp",
+ NotificationPriorityBucketKt.BUCKET_HEADS_UP) {
@Override
public boolean isInSection(ListEntry entry) {
return isCurrentlyShowingHun(entry);
@@ -205,7 +208,11 @@ public class HeadsUpCoordinator implements Coordinator {
@Nullable
@Override
public NodeController getHeaderNodeController() {
- return mIncomingHeaderController;
+ // TODO: remove SHOW_ALL_SECTIONS, this redundant method, and mIncomingHeaderController
+ if (RankingCoordinator.SHOW_ALL_SECTIONS) {
+ return mIncomingHeaderController;
+ }
+ return null;
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideLocallyDismissedNotifsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideLocallyDismissedNotifsCoordinator.java
index 0059e7baa3c2..6684237c4ebf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideLocallyDismissedNotifsCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideLocallyDismissedNotifsCoordinator.java
@@ -20,13 +20,21 @@ import static com.android.systemui.statusbar.notification.collection.Notificatio
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import javax.inject.Inject;
+
/**
* Filters out notifications that have been dismissed locally (by the user) but that system server
* hasn't yet confirmed the removal of.
*/
+@CoordinatorScope
public class HideLocallyDismissedNotifsCoordinator implements Coordinator {
+
+ @Inject
+ HideLocallyDismissedNotifsCoordinator() { }
+
@Override
public void attach(NotifPipeline pipeline) {
pipeline.addPreGroupFilter(mFilter);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinator.java
index e595dd4a2f71..7b5cf8511900 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinator.java
@@ -23,6 +23,7 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import javax.inject.Inject;
@@ -37,6 +38,7 @@ import javax.inject.Inject;
* TODO: The NotificationLockscreenUserManager currently maintains the list of active user profiles.
* We should spin that off into a standalone section at some point.
*/
+@CoordinatorScope
public class HideNotifsForOtherUsersCoordinator implements Coordinator {
private final NotificationLockscreenUserManager mLockscreenUserManager;
private final SharedCoordinatorLogger mLogger;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index 23d5369833c5..fe1cd7b98cf9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -34,13 +34,13 @@ import androidx.annotation.MainThread;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -50,7 +50,7 @@ import javax.inject.Inject;
/**
* Filters low priority and privacy-sensitive notifications from the lockscreen.
*/
-@SysUISingleton
+@CoordinatorScope
public class KeyguardCoordinator implements Coordinator {
private static final String TAG = "KeyguardCoordinator";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
index 026a3ffb73cd..8769969834c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
@@ -21,6 +21,7 @@ import static com.android.systemui.media.MediaDataManagerKt.isMediaNotification;
import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import javax.inject.Inject;
@@ -28,6 +29,7 @@ import javax.inject.Inject;
/**
* Coordinates hiding (filtering) of media notifications.
*/
+@CoordinatorScope
public class MediaCoordinator implements Coordinator {
private static final String TAG = "MediaCoordinator";
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
deleted file mode 100644
index 25b201926239..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.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.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;
-import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
-import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.inject.Inject;
-
-/**
- * Handles the attachment of {@link Coordinator}s to the {@link NotifPipeline} so that the
- * Coordinators can register their respective callbacks.
- */
-@SysUISingleton
-public class NotifCoordinators implements Dumpable {
- private static final String TAG = "NotifCoordinators";
- private final List<Coordinator> mCoordinators = new ArrayList<>();
- private final List<NotifSectioner> mOrderedSections = new ArrayList<>();
-
- /**
- * Creates all the coordinators.
- */
- @Inject
- public NotifCoordinators(
- DumpManager dumpManager,
- FeatureFlags featureFlags,
- HideNotifsForOtherUsersCoordinator hideNotifsForOtherUsersCoordinator,
- KeyguardCoordinator keyguardCoordinator,
- RankingCoordinator rankingCoordinator,
- AppOpsCoordinator appOpsCoordinator,
- DeviceProvisionedCoordinator deviceProvisionedCoordinator,
- BubbleCoordinator bubbleCoordinator,
- HeadsUpCoordinator headsUpCoordinator,
- ConversationCoordinator conversationCoordinator,
- PreparationCoordinator preparationCoordinator,
- MediaCoordinator mediaCoordinator,
- SmartspaceDedupingCoordinator smartspaceDedupingCoordinator,
- VisualStabilityCoordinator visualStabilityCoordinator) {
- dumpManager.registerDumpable(TAG, this);
-
- mCoordinators.add(new HideLocallyDismissedNotifsCoordinator());
- mCoordinators.add(hideNotifsForOtherUsersCoordinator);
- mCoordinators.add(keyguardCoordinator);
- mCoordinators.add(rankingCoordinator);
- mCoordinators.add(appOpsCoordinator);
- mCoordinators.add(deviceProvisionedCoordinator);
- mCoordinators.add(bubbleCoordinator);
- mCoordinators.add(conversationCoordinator);
- mCoordinators.add(mediaCoordinator);
- mCoordinators.add(visualStabilityCoordinator);
-
- if (featureFlags.isSmartspaceDedupingEnabled()) {
- mCoordinators.add(smartspaceDedupingCoordinator);
- }
-
- if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
- mCoordinators.add(headsUpCoordinator);
- mCoordinators.add(preparationCoordinator);
- }
-
- // Manually add Ordered Sections
- // HeadsUp > FGS > People > Alerting > Silent > Unknown/Default
- if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
- mOrderedSections.add(headsUpCoordinator.getSectioner()); // HeadsUp
- }
- mOrderedSections.add(appOpsCoordinator.getSectioner()); // ForegroundService
- mOrderedSections.add(conversationCoordinator.getSectioner()); // People
- mOrderedSections.add(rankingCoordinator.getAlertingSectioner()); // Alerting
- mOrderedSections.add(rankingCoordinator.getSilentSectioner()); // Silent
- }
-
- /**
- * Sends the pipeline to each coordinator when the pipeline is ready to accept
- * {@link Pluggable}s, {@link NotifCollectionListener}s and {@link NotifLifetimeExtender}s.
- */
- public void attach(NotifPipeline pipeline) {
- for (Coordinator c : mCoordinators) {
- c.attach(pipeline);
- }
-
- pipeline.setSections(mOrderedSections);
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println();
- pw.println(TAG + ":");
- for (Coordinator c : mCoordinators) {
- pw.println("\t" + c.getClass());
- }
-
- for (NotifSectioner s : mOrderedSections) {
- pw.println("\t" + s.getName());
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
new file mode 100644
index 000000000000..39b1ec4ff80e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.notification.collection.coordinator
+
+import com.android.systemui.Dumpable
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
+import java.io.FileDescriptor
+import java.io.PrintWriter
+import java.util.ArrayList
+import javax.inject.Inject
+
+/**
+ * Handles the attachment of [Coordinator]s to the [NotifPipeline] so that the
+ * Coordinators can register their respective callbacks.
+ */
+interface NotifCoordinators : Coordinator, Dumpable
+
+@CoordinatorScope
+class NotifCoordinatorsImpl @Inject constructor(
+ dumpManager: DumpManager,
+ featureFlags: FeatureFlags,
+ hideLocallyDismissedNotifsCoordinator: HideLocallyDismissedNotifsCoordinator,
+ hideNotifsForOtherUsersCoordinator: HideNotifsForOtherUsersCoordinator,
+ keyguardCoordinator: KeyguardCoordinator,
+ rankingCoordinator: RankingCoordinator,
+ appOpsCoordinator: AppOpsCoordinator,
+ deviceProvisionedCoordinator: DeviceProvisionedCoordinator,
+ bubbleCoordinator: BubbleCoordinator,
+ headsUpCoordinator: HeadsUpCoordinator,
+ gutsCoordinator: GutsCoordinator,
+ conversationCoordinator: ConversationCoordinator,
+ preparationCoordinator: PreparationCoordinator,
+ mediaCoordinator: MediaCoordinator,
+ remoteInputCoordinator: RemoteInputCoordinator,
+ shadeEventCoordinator: ShadeEventCoordinator,
+ smartspaceDedupingCoordinator: SmartspaceDedupingCoordinator,
+ viewConfigCoordinator: ViewConfigCoordinator,
+ visualStabilityCoordinator: VisualStabilityCoordinator,
+ sensitiveContentCoordinator: SensitiveContentCoordinator
+) : NotifCoordinators {
+
+ private val mCoordinators: MutableList<Coordinator> = ArrayList()
+ private val mOrderedSections: MutableList<NotifSectioner> = ArrayList()
+
+ /**
+ * Creates all the coordinators.
+ */
+ init {
+ dumpManager.registerDumpable(TAG, this)
+ mCoordinators.add(hideLocallyDismissedNotifsCoordinator)
+ mCoordinators.add(hideNotifsForOtherUsersCoordinator)
+ mCoordinators.add(keyguardCoordinator)
+ mCoordinators.add(rankingCoordinator)
+ mCoordinators.add(appOpsCoordinator)
+ mCoordinators.add(deviceProvisionedCoordinator)
+ mCoordinators.add(bubbleCoordinator)
+ mCoordinators.add(conversationCoordinator)
+ mCoordinators.add(mediaCoordinator)
+ mCoordinators.add(remoteInputCoordinator)
+ mCoordinators.add(shadeEventCoordinator)
+ mCoordinators.add(viewConfigCoordinator)
+ mCoordinators.add(visualStabilityCoordinator)
+ mCoordinators.add(sensitiveContentCoordinator)
+ if (featureFlags.isSmartspaceDedupingEnabled) {
+ mCoordinators.add(smartspaceDedupingCoordinator)
+ }
+ if (featureFlags.isNewNotifPipelineRenderingEnabled) {
+ mCoordinators.add(headsUpCoordinator)
+ mCoordinators.add(gutsCoordinator)
+ mCoordinators.add(preparationCoordinator)
+ }
+
+ // Manually add Ordered Sections
+ // HeadsUp > FGS > People > Alerting > Silent > Unknown/Default
+ if (featureFlags.isNewNotifPipelineRenderingEnabled) {
+ mOrderedSections.add(headsUpCoordinator.sectioner) // HeadsUp
+ }
+ mOrderedSections.add(appOpsCoordinator.sectioner) // ForegroundService
+ mOrderedSections.add(conversationCoordinator.sectioner) // People
+ mOrderedSections.add(rankingCoordinator.alertingSectioner) // Alerting
+ mOrderedSections.add(rankingCoordinator.silentSectioner) // Silent
+ }
+
+ /**
+ * Sends the pipeline to each coordinator when the pipeline is ready to accept
+ * [Pluggable]s, [NotifCollectionListener]s and [NotifLifetimeExtender]s.
+ */
+ override fun attach(pipeline: NotifPipeline) {
+ for (c in mCoordinators) {
+ c.attach(pipeline)
+ }
+ pipeline.setSections(mOrderedSections)
+ }
+
+ override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
+ pw.println()
+ pw.println("$TAG:")
+ for (c in mCoordinators) {
+ pw.println("\t${c.javaClass}")
+ }
+ for (s in mOrderedSections) {
+ pw.println("\t${s.name}")
+ }
+ }
+
+ companion object {
+ private const val TAG = "NotifCoordinators"
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
index 31826c7219de..afdfb3bdeef6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
@@ -57,6 +57,7 @@ import javax.inject.Inject;
* If a notification was uninflated, this coordinator will filter the notification out from the
* {@link ShadeListBuilder} until it is inflated.
*/
+// TODO(b/204468557): Move to @CoordinatorScope
@SysUISingleton
public class PreparationCoordinator implements Coordinator {
private static final String TAG = "PreparationCoordinator";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
index 6da4d8b70944..2ab2dd0b1273 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
@@ -16,19 +16,24 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
+import android.annotation.NonNull;
import android.annotation.Nullable;
-import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.collection.render.NodeController;
+import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
import com.android.systemui.statusbar.notification.dagger.AlertingHeader;
import com.android.systemui.statusbar.notification.dagger.SilentHeader;
+import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
+
+import java.util.List;
import javax.inject.Inject;
@@ -39,11 +44,13 @@ import javax.inject.Inject;
* - whether the notification's app is suspended or hiding its notifications
* - whether DND settings are hiding notifications from ambient display or the notification list
*/
-@SysUISingleton
+@CoordinatorScope
public class RankingCoordinator implements Coordinator {
+ public static final boolean SHOW_ALL_SECTIONS = false;
private final StatusBarStateController mStatusBarStateController;
private final HighPriorityProvider mHighPriorityProvider;
- private final NodeController mSilentHeaderController;
+ private final NodeController mSilentNodeController;
+ private final SectionHeaderController mSilentHeaderController;
private final NodeController mAlertingHeaderController;
@Inject
@@ -51,10 +58,12 @@ public class RankingCoordinator implements Coordinator {
StatusBarStateController statusBarStateController,
HighPriorityProvider highPriorityProvider,
@AlertingHeader NodeController alertingHeaderController,
- @SilentHeader NodeController silentHeaderController) {
+ @SilentHeader SectionHeaderController silentHeaderController,
+ @SilentHeader NodeController silentNodeController) {
mStatusBarStateController = statusBarStateController;
mHighPriorityProvider = highPriorityProvider;
mAlertingHeaderController = alertingHeaderController;
+ mSilentNodeController = silentNodeController;
mSilentHeaderController = silentHeaderController;
}
@@ -74,7 +83,8 @@ public class RankingCoordinator implements Coordinator {
return mSilentNotifSectioner;
}
- private final NotifSectioner mAlertingNotifSectioner = new NotifSectioner("Alerting") {
+ private final NotifSectioner mAlertingNotifSectioner = new NotifSectioner("Alerting",
+ NotificationPriorityBucketKt.BUCKET_ALERTING) {
@Override
public boolean isInSection(ListEntry entry) {
return mHighPriorityProvider.isHighPriority(entry);
@@ -83,11 +93,16 @@ public class RankingCoordinator implements Coordinator {
@Nullable
@Override
public NodeController getHeaderNodeController() {
- return mAlertingHeaderController;
+ // TODO: remove SHOW_ALL_SECTIONS, this redundant method, and mAlertingHeaderController
+ if (SHOW_ALL_SECTIONS) {
+ return mAlertingHeaderController;
+ }
+ return null;
}
};
- private final NotifSectioner mSilentNotifSectioner = new NotifSectioner("Silent") {
+ private final NotifSectioner mSilentNotifSectioner = new NotifSectioner("Silent",
+ NotificationPriorityBucketKt.BUCKET_SILENT) {
@Override
public boolean isInSection(ListEntry entry) {
return !mHighPriorityProvider.isHighPriority(entry);
@@ -96,7 +111,19 @@ public class RankingCoordinator implements Coordinator {
@Nullable
@Override
public NodeController getHeaderNodeController() {
- return mSilentHeaderController;
+ return mSilentNodeController;
+ }
+
+ @Nullable
+ @Override
+ public void onEntriesUpdated(@NonNull List<ListEntry> entries) {
+ for (int i = 0; i < entries.size(); i++) {
+ if (entries.get(i).getRepresentativeEntry().getSbn().isClearable()) {
+ mSilentHeaderController.setClearSectionEnabled(true);
+ return;
+ }
+ }
+ mSilentHeaderController.setClearSectionEnabled(false);
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinator.kt
new file mode 100644
index 000000000000..3397815f008f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinator.kt
@@ -0,0 +1,225 @@
+/*
+ * 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.collection.coordinator
+
+import android.os.Handler
+import android.service.notification.NotificationListenerService.REASON_CANCEL
+import android.service.notification.NotificationListenerService.REASON_CLICK
+import android.util.Log
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.Dumpable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.NotificationRemoteInputManager
+import com.android.systemui.statusbar.NotificationRemoteInputManager.RemoteInputListener
+import com.android.systemui.statusbar.RemoteInputController
+import com.android.systemui.statusbar.RemoteInputNotificationRebuilder
+import com.android.systemui.statusbar.SmartReplyController
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.notifcollection.SelfTrackingLifetimeExtender
+import com.android.systemui.statusbar.notification.collection.notifcollection.InternalNotifUpdater
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
+import java.io.FileDescriptor
+import java.io.PrintWriter
+import javax.inject.Inject
+
+private const val TAG = "RemoteInputCoordinator"
+
+/**
+ * How long to wait before auto-dismissing a notification that was kept for active remote input, and
+ * has now sent a remote input. We auto-dismiss, because the app may not cannot cancel
+ * these given that they technically don't exist anymore. We wait a bit in case the app issues
+ * an update, and to also give the other lifetime extenders a beat to decide they want it.
+ */
+private const val REMOTE_INPUT_ACTIVE_EXTENDER_AUTO_CANCEL_DELAY: Long = 500
+
+/**
+ * How long to wait before releasing a lifetime extension when requested to do so due to a user
+ * interaction (such as tapping another action).
+ * We wait a bit in case the app issues an update in response to the action, but not too long or we
+ * risk appearing unresponsive to the user.
+ */
+private const val REMOTE_INPUT_EXTENDER_RELEASE_DELAY: Long = 200
+
+/** Whether this class should print spammy debug logs */
+private val DEBUG: Boolean by lazy { Log.isLoggable(TAG, Log.DEBUG) }
+
+@SysUISingleton
+class RemoteInputCoordinator @Inject constructor(
+ dumpManager: DumpManager,
+ private val mRebuilder: RemoteInputNotificationRebuilder,
+ private val mNotificationRemoteInputManager: NotificationRemoteInputManager,
+ @Main private val mMainHandler: Handler,
+ private val mSmartReplyController: SmartReplyController
+) : Coordinator, RemoteInputListener, Dumpable {
+
+ @VisibleForTesting val mRemoteInputHistoryExtender = RemoteInputHistoryExtender()
+ @VisibleForTesting val mSmartReplyHistoryExtender = SmartReplyHistoryExtender()
+ @VisibleForTesting val mRemoteInputActiveExtender = RemoteInputActiveExtender()
+ private val mRemoteInputLifetimeExtenders = listOf(
+ mRemoteInputHistoryExtender,
+ mSmartReplyHistoryExtender,
+ mRemoteInputActiveExtender
+ )
+
+ private lateinit var mNotifUpdater: InternalNotifUpdater
+
+ init {
+ dumpManager.registerDumpable(this)
+ }
+
+ fun getLifetimeExtenders(): List<NotifLifetimeExtender> = mRemoteInputLifetimeExtenders
+
+ override fun attach(pipeline: NotifPipeline) {
+ mNotificationRemoteInputManager.setRemoteInputListener(this)
+ mRemoteInputLifetimeExtenders.forEach { pipeline.addNotificationLifetimeExtender(it) }
+ mNotifUpdater = pipeline.getInternalNotifUpdater(TAG)
+ pipeline.addCollectionListener(mCollectionListener)
+ }
+
+ val mCollectionListener = object : NotifCollectionListener {
+ override fun onEntryUpdated(entry: NotificationEntry, fromSystem: Boolean) {
+ if (DEBUG) {
+ Log.d(TAG, "mCollectionListener.onEntryUpdated(entry=${entry.key}," +
+ " fromSystem=$fromSystem)")
+ }
+ if (fromSystem) {
+ // Mark smart replies as sent whenever a notification is updated by the app,
+ // otherwise the smart replies are never marked as sent.
+ mSmartReplyController.stopSending(entry)
+ }
+ }
+
+ override fun onEntryRemoved(entry: NotificationEntry, reason: Int) {
+ if (DEBUG) Log.d(TAG, "mCollectionListener.onEntryRemoved(entry=${entry.key})")
+ // We're removing the notification, the smart reply controller can forget about it.
+ // TODO(b/145659174): track 'sending' state on the entry to avoid having to clear it.
+ mSmartReplyController.stopSending(entry)
+
+ // When we know the entry will not be lifetime extended, clean up the remote input view
+ // TODO: Share code with NotifCollection.cannotBeLifetimeExtended
+ if (reason == REASON_CANCEL || reason == REASON_CLICK) {
+ mNotificationRemoteInputManager.cleanUpRemoteInputForUserRemoval(entry)
+ }
+ }
+ }
+
+ override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+ mRemoteInputLifetimeExtenders.forEach { it.dump(fd, pw, args) }
+ }
+
+ override fun onRemoteInputSent(entry: NotificationEntry) {
+ if (DEBUG) Log.d(TAG, "onRemoteInputSent(entry=${entry.key})")
+ // These calls effectively ensure the freshness of the lifetime extensions.
+ // NOTE: This is some trickery! By removing the lifetime extensions when we know they should
+ // be immediately re-upped, we ensure that the side-effects of the lifetime extenders get to
+ // fire again, thus ensuring that we add subsequent replies to the notification.
+ mRemoteInputHistoryExtender.endLifetimeExtension(entry.key)
+ mSmartReplyHistoryExtender.endLifetimeExtension(entry.key)
+
+ // If we're extending for remote input being active, then from the apps point of
+ // view it is already canceled, so we'll need to cancel it on the apps behalf
+ // now that a reply has been sent. However, delay so that the app has time to posts an
+ // update in the mean time, and to give another lifetime extender time to pick it up.
+ mRemoteInputActiveExtender.endLifetimeExtensionAfterDelay(entry.key,
+ REMOTE_INPUT_ACTIVE_EXTENDER_AUTO_CANCEL_DELAY)
+ }
+
+ private fun onSmartReplySent(entry: NotificationEntry, reply: CharSequence) {
+ if (DEBUG) Log.d(TAG, "onSmartReplySent(entry=${entry.key})")
+ val newSbn = mRebuilder.rebuildForSendingSmartReply(entry, reply)
+ mNotifUpdater.onInternalNotificationUpdate(newSbn,
+ "Adding smart reply spinner for sent")
+
+ // If we're extending for remote input being active, then from the apps point of
+ // view it is already canceled, so we'll need to cancel it on the apps behalf
+ // now that a reply has been sent. However, delay so that the app has time to posts an
+ // update in the mean time, and to give another lifetime extender time to pick it up.
+ mRemoteInputActiveExtender.endLifetimeExtensionAfterDelay(entry.key,
+ REMOTE_INPUT_ACTIVE_EXTENDER_AUTO_CANCEL_DELAY)
+ }
+
+ override fun onPanelCollapsed() {
+ mRemoteInputActiveExtender.endAllLifetimeExtensions()
+ }
+
+ override fun isNotificationKeptForRemoteInputHistory(key: String) =
+ mRemoteInputHistoryExtender.isExtending(key) ||
+ mSmartReplyHistoryExtender.isExtending(key)
+
+ override fun releaseNotificationIfKeptForRemoteInputHistory(entry: NotificationEntry) {
+ if (DEBUG) Log.d(TAG, "releaseNotificationIfKeptForRemoteInputHistory(entry=${entry.key})")
+ mRemoteInputHistoryExtender.endLifetimeExtensionAfterDelay(entry.key,
+ REMOTE_INPUT_EXTENDER_RELEASE_DELAY)
+ mSmartReplyHistoryExtender.endLifetimeExtensionAfterDelay(entry.key,
+ REMOTE_INPUT_EXTENDER_RELEASE_DELAY)
+ mRemoteInputActiveExtender.endLifetimeExtensionAfterDelay(entry.key,
+ REMOTE_INPUT_EXTENDER_RELEASE_DELAY)
+ }
+
+ override fun setRemoteInputController(remoteInputController: RemoteInputController) {
+ mSmartReplyController.setCallback(this::onSmartReplySent)
+ }
+
+ @VisibleForTesting
+ inner class RemoteInputHistoryExtender :
+ SelfTrackingLifetimeExtender(TAG, "RemoteInputHistory", DEBUG, mMainHandler) {
+
+ override fun queryShouldExtendLifetime(entry: NotificationEntry): Boolean =
+ mNotificationRemoteInputManager.shouldKeepForRemoteInputHistory(entry)
+
+ override fun onStartedLifetimeExtension(entry: NotificationEntry) {
+ val newSbn = mRebuilder.rebuildForRemoteInputReply(entry)
+ entry.onRemoteInputInserted()
+ mNotifUpdater.onInternalNotificationUpdate(newSbn,
+ "Extending lifetime of notification with remote input")
+ // TODO: Check if the entry was removed due perhaps to an inflation exception?
+ }
+ }
+
+ @VisibleForTesting
+ inner class SmartReplyHistoryExtender :
+ SelfTrackingLifetimeExtender(TAG, "SmartReplyHistory", DEBUG, mMainHandler) {
+
+ override fun queryShouldExtendLifetime(entry: NotificationEntry): Boolean =
+ mNotificationRemoteInputManager.shouldKeepForSmartReplyHistory(entry)
+
+ override fun onStartedLifetimeExtension(entry: NotificationEntry) {
+ val newSbn = mRebuilder.rebuildForCanceledSmartReplies(entry)
+ mSmartReplyController.stopSending(entry)
+ mNotifUpdater.onInternalNotificationUpdate(newSbn,
+ "Extending lifetime of notification with smart reply")
+ // TODO: Check if the entry was removed due perhaps to an inflation exception?
+ }
+
+ override fun onCanceledLifetimeExtension(entry: NotificationEntry) {
+ // TODO(b/145659174): track 'sending' state on the entry to avoid having to clear it.
+ mSmartReplyController.stopSending(entry)
+ }
+ }
+
+ @VisibleForTesting
+ inner class RemoteInputActiveExtender :
+ SelfTrackingLifetimeExtender(TAG, "RemoteInputActive", DEBUG, mMainHandler) {
+
+ override fun queryShouldExtendLifetime(entry: NotificationEntry): Boolean =
+ mNotificationRemoteInputManager.isRemoteInputActive(entry)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
new file mode 100644
index 000000000000..a115e0400de3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
@@ -0,0 +1,105 @@
+/*
+ * 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.collection.coordinator
+
+import android.os.UserHandle
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.statusbar.notification.DynamicPrivacyController
+import com.android.systemui.statusbar.notification.collection.GroupEntry
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator
+import dagger.Module
+import dagger.Provides
+
+@Module
+object SensitiveContentCoordinatorModule {
+ @Provides
+ @JvmStatic
+ @CoordinatorScope
+ fun provideCoordinator(
+ dynamicPrivacyController: DynamicPrivacyController,
+ lockscreenUserManager: NotificationLockscreenUserManager
+ ): SensitiveContentCoordinator =
+ SensitiveContentCoordinatorImpl(dynamicPrivacyController, lockscreenUserManager)
+}
+
+/** Coordinates re-inflation and post-processing of sensitive notification content. */
+interface SensitiveContentCoordinator : Coordinator
+
+private class SensitiveContentCoordinatorImpl(
+ private val dynamicPrivacyController: DynamicPrivacyController,
+ private val lockscreenUserManager: NotificationLockscreenUserManager
+) : Invalidator("SensitiveContentInvalidator"),
+ SensitiveContentCoordinator,
+ DynamicPrivacyController.Listener,
+ OnBeforeRenderListListener {
+
+ override fun attach(pipeline: NotifPipeline) {
+ dynamicPrivacyController.addListener(this)
+ pipeline.addOnBeforeRenderListListener(this)
+ pipeline.addPreRenderInvalidator(this)
+ }
+
+ override fun onDynamicPrivacyChanged(): Unit = invalidateList()
+
+ override fun onBeforeRenderList(entries: List<ListEntry>) {
+ val currentUserId = lockscreenUserManager.currentUserId
+ val devicePublic = lockscreenUserManager.isLockscreenPublicMode(currentUserId)
+ val deviceSensitive = devicePublic &&
+ !lockscreenUserManager.userAllowsPrivateNotificationsInPublic(currentUserId)
+ val dynamicallyUnlocked = dynamicPrivacyController.isDynamicallyUnlocked
+ for (entry in extractAllRepresentativeEntries(entries).filter { it.rowExists() }) {
+ val notifUserId = entry.sbn.user.identifier
+ val userLockscreen = devicePublic ||
+ lockscreenUserManager.isLockscreenPublicMode(notifUserId)
+ val userPublic = when {
+ // if we're not on the lockscreen, we're definitely private
+ !userLockscreen -> false
+ // we are on the lockscreen, so unless we're dynamically unlocked, we're
+ // definitely public
+ !dynamicallyUnlocked -> true
+ // we're dynamically unlocked, but check if the notification needs
+ // a separate challenge if it's from a work profile
+ else -> when (notifUserId) {
+ currentUserId -> false
+ UserHandle.USER_ALL -> false
+ else -> lockscreenUserManager.needsSeparateWorkChallenge(notifUserId)
+ }
+ }
+ val needsRedaction = lockscreenUserManager.needsRedaction(entry)
+ val isSensitive = userPublic && needsRedaction
+ entry.setSensitive(isSensitive, deviceSensitive)
+ }
+ }
+}
+
+private fun extractAllRepresentativeEntries(
+ entries: List<ListEntry>
+): Sequence<NotificationEntry> =
+ entries.asSequence().flatMap(::extractAllRepresentativeEntries)
+
+private fun extractAllRepresentativeEntries(listEntry: ListEntry): Sequence<NotificationEntry> =
+ sequence {
+ listEntry.representativeEntry?.let { yield(it) }
+ if (listEntry is GroupEntry) {
+ yieldAll(extractAllRepresentativeEntries(listEntry.children))
+ }
+ } \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinator.kt
new file mode 100644
index 000000000000..2d5c331e2071
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinator.kt
@@ -0,0 +1,79 @@
+/*
+ * 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.collection.coordinator
+
+import android.service.notification.NotificationListenerService
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
+import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource
+import javax.inject.Inject
+
+/**
+ * A coordinator which provides callbacks to a view surfaces for various events relevant to the
+ * shade, such as when the user removes a notification, or when the shade is emptied.
+ */
+// TODO(b/204468557): Move to @CoordinatorScope
+@SysUISingleton
+class ShadeEventCoordinator @Inject internal constructor(
+ private val mLogger: ShadeEventCoordinatorLogger
+) : Coordinator, NotifShadeEventSource {
+ private var mNotifRemovedByUserCallback: Runnable? = null
+ private var mShadeEmptiedCallback: Runnable? = null
+ private var mEntryRemoved = false
+ private var mEntryRemovedByUser = false
+
+ override fun attach(pipeline: NotifPipeline) {
+ pipeline.addCollectionListener(mNotifCollectionListener)
+ pipeline.addOnBeforeRenderListListener(this::onBeforeRenderList)
+ }
+
+ private val mNotifCollectionListener = object : NotifCollectionListener {
+ override fun onEntryRemoved(entry: NotificationEntry, reason: Int) {
+ mEntryRemoved = true
+ mEntryRemovedByUser =
+ reason == NotificationListenerService.REASON_CLICK ||
+ reason == NotificationListenerService.REASON_CANCEL_ALL ||
+ reason == NotificationListenerService.REASON_CANCEL
+ }
+ }
+
+ override fun setNotifRemovedByUserCallback(callback: Runnable) {
+ check(mNotifRemovedByUserCallback == null) { "mNotifRemovedByUserCallback already set" }
+ mNotifRemovedByUserCallback = callback
+ }
+
+ override fun setShadeEmptiedCallback(callback: Runnable) {
+ check(mShadeEmptiedCallback == null) { "mShadeEmptiedCallback already set" }
+ mShadeEmptiedCallback = callback
+ }
+
+ private fun onBeforeRenderList(entries: List<ListEntry>) {
+ if (mEntryRemoved && entries.isEmpty()) {
+ mLogger.logShadeEmptied()
+ mShadeEmptiedCallback?.run()
+ }
+ if (mEntryRemoved && mEntryRemovedByUser) {
+ mLogger.logNotifRemovedByUser()
+ mNotifRemovedByUserCallback?.run()
+ }
+ mEntryRemoved = false
+ mEntryRemovedByUser = false
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt
new file mode 100644
index 000000000000..c687e1bacbc9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.collection.coordinator
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.dagger.NotificationLog
+import javax.inject.Inject
+
+private const val TAG = "ShadeEventCoordinator"
+
+/** Logger for the [ShadeEventCoordinator] */
+class ShadeEventCoordinatorLogger @Inject constructor(
+ @NotificationLog private val buffer: LogBuffer
+) {
+
+ fun logShadeEmptied() {
+ buffer.log(TAG, LogLevel.DEBUG, { }, { "Shade emptied" })
+ }
+
+ fun logNotifRemovedByUser() {
+ buffer.log(TAG, LogLevel.DEBUG, { }, { "Notification removed by user" })
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt
index 442d9d2bb205..519d75ff07d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt
@@ -18,7 +18,6 @@ package com.android.systemui.statusbar.notification.collection.coordinator
import android.app.smartspace.SmartspaceTarget
import android.os.Parcelable
-import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.NotificationLockscreenUserManager
@@ -28,6 +27,7 @@ import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
import com.android.systemui.statusbar.notification.NotificationEntryManager
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
import com.android.systemui.util.concurrency.DelayableExecutor
@@ -45,7 +45,7 @@ import javax.inject.Inject
*/
// This class is a singleton so that the same instance can be accessed by both the old and new
// pipelines
-@SysUISingleton
+@CoordinatorScope
class SmartspaceDedupingCoordinator @Inject constructor(
private val statusBarStateController: SysuiStatusBarStateController,
private val smartspaceController: LockscreenSmartspaceController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
new file mode 100644
index 000000000000..5b86de2a9d87
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
@@ -0,0 +1,109 @@
+/*
+ * 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.collection.coordinator
+
+import com.android.internal.widget.MessagingGroup
+import com.android.internal.widget.MessagingMessage
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener
+import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager
+import com.android.systemui.statusbar.policy.ConfigurationController
+import javax.inject.Inject
+
+/**
+ * A coordinator which ensures that notifications within the new pipeline are correctly inflated
+ * for the current uiMode and screen properties; additionally deferring those changes when a user
+ * change is in progress until that process has completed.
+ */
+@CoordinatorScope
+class ViewConfigCoordinator @Inject internal constructor(
+ configurationController: ConfigurationController,
+ lockscreenUserManager: NotificationLockscreenUserManagerImpl,
+ featureFlags: FeatureFlags,
+ private val mGutsManager: NotificationGutsManager,
+ private val mKeyguardUpdateMonitor: KeyguardUpdateMonitor
+) : Coordinator, UserChangedListener, ConfigurationController.ConfigurationListener {
+
+ private var mReinflateNotificationsOnUserSwitched = false
+ private var mDispatchUiModeChangeOnUserSwitched = false
+ private var mPipeline: NotifPipeline? = null
+
+ init {
+ if (featureFlags.isNewNotifPipelineRenderingEnabled) {
+ lockscreenUserManager.addUserChangedListener(this)
+ configurationController.addCallback(this)
+ }
+ }
+
+ override fun attach(pipeline: NotifPipeline) {
+ mPipeline = pipeline
+ }
+
+ override fun onDensityOrFontScaleChanged() {
+ MessagingMessage.dropCache()
+ MessagingGroup.dropCache()
+ if (!mKeyguardUpdateMonitor.isSwitchingUser) {
+ updateNotificationsOnDensityOrFontScaleChanged()
+ } else {
+ mReinflateNotificationsOnUserSwitched = true
+ }
+ }
+
+ override fun onUiModeChanged() {
+ if (!mKeyguardUpdateMonitor.isSwitchingUser) {
+ updateNotificationsOnUiModeChanged()
+ } else {
+ mDispatchUiModeChangeOnUserSwitched = true
+ }
+ }
+
+ override fun onThemeChanged() {
+ onDensityOrFontScaleChanged()
+ }
+
+ override fun onUserChanged(userId: Int) {
+ if (mReinflateNotificationsOnUserSwitched) {
+ updateNotificationsOnDensityOrFontScaleChanged()
+ mReinflateNotificationsOnUserSwitched = false
+ }
+ if (mDispatchUiModeChangeOnUserSwitched) {
+ updateNotificationsOnUiModeChanged()
+ mDispatchUiModeChangeOnUserSwitched = false
+ }
+ }
+
+ private fun updateNotificationsOnUiModeChanged() {
+ mPipeline?.allNotifs?.forEach { entry ->
+ val row = entry.row
+ row?.onUiModeChanged()
+ }
+ }
+
+ private fun updateNotificationsOnDensityOrFontScaleChanged() {
+ mPipeline?.allNotifs?.forEach { entry ->
+ entry.onDensityOrFontScaleChanged()
+ val exposedGuts = entry.areGutsExposed()
+ if (exposedGuts) {
+ mGutsManager.onDensityOrFontScaleChanged(entry)
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
index 5d6c0437ce9b..5ba4c2ff36ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
@@ -50,6 +50,7 @@ import javax.inject.Inject;
* This is now integrated in the data-layer via
* {@link com.android.systemui.statusbar.notification.collection.ShadeListBuilder}.
*/
+// TODO(b/204468557): Move to @CoordinatorScope
@SysUISingleton
public class VisualStabilityCoordinator implements Coordinator {
private final DelayableExecutor mDelayableExecutor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt
new file mode 100644
index 000000000000..a26d50d2a059
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt
@@ -0,0 +1,65 @@
+/*
+ * 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.collection.coordinator.dagger
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinators
+import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinatorsImpl
+import com.android.systemui.statusbar.notification.collection.coordinator.SensitiveContentCoordinatorModule
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.Subcomponent
+import javax.inject.Qualifier
+import javax.inject.Scope
+
+@Module(subcomponents = [CoordinatorsSubcomponent::class])
+object CoordinatorsModule {
+ @SysUISingleton
+ @JvmStatic
+ @Provides
+ fun notifCoordinators(factory: CoordinatorsSubcomponent.Factory): NotifCoordinators =
+ factory.create().notifCoordinators
+}
+
+@CoordinatorScope
+@Subcomponent(modules = [InternalCoordinatorsModule::class])
+interface CoordinatorsSubcomponent {
+ @get:Internal val notifCoordinators: NotifCoordinators
+
+ @Subcomponent.Factory
+ interface Factory {
+ fun create(): CoordinatorsSubcomponent
+ }
+}
+
+@Module(includes = [SensitiveContentCoordinatorModule::class])
+private abstract class InternalCoordinatorsModule {
+ @Binds
+ @Internal
+ abstract fun bindNotifCoordinators(impl: NotifCoordinatorsImpl): NotifCoordinators
+}
+
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+private annotation class Internal
+
+@Scope
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class CoordinatorScope \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationPresenterExtensions.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationPresenterExtensions.java
new file mode 100644
index 000000000000..4ee08ed4899f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationPresenterExtensions.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.legacy;
+
+import static com.android.systemui.statusbar.phone.StatusBar.SPEW;
+
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
+
+import org.jetbrains.annotations.NotNull;
+
+import javax.inject.Inject;
+
+/**
+ * This is some logic extracted from the
+ * {@link com.android.systemui.statusbar.phone.StatusBarNotificationPresenter}
+ * into a class that implements a new-pipeline interface so that the new pipeline can implement it
+ * correctly.
+ *
+ * Specifically, this is the logic which updates notifications when uiMode and screen properties
+ * change, and which closes the shade when the last notification disappears.
+ */
+public class LegacyNotificationPresenterExtensions implements NotifShadeEventSource {
+ private static final String TAG = "LegacyNotifPresenter";
+ private final NotificationEntryManager mEntryManager;
+ private boolean mEntryListenerAdded;
+ private Runnable mShadeEmptiedCallback;
+ private Runnable mNotifRemovedByUserCallback;
+
+ @Inject
+ public LegacyNotificationPresenterExtensions(NotificationEntryManager entryManager) {
+ mEntryManager = entryManager;
+ }
+
+ private void ensureEntryListenerAdded() {
+ if (mEntryListenerAdded) return;
+ mEntryListenerAdded = true;
+ mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
+ @Override
+ public void onEntryRemoved(
+ @NotNull NotificationEntry entry,
+ NotificationVisibility visibility,
+ boolean removedByUser,
+ int reason) {
+ StatusBarNotification old = entry.getSbn();
+ if (SPEW) {
+ Log.d(TAG, "removeNotification key=" + entry.getKey()
+ + " old=" + old + " reason=" + reason);
+ }
+
+ if (old != null && !mEntryManager.hasActiveNotifications()) {
+ if (mShadeEmptiedCallback != null) mShadeEmptiedCallback.run();
+ }
+ if (removedByUser) {
+ if (mNotifRemovedByUserCallback != null) mNotifRemovedByUserCallback.run();
+ }
+ }
+ });
+ }
+
+ @Override
+ public void setNotifRemovedByUserCallback(@NonNull Runnable callback) {
+ if (mNotifRemovedByUserCallback != null) {
+ throw new IllegalStateException("mNotifRemovedByUserCallback already set");
+ }
+ mNotifRemovedByUserCallback = callback;
+ ensureEntryListenerAdded();
+ }
+
+ @Override
+ public void setShadeEmptiedCallback(@NonNull Runnable callback) {
+ if (mShadeEmptiedCallback != null) {
+ throw new IllegalStateException("mShadeEmptiedCallback already set");
+ }
+ mShadeEmptiedCallback = callback;
+ ensureEntryListenerAdded();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
index c9fc9929f0d3..6424e37ad328 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
@@ -18,14 +18,17 @@ package com.android.systemui.statusbar.notification.collection.listbuilder
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
import com.android.systemui.statusbar.notification.collection.render.NodeController
+import com.android.systemui.statusbar.notification.stack.PriorityBucket
data class NotifSection(
val sectioner: NotifSectioner,
val index: Int
) {
val label: String
- get() = "Section($index, \"${sectioner.name}\")"
+ get() = "Section($index, $bucket, \"${sectioner.name}\")"
val headerController: NodeController?
get() = sectioner.headerNodeController
+
+ @PriorityBucket val bucket: Int = sectioner.bucket
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
index 5a35127397b4..8fff90504798 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
@@ -47,6 +47,15 @@ class ShadeListBuilderLogger @Inject constructor(
})
}
+ fun logPreRenderInvalidated(filterName: String, pipelineState: Int) {
+ buffer.log(TAG, DEBUG, {
+ str1 = filterName
+ int1 = pipelineState
+ }, {
+ """Pre-render Invalidator "$str1" invalidated; pipeline state is $int1"""
+ })
+ }
+
fun logPreGroupFilterInvalidated(filterName: String, pipelineState: Int) {
buffer.log(TAG, DEBUG, {
str1 = filterName
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Invalidator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Invalidator.java
new file mode 100644
index 000000000000..d7092ecd536e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Invalidator.java
@@ -0,0 +1,24 @@
+/*
+ * 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.collection.listbuilder.pluggable;
+
+/** A {@link Pluggable} that can only invalidate. */
+public abstract class Invalidator extends Pluggable<Invalidator> {
+ protected Invalidator(String name) {
+ super(name);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java
index c8982d35c4a0..ef9ee11ef116 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java
@@ -22,13 +22,28 @@ import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.ShadeListBuilder;
import com.android.systemui.statusbar.notification.collection.render.NodeController;
import com.android.systemui.statusbar.notification.collection.render.NodeSpec;
+import com.android.systemui.statusbar.notification.stack.PriorityBucket;
+
+import java.util.List;
/**
- * Pluggable for participating in notif sectioning. See {@link ShadeListBuilder#setSections}.
+ * Pluggable for participating in notif sectioning. See {@link ShadeListBuilder#setSectioners}.
*/
public abstract class NotifSectioner extends Pluggable<NotifSectioner> {
- protected NotifSectioner(String name) {
+ @PriorityBucket
+ private final int mBucket;
+
+ protected NotifSectioner(String name, @PriorityBucket int bucket) {
super(name);
+ mBucket = bucket;
+ }
+
+ /**
+ * @return the "bucket" value to apply to entries in this section
+ */
+ @PriorityBucket
+ public final int getBucket() {
+ return mBucket;
}
/**
@@ -46,4 +61,10 @@ public abstract class NotifSectioner extends Pluggable<NotifSectioner> {
public @Nullable NodeController getHeaderNodeController() {
return null;
}
+
+ /**
+ * Notify of children of this section being updated
+ * @param entries of this section that are borrowed (must clone to store)
+ */
+ public void onEntriesUpdated(List<ListEntry> entries) {}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java
index 8e4fb7523767..b981a9621526 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.collection.listbuilder.pluggable;
import android.annotation.Nullable;
+import android.os.Trace;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -50,7 +51,9 @@ public abstract class Pluggable<This> {
*/
public final void invalidateList() {
if (mListener != null) {
+ Trace.beginSection("Pluggable<" + mName + ">.invalidateList");
mListener.onPluggableInvalidated((This) this);
+ Trace.endSection();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/InternalNotifUpdater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/InternalNotifUpdater.java
new file mode 100644
index 000000000000..5692fb2b523e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/InternalNotifUpdater.java
@@ -0,0 +1,37 @@
+/*
+ * 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.collection.notifcollection;
+
+import android.service.notification.StatusBarNotification;
+
+/**
+ * An object that allows Coordinators to update notifications internally to SystemUI.
+ * This is used when part of the UI involves updating the underlying appearance of a notification
+ * on behalf of an app, such as to add a spinner or remote input history.
+ */
+public interface InternalNotifUpdater {
+ /**
+ * Called when an already-existing notification needs to be updated to a new temporary
+ * appearance.
+ * This update is local to the SystemUI process.
+ * This has no effect if no notification with the given key exists in the pipeline.
+ *
+ * @param sbn a notification to update
+ * @param reason a debug reason for the update
+ */
+ void onInternalNotificationUpdate(StatusBarNotification sbn, String reason);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java
index db0c1745f565..68a346f817e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java
@@ -56,6 +56,17 @@ public interface NotifCollectionListener {
/**
* Called whenever a notification with the same key as an existing notification is posted. By
* the time this listener is called, the entry's SBN and Ranking will already have been updated.
+ * This delegates to {@link #onEntryUpdated(NotificationEntry)} by default.
+ * @param fromSystem If true, this update came from the NotificationManagerService.
+ * If false, the notification update is an internal change within systemui.
+ */
+ default void onEntryUpdated(@NonNull NotificationEntry entry, boolean fromSystem) {
+ onEntryUpdated(entry);
+ }
+
+ /**
+ * Called whenever a notification with the same key as an existing notification is posted. By
+ * the time this listener is called, the entry's SBN and Ranking will already have been updated.
*/
default void onEntryUpdated(@NonNull NotificationEntry entry) {
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
index f8a778d6b1d2..1ebc66e4c665 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
@@ -121,6 +121,26 @@ class NotifCollectionLogger @Inject constructor(
})
}
+ fun logNotifInternalUpdate(key: String, name: String, reason: String) {
+ buffer.log(TAG, INFO, {
+ str1 = key
+ str2 = name
+ str3 = reason
+ }, {
+ "UPDATED INTERNALLY $str1 BY $str2 BECAUSE $str3"
+ })
+ }
+
+ fun logNotifInternalUpdateFailed(key: String, name: String, reason: String) {
+ buffer.log(TAG, INFO, {
+ str1 = key
+ str2 = name
+ str3 = reason
+ }, {
+ "FAILED INTERNAL UPDATE $str1 BY $str2 BECAUSE $str3"
+ })
+ }
+
fun logNoNotificationToRemoveWithKey(key: String) {
buffer.log(TAG, ERROR, {
str1 = key
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt
index 2810b891373f..179e95328442 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt
@@ -64,10 +64,11 @@ data class EntryAddedEvent(
}
data class EntryUpdatedEvent(
- val entry: NotificationEntry
+ val entry: NotificationEntry,
+ val fromSystem: Boolean
) : NotifEvent() {
override fun dispatchToListener(listener: NotifCollectionListener) {
- listener.onEntryUpdated(entry)
+ listener.onEntryUpdated(entry, fromSystem)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java
index f8fe0676e003..2fe3bd63c2e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.collection.notifcollection;
+import androidx.annotation.NonNull;
+
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -26,14 +28,14 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
*/
public interface NotifLifetimeExtender {
/** Name to associate with this extender (for the purposes of debugging) */
- String getName();
+ @NonNull String getName();
/**
* Called on the extender immediately after it has been registered. The extender should hang on
* to this callback and execute it whenever it no longer needs to extend the lifetime of a
* notification.
*/
- void setCallback(OnEndLifetimeExtensionCallback callback);
+ void setCallback(@NonNull OnEndLifetimeExtensionCallback callback);
/**
* Called by the NotifCollection whenever a notification has been retracted (by the app) or
@@ -43,7 +45,7 @@ public interface NotifLifetimeExtender {
* called on all lifetime extenders even if earlier ones return true (in other words, multiple
* lifetime extenders can be extending a notification at the same time).
*/
- boolean shouldExtendLifetime(NotificationEntry entry, @CancellationReason int reason);
+ boolean shouldExtendLifetime(@NonNull NotificationEntry entry, @CancellationReason int reason);
/**
* Called by the NotifCollection to inform a lifetime extender that its extension of a notif
@@ -51,7 +53,7 @@ public interface NotifLifetimeExtender {
* lifetime extension). The extender should clean up any references it has to the notif in
* question.
*/
- void cancelLifetimeExtension(NotificationEntry entry);
+ void cancelLifetimeExtension(@NonNull NotificationEntry entry);
/** Callback for notifying the NotifCollection that a lifetime extension has expired.*/
interface OnEndLifetimeExtensionCallback {
@@ -59,6 +61,8 @@ public interface NotifLifetimeExtender {
* Stop extending the lifetime of `entry` with `extender` and then immediately re-evaluates
* whether to continue lifetime extending this notification or to remove it.
*/
- void onEndLifetimeExtension(NotifLifetimeExtender extender, NotificationEntry entry);
+ void onEndLifetimeExtension(
+ @NonNull NotifLifetimeExtender extender,
+ @NonNull NotificationEntry entry);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtender.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtender.kt
new file mode 100644
index 000000000000..145c1e54d732
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtender.kt
@@ -0,0 +1,113 @@
+package com.android.systemui.statusbar.notification.collection.notifcollection
+
+import android.os.Handler
+import android.util.ArrayMap
+import android.util.Log
+import com.android.systemui.Dumpable
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import java.io.FileDescriptor
+import java.io.PrintWriter
+
+/**
+ * A helpful class that implements the core contract of the lifetime extender internally,
+ * making it easier for coordinators to interact with them
+ */
+abstract class SelfTrackingLifetimeExtender(
+ private val tag: String,
+ private val name: String,
+ private val debug: Boolean,
+ private val mainHandler: Handler
+) : NotifLifetimeExtender, Dumpable {
+ private lateinit var mCallback: NotifLifetimeExtender.OnEndLifetimeExtensionCallback
+ protected val mEntriesExtended = ArrayMap<String, NotificationEntry>()
+ private var mEnding = false
+
+ /**
+ * When debugging, warn if the call is happening during and "end lifetime extension" call.
+ *
+ * Note: this will warn a lot! The pipeline explicitly re-invokes all lifetime extenders
+ * whenever one ends, giving all of them a chance to re-up their lifetime extension.
+ */
+ private fun warnIfEnding() {
+ if (debug && mEnding) Log.w(tag, "reentrant code while ending a lifetime extension")
+ }
+
+ fun endAllLifetimeExtensions() {
+ // clear the map before iterating over a copy of the items, because the pipeline will
+ // always give us another chance to extend the lifetime again, and we don't want
+ // concurrent modification
+ val entries = mEntriesExtended.values.toList()
+ if (debug) Log.d(tag, "$name.endAllLifetimeExtensions() entries=$entries")
+ mEntriesExtended.clear()
+ warnIfEnding()
+ mEnding = true
+ entries.forEach { mCallback.onEndLifetimeExtension(this, it) }
+ mEnding = false
+ }
+
+ fun endLifetimeExtensionAfterDelay(key: String, delayMillis: Long) {
+ if (debug) {
+ Log.d(tag, "$name.endLifetimeExtensionAfterDelay" +
+ "(key=$key, delayMillis=$delayMillis)" +
+ " isExtending=${isExtending(key)}")
+ }
+ if (isExtending(key)) {
+ mainHandler.postDelayed({ endLifetimeExtension(key) }, delayMillis)
+ }
+ }
+
+ fun endLifetimeExtension(key: String) {
+ if (debug) {
+ Log.d(tag, "$name.endLifetimeExtension(key=$key)" +
+ " isExtending=${isExtending(key)}")
+ }
+ warnIfEnding()
+ mEnding = true
+ mEntriesExtended.remove(key)?.let { removedEntry ->
+ mCallback.onEndLifetimeExtension(this, removedEntry)
+ }
+ mEnding = false
+ }
+
+ fun isExtending(key: String) = mEntriesExtended.contains(key)
+
+ final override fun getName(): String = name
+
+ final override fun shouldExtendLifetime(entry: NotificationEntry, reason: Int): Boolean {
+ val shouldExtend = queryShouldExtendLifetime(entry)
+ if (debug) {
+ Log.d(tag, "$name.shouldExtendLifetime(key=${entry.key}, reason=$reason)" +
+ " isExtending=${isExtending(entry.key)}" +
+ " shouldExtend=$shouldExtend")
+ }
+ warnIfEnding()
+ if (shouldExtend && mEntriesExtended.put(entry.key, entry) == null) {
+ onStartedLifetimeExtension(entry)
+ }
+ return shouldExtend
+ }
+
+ final override fun cancelLifetimeExtension(entry: NotificationEntry) {
+ if (debug) {
+ Log.d(tag, "$name.cancelLifetimeExtension(key=${entry.key})" +
+ " isExtending=${isExtending(entry.key)}")
+ }
+ warnIfEnding()
+ mEntriesExtended.remove(entry.key)
+ onCanceledLifetimeExtension(entry)
+ }
+
+ abstract fun queryShouldExtendLifetime(entry: NotificationEntry): Boolean
+ open fun onStartedLifetimeExtension(entry: NotificationEntry) {}
+ open fun onCanceledLifetimeExtension(entry: NotificationEntry) {}
+
+ final override fun setCallback(callback: NotifLifetimeExtender.OnEndLifetimeExtensionCallback) {
+ mCallback = callback
+ }
+
+ final override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+ pw.println("LifetimeExtender: $name:")
+ pw.println(" mEntriesExtended: ${mEntriesExtended.size}")
+ mEntriesExtended.forEach { pw.println(" * ${it.key}") }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
index 9b8ac722d5c9..010b6f80121c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
@@ -20,6 +20,7 @@ import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
+import com.android.systemui.util.traceSection
/**
* Converts a notif list (the output of the ShadeListBuilder) into a NodeSpec, an abstract
@@ -36,7 +37,7 @@ class NodeSpecBuilder(
fun buildNodeSpec(
rootController: NodeController,
notifList: List<ListEntry>
- ): NodeSpec {
+ ): NodeSpec = traceSection("NodeSpecBuilder.buildNodeSpec") {
val root = NodeSpecImpl(null, rootController)
var currentSection: NotifSection? = null
val prevSections = mutableSetOf<NotifSection?>()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewListener.kt
new file mode 100644
index 000000000000..129f6b1750e6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewListener.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.collection.render
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.row.NotificationGuts
+
+/**
+ * Interface for listening to guts open and close events.
+ */
+interface NotifGutsViewListener {
+ /** A notification's guts are being opened */
+ fun onGutsOpen(entry: NotificationEntry, guts: NotificationGuts)
+
+ /** A notification's guts are being closed */
+ fun onGutsClose(entry: NotificationEntry)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewManager.kt
new file mode 100644
index 000000000000..0260f89110f8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewManager.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.collection.render
+
+/** A type which provides open and close guts events to a single listener */
+interface NotifGutsViewManager {
+ /**
+ * @param listener the object that will listen to open and close guts events
+ */
+ fun setGutsListener(listener: NotifGutsViewListener?)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifShadeEventSource.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifShadeEventSource.kt
new file mode 100644
index 000000000000..e24f6a036095
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifShadeEventSource.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.collection.render
+
+/**
+ * This is an object which provides callbacks for certain important events related to the
+ * notification shade, such as notifications being removed by the user, or the shade becoming empty.
+ */
+interface NotifShadeEventSource {
+ /**
+ * Registers a callback to be invoked when the last notification has been removed from
+ * the shade for any reason
+ */
+ fun setShadeEmptiedCallback(callback: Runnable)
+
+ /**
+ * Registers a callback to be invoked when a notification has been removed from
+ * the shade by a user action
+ */
+ fun setNotifRemovedByUserCallback(callback: Runnable)
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/SectionHeaderController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/SectionHeaderController.kt
index 1311e3e756dc..8c15647c5038 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/SectionHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/SectionHeaderController.kt
@@ -33,7 +33,8 @@ import javax.inject.Inject
interface SectionHeaderController {
fun reinflateView(parent: ViewGroup)
val headerView: SectionHeaderView?
- fun setOnClearAllClickListener(listener: View.OnClickListener)
+ fun setClearSectionEnabled(enabled: Boolean)
+ fun setOnClearSectionClickListener(listener: View.OnClickListener)
}
@SectionHeaderScope
@@ -46,6 +47,7 @@ internal class SectionHeaderNodeControllerImpl @Inject constructor(
) : NodeController, SectionHeaderController {
private var _view: SectionHeaderView? = null
+ private var clearAllButtonEnabled = false
private var clearAllClickListener: View.OnClickListener? = null
private val onHeaderClickListener = View.OnClickListener {
activityStarter.startActivity(
@@ -76,12 +78,18 @@ internal class SectionHeaderNodeControllerImpl @Inject constructor(
parent.addView(inflated, oldPos)
}
_view = inflated
+ _view?.setClearSectionButtonEnabled(clearAllButtonEnabled)
}
override val headerView: SectionHeaderView?
get() = _view
- override fun setOnClearAllClickListener(listener: View.OnClickListener) {
+ override fun setClearSectionEnabled(enabled: Boolean) {
+ clearAllButtonEnabled = enabled
+ _view?.setClearSectionButtonEnabled(enabled)
+ }
+
+ override fun setOnClearSectionClickListener(listener: View.OnClickListener) {
clearAllClickListener = listener
_view?.setOnClearAllClickListener(listener)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
index 7babbb40b6c1..6d4ae4b1a869 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification.collection.render
import android.annotation.MainThread
import android.view.View
import com.android.systemui.util.kotlin.transform
+import com.android.systemui.util.traceSection
/**
* Given a "spec" that describes a "tree" of views, adds and removes views from the
@@ -47,7 +48,7 @@ class ShadeViewDiffer(
* provided [spec]. The root node of the spec must match the root controller passed to the
* differ's constructor.
*/
- fun applySpec(spec: NodeSpec) {
+ fun applySpec(spec: NodeSpec) = traceSection("ShadeViewDiffer.applySpec") {
val specMap = treeToMap(spec)
if (spec.controller != rootNode.controller) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
index a2c7aa5cc8f7..b582a24f5a3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
@@ -18,10 +18,13 @@ package com.android.systemui.statusbar.notification.collection.render
import android.content.Context
import android.view.View
+import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.ShadeListBuilder
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.phone.NotificationIconAreaController
+import com.android.systemui.util.traceSection
import javax.inject.Inject
/**
@@ -32,7 +35,7 @@ class ShadeViewManager constructor(
context: Context,
listContainer: NotificationListContainer,
logger: ShadeViewDifferLogger,
- viewBarn: NotifViewBarn,
+ private val viewBarn: NotifViewBarn,
private val notificationIconAreaController: NotificationIconAreaController
) {
// We pass a shim view here because the listContainer may not actually have a view associated
@@ -45,8 +48,21 @@ class ShadeViewManager constructor(
listBuilder.setOnRenderListListener(::onNewNotifTree)
private fun onNewNotifTree(notifList: List<ListEntry>) {
- viewDiffer.applySpec(specBuilder.buildNodeSpec(rootController, notifList))
- notificationIconAreaController.updateNotificationIcons(notifList)
+ traceSection("ShadeViewManager.onNewNotifTree") {
+ viewDiffer.applySpec(specBuilder.buildNodeSpec(rootController, notifList))
+ updateGroupCounts(notifList)
+ notificationIconAreaController.updateNotificationIcons(notifList)
+ }
+ }
+
+ private fun updateGroupCounts(notifList: List<ListEntry>) {
+ traceSection("ShadeViewManager.updateGroupCounts") {
+ notifList.asSequence().filterIsInstance<GroupEntry>().forEach { groupEntry ->
+ val controller = viewBarn.requireView(checkNotNull(groupEntry.summary))
+ val row = controller.view as ExpandableNotificationRow
+ row.setUntruncatedChildCount(groupEntry.untruncatedChildCount)
+ }
+ }
}
}
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 94f5c44d7c78..1eb007e345ec 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
@@ -45,10 +45,13 @@ import com.android.systemui.statusbar.notification.NotificationEntryManagerLogge
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.coordinator.ShadeEventCoordinator;
import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator;
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorsModule;
import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.inflation.OnUserInteractionCallbackImpl;
+import com.android.systemui.statusbar.notification.collection.legacy.LegacyNotificationPresenterExtensions;
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.legacy.OnUserInteractionCallbackImplLegacy;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
@@ -58,6 +61,8 @@ import com.android.systemui.statusbar.notification.collection.render.GroupExpans
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManagerImpl;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl;
+import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager;
+import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl;
import com.android.systemui.statusbar.notification.init.NotificationsControllerStub;
@@ -89,7 +94,10 @@ import dagger.Provides;
/**
* Dagger Module for classes found within the com.android.systemui.statusbar.notification package.
*/
-@Module(includes = { NotificationSectionHeadersModule.class })
+@Module(includes = {
+ NotificationSectionHeadersModule.class,
+ CoordinatorsModule.class
+})
public interface NotificationsModule {
@Binds
StackScrollAlgorithm.SectionProvider bindSectionProvider(
@@ -169,6 +177,14 @@ public interface NotificationsModule {
dumpManager);
}
+ /** Provides an instance of {@link NotifGutsViewManager} */
+ @SysUISingleton
+ @Provides
+ static NotifGutsViewManager provideNotifGutsViewManager(
+ NotificationGutsManager notificationGutsManager) {
+ return notificationGutsManager;
+ }
+
/** Provides an instance of {@link VisualStabilityManager} */
@SysUISingleton
@Provides
@@ -262,6 +278,20 @@ public interface NotificationsModule {
}
/**
+ * Provide the active implementation for presenting notifications.
+ */
+ @Provides
+ @SysUISingleton
+ static NotifShadeEventSource provideNotifShadeEventSource(
+ FeatureFlags featureFlags,
+ Lazy<ShadeEventCoordinator> shadeEventCoordinatorLazy,
+ Lazy<LegacyNotificationPresenterExtensions> legacyNotificationPresenterExtensionsLazy) {
+ return featureFlags.isNewNotifPipelineRenderingEnabled()
+ ? shadeEventCoordinatorLazy.get()
+ : legacyNotificationPresenterExtensionsLazy.get();
+ }
+
+ /**
* Provide a dismissal callback that's triggered when a user manually dismissed a notification
* from the notification shade or it gets auto-cancelled by click.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
index c147023edf8d..9faef1b43bc1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
@@ -16,12 +16,12 @@
package com.android.systemui.statusbar.notification.logging;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_ALERTING;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_FOREGROUND_SERVICE;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_HEADS_UP;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_MEDIA_CONTROLS;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_PEOPLE;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_ALERTING;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_FOREGROUND_SERVICE;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_HEADS_UP;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_MEDIA_CONTROLS;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PEOPLE;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
import android.annotation.Nullable;
import android.service.notification.StatusBarNotification;
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 0d8e85094646..1bbd45192bea 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
@@ -107,6 +107,7 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
+import com.android.systemui.util.DumpUtilsKt;
import com.android.systemui.wmshell.BubblesManager;
import java.io.FileDescriptor;
@@ -1249,6 +1250,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
@Override
public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
if (mMenuRow != null && mMenuRow.getMenuView() != null) {
mMenuRow.onConfigurationChanged();
}
@@ -1758,7 +1760,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
* Called when a notification is dropped on proper target window.
*/
public void dragAndDropSuccess() {
- mOnDragSuccessListener.onDragSuccess(getEntry());
+ if (mOnDragSuccessListener != null) {
+ mOnDragSuccessListener.onDragSuccess(getEntry());
+ }
}
private void doLongClickCallback() {
@@ -3201,13 +3205,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
- /** Sets whether dismiss gestures are right-to-left (instead of left-to-right). */
- public void setDismissRtl(boolean dismissRtl) {
- if (mMenuRow != null) {
- mMenuRow.setDismissRtl(dismissRtl);
- }
- }
-
private static class NotificationViewState extends ExpandableViewState {
@Override
@@ -3311,40 +3308,45 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- super.dump(fd, pw, args);
- pw.println(" Notification: " + mEntry.getKey());
- pw.print(" visibility: " + getVisibility());
- pw.print(", alpha: " + getAlpha());
- pw.print(", translation: " + getTranslation());
- pw.print(", removed: " + isRemoved());
- pw.print(", expandAnimationRunning: " + mExpandAnimationRunning);
- NotificationContentView showingLayout = getShowingLayout();
- pw.print(", privateShowing: " + (showingLayout == mPrivateLayout));
- pw.println();
- showingLayout.dump(fd, pw, args);
- pw.print(" ");
- if (getViewState() != null) {
- getViewState().dump(fd, pw, args);
- } else {
- pw.print("no viewState!!!");
- }
- pw.println();
- pw.println();
- if (mIsSummaryWithChildren) {
- pw.print(" ChildrenContainer");
- pw.print(" visibility: " + mChildrenContainer.getVisibility());
- pw.print(", alpha: " + mChildrenContainer.getAlpha());
- pw.print(", translationY: " + mChildrenContainer.getTranslationY());
- pw.println();
- List<ExpandableNotificationRow> notificationChildren = getAttachedChildren();
- pw.println(" Children: " + notificationChildren.size());
- pw.println(" {");
- for(ExpandableNotificationRow child : notificationChildren) {
- child.dump(fd, pw, args);
- }
- pw.println(" }");
- pw.println();
- }
+ // Skip super call; dump viewState ourselves
+ pw.println("Notification: " + mEntry.getKey());
+ DumpUtilsKt.withIndenting(pw, ipw -> {
+ ipw.print("visibility: " + getVisibility());
+ ipw.print(", alpha: " + getAlpha());
+ ipw.print(", translation: " + getTranslation());
+ ipw.print(", removed: " + isRemoved());
+ ipw.print(", expandAnimationRunning: " + mExpandAnimationRunning);
+ NotificationContentView showingLayout = getShowingLayout();
+ ipw.print(", privateShowing: " + (showingLayout == mPrivateLayout));
+ ipw.println();
+ showingLayout.dump(fd, ipw, args);
+
+ if (getViewState() != null) {
+ getViewState().dump(fd, ipw, args);
+ ipw.println();
+ } else {
+ ipw.println("no viewState!!!");
+ }
+
+ if (mIsSummaryWithChildren) {
+ ipw.println();
+ ipw.print("ChildrenContainer");
+ ipw.print(" visibility: " + mChildrenContainer.getVisibility());
+ ipw.print(", alpha: " + mChildrenContainer.getAlpha());
+ ipw.print(", translationY: " + mChildrenContainer.getTranslationY());
+ ipw.println();
+ List<ExpandableNotificationRow> notificationChildren = getAttachedChildren();
+ ipw.println("Children: " + notificationChildren.size());
+ ipw.print("{");
+ ipw.increaseIndent();
+ for (ExpandableNotificationRow child : notificationChildren) {
+ ipw.println();
+ child.dump(fd, ipw, args);
+ }
+ ipw.decreaseIndent();
+ ipw.println("}");
+ }
+ });
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 8b0764b1c313..fa2c1ee772cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -34,6 +34,7 @@ import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.util.DumpUtilsKt;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -743,6 +744,16 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println(getClass().getSimpleName());
+ DumpUtilsKt.withIndenting(pw, ipw -> {
+ ExpandableViewState viewState = getViewState();
+ if (viewState == null) {
+ ipw.println("no viewState!!!");
+ } else {
+ viewState.dump(fd, ipw, args);
+ ipw.println();
+ }
+ });
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
index 9eb95c409009..b27a40a828f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
@@ -25,6 +25,10 @@ import android.view.View;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.ViewState;
+import com.android.systemui.util.DumpUtilsKt;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
public class FooterView extends StackScrollerDecorView {
private FooterViewButton mDismissButton;
@@ -45,6 +49,19 @@ public class FooterView extends StackScrollerDecorView {
}
@Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ super.dump(fd, pw, args);
+ DumpUtilsKt.withIndenting(pw, ipw -> {
+ ipw.println("visibility: " + DumpUtilsKt.visibilityString(getVisibility()));
+ ipw.println("manageButton showHistory: " + mShowHistory);
+ ipw.println("manageButton visibility: "
+ + DumpUtilsKt.visibilityString(mDismissButton.getVisibility()));
+ ipw.println("dismissButton visibility: "
+ + DumpUtilsKt.visibilityString(mDismissButton.getVisibility()));
+ });
+ }
+
+ @Override
protected void onFinishInflate() {
super.onFinishInflate();
mDismissButton = (FooterViewButton) findSecondaryView();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 4f54e4feb21d..df484dd8ed77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1253,7 +1253,7 @@ public class NotificationContentView extends FrameLayout {
}
if (hasRemoteInput) {
existing.setWrapper(wrapper);
- existing.setOnVisibilityChangedListener(this::setRemoteInputVisible);
+ existing.addOnVisibilityChangedListener(this::setRemoteInputVisible);
if (existingPendingIntent != null || existing.isActive()) {
// The current action could be gone, or the pending intent no longer valid.
@@ -1938,7 +1938,6 @@ public class NotificationContentView extends FrameLayout {
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.print(" ");
pw.print("contentView visibility: " + getVisibility());
pw.print(", alpha: " + getAlpha());
pw.print(", clipBounds: " + getClipBounds());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 7eec95acc6ec..8e02d9f635d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -65,6 +65,8 @@ import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewListener;
+import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager;
import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -83,7 +85,8 @@ import dagger.Lazy;
* Handles various NotificationGuts related tasks, such as binding guts to a row, opening and
* closing guts, and keeping track of the currently exposed notification guts.
*/
-public class NotificationGutsManager implements Dumpable, NotificationLifetimeExtender {
+public class NotificationGutsManager implements Dumpable, NotificationLifetimeExtender,
+ NotifGutsViewManager {
private static final String TAG = "NotificationGutsManager";
// Must match constant in Settings. Used to highlight preferences when linking to Settings.
@@ -123,7 +126,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
private final Optional<BubblesManager> mBubblesManagerOptional;
private Runnable mOpenRunnable;
private final INotificationManager mNotificationManager;
- private final NotificationEntryManager mNotificationEntryManager;
private final PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
private final LauncherApps mLauncherApps;
private final ShortcutManager mShortcutManager;
@@ -131,6 +133,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
private final UiEventLogger mUiEventLogger;
private final ShadeController mShadeController;
private final AppWidgetManager mAppWidgetManager;
+ private NotifGutsViewListener mGutsListener;
/**
* Injected constructor. See {@link NotificationsModule}.
@@ -161,7 +164,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
mAccessibilityManager = accessibilityManager;
mHighPriorityProvider = highPriorityProvider;
mNotificationManager = notificationManager;
- mNotificationEntryManager = notificationEntryManager;
mPeopleSpaceWidgetManager = peopleSpaceWidgetManager;
mLauncherApps = launcherApps;
mShortcutManager = shortcutManager;
@@ -258,10 +260,10 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
@VisibleForTesting
protected boolean bindGuts(final ExpandableNotificationRow row,
NotificationMenuRowPlugin.MenuItem item) {
- StatusBarNotification sbn = row.getEntry().getSbn();
+ NotificationEntry entry = row.getEntry();
row.setGutsView(item);
- row.setTag(sbn.getPackageName());
+ row.setTag(entry.getSbn().getPackageName());
row.getGuts().setClosedListener((NotificationGuts g) -> {
row.onGutsClosed();
if (!g.willBeRemoved() && !row.isRemoved()) {
@@ -272,7 +274,10 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
mNotificationGutsExposed = null;
mGutsMenuItem = null;
}
- String key = sbn.getKey();
+ if (mGutsListener != null) {
+ mGutsListener.onGutsClose(entry);
+ }
+ String key = entry.getKey();
if (key.equals(mKeyToRemoveOnGutsClosed)) {
mKeyToRemoveOnGutsClosed = null;
if (mNotificationLifetimeFinishedCallback != null) {
@@ -650,6 +655,10 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
needsFalsingProtection,
row::onGutsOpened);
+ if (mGutsListener != null) {
+ mGutsListener.onGutsOpen(row.getEntry(), guts);
+ }
+
row.closeRemoteInput();
mListContainer.onHeightChanged(row, true /* needsAnimation */);
mGutsMenuItem = menuItem;
@@ -695,10 +704,17 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("NotificationGutsManager state:");
- pw.print(" mKeyToRemoveOnGutsClosed: ");
+ pw.print(" mKeyToRemoveOnGutsClosed (legacy): ");
pw.println(mKeyToRemoveOnGutsClosed);
}
+ /**
+ * @param gutsListener the listener for open and close guts events
+ */
+ public void setGutsListener(NotifGutsViewListener gutsListener) {
+ mGutsListener = gutsListener;
+ }
+
public interface OnSettingsClickListener {
public void onSettingsClick(String key);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index d59318e45e7e..3a37fb44b33a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -85,7 +85,6 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl
private ArrayList<MenuItem> mRightMenuItems;
private final Map<View, MenuItem> mMenuItemsByView = new ArrayMap<>();
private OnMenuEventListener mMenuListener;
- private boolean mDismissRtl;
private ValueAnimator mFadeAnimator;
private boolean mAnimating;
@@ -790,14 +789,6 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl
return getParent().canViewBeDismissed();
}
- @Override
- public void setDismissRtl(boolean dismissRtl) {
- mDismissRtl = dismissRtl;
- if (mMenuContainer != null) {
- createMenuViews(true);
- }
- }
-
public static class NotificationMenuItem implements MenuItem {
View mMenuView;
GutsContent mGutsContent;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt
new file mode 100644
index 000000000000..31f4857e4b04
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt
@@ -0,0 +1,25 @@
+package com.android.systemui.statusbar.notification.stack
+
+import android.annotation.IntDef
+
+/**
+ * For now, declare the available notification buckets (sections) here so that other
+ * presentation code can decide what to do based on an entry's buckets
+ */
+@Retention(AnnotationRetention.SOURCE)
+@IntDef(
+ prefix = ["BUCKET_"],
+ value = [
+ BUCKET_UNKNOWN, BUCKET_MEDIA_CONTROLS, BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE,
+ BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT
+ ]
+)
+annotation class PriorityBucket
+
+const val BUCKET_UNKNOWN = 0
+const val BUCKET_MEDIA_CONTROLS = 1
+const val BUCKET_HEADS_UP = 2
+const val BUCKET_FOREGROUND_SERVICE = 3
+const val BUCKET_PEOPLE = 4
+const val BUCKET_ALERTING = 5
+const val BUCKET_SILENT = 6
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
index ab39de0f9bc7..bc172ce537f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar.notification.stack;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_MEDIA_CONTROLS;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_MEDIA_CONTROLS;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index 45ce20a1f08f..5f157a767c5e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.notification.stack
import android.annotation.ColorInt
-import android.annotation.IntDef
import android.annotation.LayoutRes
import android.util.Log
import android.view.LayoutInflater
@@ -350,7 +349,7 @@ class NotificationSectionsManager @Inject internal constructor(
silentHeaderView?.run {
val hasActiveClearableNotifications = this@NotificationSectionsManager.parent
.hasActiveClearableNotifications(NotificationStackScrollLayout.ROWS_GENTLE)
- setAreThereDismissableGentleNotifs(hasActiveClearableNotifications)
+ setClearSectionButtonEnabled(hasActiveClearableNotifications)
}
}
@@ -448,25 +447,3 @@ class NotificationSectionsManager @Inject internal constructor(
private const val DEBUG = false
}
}
-
-/**
- * For now, declare the available notification buckets (sections) here so that other
- * presentation code can decide what to do based on an entry's buckets
- */
-@Retention(AnnotationRetention.SOURCE)
-@IntDef(
- prefix = ["BUCKET_"],
- value = [
- BUCKET_UNKNOWN, BUCKET_MEDIA_CONTROLS, BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE,
- BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT
- ]
-)
-annotation class PriorityBucket
-
-const val BUCKET_UNKNOWN = 0
-const val BUCKET_MEDIA_CONTROLS = 1
-const val BUCKET_HEADS_UP = 2
-const val BUCKET_FOREGROUND_SERVICE = 3
-const val BUCKET_PEOPLE = 4
-const val BUCKET_ALERTING = 5
-const val BUCKET_SILENT = 6
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 7213b2fb46f9..6a127102b726 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
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.notification.stack;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_SWIPE;
import static com.android.systemui.util.Utils.shouldUseSplitNotificationShade;
@@ -109,6 +109,7 @@ import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.ScrollAdapter;
import com.android.systemui.util.Assert;
+import com.android.systemui.util.DumpUtilsKt;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -161,7 +162,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private final Paint mBackgroundPaint = new Paint();
private final boolean mShouldDrawNotificationBackground;
private boolean mHighPriorityBeforeSpeedBump;
- private boolean mDismissRtl;
private float mExpandedHeight;
private int mOwnScrollY;
@@ -613,16 +613,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
addView(mFgsSectionView, -1);
}
- void updateDismissRtlSetting(boolean dismissRtl) {
- mDismissRtl = dismissRtl;
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
- if (child instanceof ExpandableNotificationRow) {
- ((ExpandableNotificationRow) child).setDismissRtl(dismissRtl);
- }
- }
- }
-
/**
* Set the overexpansion of the panel to be applied to the view.
*/
@@ -664,6 +654,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
return 0f;
}
+ public float getNotificationSquishinessFraction() {
+ return mStackScrollAlgorithm.getNotificationSquishinessFraction(mAmbientState);
+ }
+
void reinflateViews() {
inflateFooterView();
inflateEmptyShadeView();
@@ -2911,7 +2905,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
updateChronometerForChild(child);
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- row.setDismissRtl(mDismissRtl);
row.setDismissUsingRowTranslationX(mDismissUsingRowTranslationX);
}
@@ -4907,54 +4900,42 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println(String.format("[%s: pulsing=%s visibility=%s"
- + " alpha=%f scrollY:%d maxTopPadding=%d showShelfOnly=%s"
- + " qsExpandFraction=%f"
- + " hideAmount=%f]",
- this.getClass().getSimpleName(),
- mPulsing ? "T" : "f",
- getVisibility() == View.VISIBLE ? "visible"
- : getVisibility() == View.GONE ? "gone"
- : "invisible",
- getAlpha(),
- mAmbientState.getScrollY(),
- mMaxTopPadding,
- mShouldShowShelfOnly ? "T" : "f",
- mQsExpansionFraction,
- mAmbientState.getHideAmount()));
- int childCount = getChildCount();
- pw.println(" Number of children: " + childCount);
- pw.println();
+ StringBuilder sb = new StringBuilder("[")
+ .append(this.getClass().getSimpleName()).append(":")
+ .append(" pulsing=").append(mPulsing ? "T" : "f")
+ .append(" visibility=").append(DumpUtilsKt.visibilityString(getVisibility()))
+ .append(" alpha=").append(getAlpha())
+ .append(" scrollY=").append(mAmbientState.getScrollY())
+ .append(" maxTopPadding=").append(mMaxTopPadding)
+ .append(" showShelfOnly=").append(mShouldShowShelfOnly ? "T" : "f")
+ .append(" qsExpandFraction=").append(mQsExpansionFraction)
+ .append(" isCurrentUserSetup=").append(mIsCurrentUserSetup)
+ .append(" hideAmount=").append(mAmbientState.getHideAmount())
+ .append("]");
+ pw.println(sb.toString());
+ DumpUtilsKt.withIndenting(pw, ipw -> {
+ int childCount = getChildCount();
+ ipw.println("Number of children: " + childCount);
+ ipw.println();
- for (int i = 0; i < childCount; i++) {
- ExpandableView child = (ExpandableView) getChildAt(i);
- child.dump(fd, pw, args);
- if (!(child instanceof ExpandableNotificationRow)) {
- pw.println(" " + child.getClass().getSimpleName());
- // Notifications dump it's viewstate as part of their dump to support children
- ExpandableViewState viewState = child.getViewState();
- if (viewState == null) {
- pw.println(" no viewState!!!");
- } else {
- pw.print(" ");
- viewState.dump(fd, pw, args);
- pw.println();
- pw.println();
- }
+ for (int i = 0; i < childCount; i++) {
+ ExpandableView child = (ExpandableView) getChildAt(i);
+ child.dump(fd, ipw, args);
+ ipw.println();
+ }
+ int transientViewCount = getTransientViewCount();
+ pw.println("Transient Views: " + transientViewCount);
+ for (int i = 0; i < transientViewCount; i++) {
+ ExpandableView child = (ExpandableView) getTransientView(i);
+ child.dump(fd, pw, args);
+ }
+ View swipedView = mSwipeHelper.getSwipedView();
+ pw.println("Swiped view: " + swipedView);
+ if (swipedView instanceof ExpandableView) {
+ ExpandableView expandableView = (ExpandableView) swipedView;
+ expandableView.dump(fd, pw, args);
}
- }
- int transientViewCount = getTransientViewCount();
- pw.println(" Transient Views: " + transientViewCount);
- for (int i = 0; i < transientViewCount; i++) {
- ExpandableView child = (ExpandableView) getTransientView(i);
- child.dump(fd, pw, args);
- }
- View swipedView = mSwipeHelper.getSwipedView();
- pw.println(" Swiped view: " + swipedView);
- if (swipedView instanceof ExpandableView) {
- ExpandableView expandableView = (ExpandableView) swipedView;
- expandableView.dump(fd, pw, args);
- }
+ });
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
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 b226aec88cd8..03fc76760133 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
@@ -783,9 +783,6 @@ public class NotificationStackScrollLayoutController {
mTunerService.addTunable(
(key, newValue) -> {
switch (key) {
- case Settings.Secure.NOTIFICATION_DISMISS_RTL:
- mView.updateDismissRtlSetting("1".equals(newValue));
- break;
case Settings.Secure.NOTIFICATION_HISTORY_ENABLED:
updateFooter();
break;
@@ -795,7 +792,6 @@ public class NotificationStackScrollLayoutController {
}
},
HIGH_PRIORITY,
- Settings.Secure.NOTIFICATION_DISMISS_RTL,
Settings.Secure.NOTIFICATION_HISTORY_ENABLED);
mKeyguardMediaController.setVisibilityChangedListener(visible -> {
@@ -810,14 +806,15 @@ public class NotificationStackScrollLayoutController {
return Unit.INSTANCE;
});
- // callback is invoked synchronously, updating mView immediately
+ // attach callback, and then call it to update mView immediately
mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
+ mDeviceProvisionedListener.onDeviceProvisionedChanged();
if (mView.isAttachedToWindow()) {
mOnAttachStateChangeListener.onViewAttachedToWindow(mView);
}
mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
- mSilentHeaderController.setOnClearAllClickListener(v -> clearSilentNotifications());
+ mSilentHeaderController.setOnClearSectionClickListener(v -> clearSilentNotifications());
}
private boolean isInVisibleLocation(NotificationEntry entry) {
@@ -1077,6 +1074,10 @@ public class NotificationStackScrollLayoutController {
mView.setOnStackYChanged(onStackYChanged);
}
+ public float getNotificationSquishinessFraction() {
+ return mView.getNotificationSquishinessFraction();
+ }
+
public float calculateAppearFractionBypass() {
return mView.calculateAppearFractionBypass();
}
@@ -1300,6 +1301,9 @@ public class NotificationStackScrollLayoutController {
}
public void updateSectionBoundaries(String reason) {
+ if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+ return;
+ }
mView.updateSectionBoundaries(reason);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
index 99ec7548fb9d..baf09c70f936 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
@@ -85,8 +85,12 @@ public class SectionHeaderView extends StackScrollerDecorView {
return true;
}
- void setAreThereDismissableGentleNotifs(boolean areThereDismissableGentleNotifs) {
- mClearAllButton.setVisibility(areThereDismissableGentleNotifs ? View.VISIBLE : View.GONE);
+ /**
+ * Show the clear section [X] button
+ * @param enabled
+ */
+ public void setClearSectionButtonEnabled(boolean enabled) {
+ mClearAllButton.setVisibility(enabled ? View.VISIBLE : View.GONE);
}
@Override
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 afe0bbafbd31..015edb8e5541 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
@@ -110,6 +110,15 @@ public class StackScrollAlgorithm {
getNotificationChildrenStates(algorithmState, ambientState);
}
+ /**
+ * How expanded or collapsed notifications are when pulling down the shade.
+ * @param ambientState Current ambient state.
+ * @return 0 when fully collapsed, 1 when expanded.
+ */
+ public float getNotificationSquishinessFraction(AmbientState ambientState) {
+ return getExpansionFractionWithoutShelf(mTempAlgorithmState, ambientState);
+ }
+
private void resetChildViewStates() {
int numChildren = mHostView.getChildCount();
for (int i = 0; i < numChildren; i++) {
@@ -364,7 +373,6 @@ public class StackScrollAlgorithm {
final float stackHeight = ambientState.getStackHeight() - shelfHeight - scrimPadding;
final float stackEndHeight = ambientState.getStackEndHeight() - shelfHeight - scrimPadding;
-
return stackHeight / stackEndHeight;
}
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 989f6b85668b..fe621da17767 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -26,6 +26,7 @@ import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedul
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.SHOWING_PERSISTENT_DOT;
import android.animation.ValueAnimator;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Fragment;
import android.os.Bundle;
@@ -46,13 +47,15 @@ import com.android.systemui.statusbar.DisableFlagsLogger.DisableState;
import com.android.systemui.statusbar.OperatorNameView;
import com.android.systemui.statusbar.OperatorNameViewController;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.connectivity.IconState;
import com.android.systemui.statusbar.connectivity.NetworkController;
-import com.android.systemui.statusbar.connectivity.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.connectivity.SignalCallback;
import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallListener;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.EncryptionHelper;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -101,13 +104,15 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private final StatusBarLocationPublisher mLocationPublisher;
private final FeatureFlags mFeatureFlags;
private final NotificationIconAreaController mNotificationIconAreaController;
+ private final PanelExpansionStateManager mPanelExpansionStateManager;
private final StatusBarIconController mStatusBarIconController;
+ private final StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
private List<String> mBlockedIcons = new ArrayList<>();
private SignalCallback mSignalCallback = new SignalCallback() {
@Override
- public void setIsAirplaneMode(NetworkController.IconState icon) {
+ public void setIsAirplaneMode(@NonNull IconState icon) {
mCommandQueue.recomputeDisableFlags(getContext().getDisplayId(), true /* animate */);
}
};
@@ -126,9 +131,11 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
SystemStatusAnimationScheduler animationScheduler,
StatusBarLocationPublisher locationPublisher,
NotificationIconAreaController notificationIconAreaController,
+ PanelExpansionStateManager panelExpansionStateManager,
FeatureFlags featureFlags,
Lazy<Optional<StatusBar>> statusBarOptionalLazy,
StatusBarIconController statusBarIconController,
+ StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
KeyguardStateController keyguardStateController,
NetworkController networkController,
StatusBarStateController statusBarStateController,
@@ -140,9 +147,11 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mAnimationScheduler = animationScheduler;
mLocationPublisher = locationPublisher;
mNotificationIconAreaController = notificationIconAreaController;
+ mPanelExpansionStateManager = panelExpansionStateManager;
mFeatureFlags = featureFlags;
mStatusBarOptionalLazy = statusBarOptionalLazy;
mStatusBarIconController = statusBarIconController;
+ mStatusBarHideIconsForBouncerManager = statusBarHideIconsForBouncerManager;
mKeyguardStateController = keyguardStateController;
mNetworkController = networkController;
mStatusBarStateController = statusBarStateController;
@@ -253,8 +262,8 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
state1 = adjustDisableFlags(state1);
mCollapsedStatusBarFragmentLogger.logDisableFlagChange(
- new DisableState(state1BeforeAdjustment, state2),
- new DisableState(state1, state2));
+ /* new= */ new DisableState(state1BeforeAdjustment, state2),
+ /* newAfterLocalModification= */ new DisableState(state1, state2));
final int old1 = mDisabled1;
final int diff1 = state1 ^ old1;
@@ -363,15 +372,12 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private boolean shouldHideNotificationIcons() {
final Optional<StatusBar> statusBarOptional = mStatusBarOptionalLazy.get();
- if (!mStatusBar.isClosed()
+ if (!mPanelExpansionStateManager.isClosed()
&& statusBarOptional.map(
StatusBar::hideStatusBarIconsWhenExpanded).orElse(false)) {
return true;
}
- if (statusBarOptional.map(StatusBar::hideStatusBarIconsForBouncer).orElse(false)) {
- return true;
- }
- return false;
+ return mStatusBarHideIconsForBouncerManager.getShouldHideStatusBarIconsForBouncer();
}
private void hideSystemIconArea(boolean animate) {
@@ -409,7 +415,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
* don't set the clock GONE otherwise it'll mess up the animation.
*/
private int clockHiddenMode() {
- if (!mStatusBar.isClosed() && !mKeyguardStateController.isShowing()
+ if (!mPanelExpansionStateManager.isClosed() && !mKeyguardStateController.isShowing()
&& !mStatusBarStateController.isDozing()) {
return View.INVISIBLE;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentLogger.kt
index 3c2b555eea68..4d472e47a387 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentLogger.kt
@@ -28,22 +28,31 @@ class CollapsedStatusBarFragmentLogger @Inject constructor(
private val disableFlagsLogger: DisableFlagsLogger,
) {
- /** Logs a string representing the old and new disable flag states to [buffer]. */
+ /**
+ * Logs a string representing the new state received by [CollapsedStatusBarFragment] and any
+ * modifications that were made to the flags locally.
+ *
+ * @param new see [DisableFlagsLogger.getDisableFlagsString]
+ * @param newAfterLocalModification see [DisableFlagsLogger.getDisableFlagsString]
+ */
fun logDisableFlagChange(
- oldState: DisableFlagsLogger.DisableState,
- newState: DisableFlagsLogger.DisableState) {
+ new: DisableFlagsLogger.DisableState,
+ newAfterLocalModification: DisableFlagsLogger.DisableState
+ ) {
buffer.log(
TAG,
LogLevel.INFO,
{
- int1 = oldState.disable1
- int2 = oldState.disable2
- long1 = newState.disable1.toLong()
- long2 = newState.disable2.toLong()
+ int1 = new.disable1
+ int2 = new.disable2
+ long1 = newAfterLocalModification.disable1.toLong()
+ long2 = newAfterLocalModification.disable2.toLong()
},
{
disableFlagsLogger.getDisableFlagsString(
- DisableFlagsLogger.DisableState(int1, int2),
+ old = null,
+ new = DisableFlagsLogger.DisableState(int1, int2),
+ newAfterLocalModification =
DisableFlagsLogger.DisableState(long1.toInt(), long2.toInt())
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 21c3e5e0a8d0..7de4668abe28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -21,7 +21,6 @@ import android.os.Handler;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
@@ -92,10 +91,14 @@ public class DozeScrimController implements StateListener {
};
@Inject
- public DozeScrimController(DozeParameters dozeParameters, DozeLog dozeLog) {
+ public DozeScrimController(
+ DozeParameters dozeParameters,
+ DozeLog dozeLog,
+ StatusBarStateController statusBarStateController
+ ) {
mDozeParameters = dozeParameters;
- //Never expected to be destroyed
- Dependency.get(StatusBarStateController.class).addCallback(this);
+ // Never expected to be destroyed
+ statusBarStateController.addCallback(this);
mDozeLog = dozeLog;
}
@@ -219,6 +222,10 @@ public class DozeScrimController implements StateListener {
@Override
public void onDozingChanged(boolean isDozing) {
+ if (mDozing != isDozing) {
+ mDozeLog.traceDozingChanged(isDozing);
+ }
+
setDozing(isDozing);
}
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index c639eecf037c..e26f75f7ce40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -1078,10 +1078,14 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(ControlsUiController.EXTRA_ANIMATE, true);
+ ActivityLaunchAnimator.Controller controller =
+ v != null ? ActivityLaunchAnimator.Controller.fromView(v, null /* cujType */)
+ : null;
if (mControlsComponent.getVisibility() == AVAILABLE) {
- mContext.startActivity(intent);
+ mActivityStarter.startActivity(intent, true /* dismissShade */, controller,
+ true /* showOverLockscreenWhenLocked */);
} else {
- mActivityStarter.postStartActivityDismissingKeyguard(intent, 0 /* delay */);
+ mActivityStarter.postStartActivityDismissingKeyguard(intent, 0 /* delay */, controller);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index b9b663c33a45..353868ba969f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -45,6 +45,7 @@ import com.android.systemui.dagger.qualifiers.RootView;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.ListenerSet;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -84,11 +85,11 @@ public class KeyguardBouncer {
private final Runnable mRemoveViewRunnable = this::removeView;
private final KeyguardBypassController mKeyguardBypassController;
private KeyguardHostViewController mKeyguardViewController;
- private final List<KeyguardResetCallback> mResetCallbacks = new ArrayList<>();
+ private final ListenerSet<KeyguardResetCallback> mResetCallbacks = new ListenerSet<>();
private final Runnable mResetRunnable = ()-> {
if (mKeyguardViewController != null) {
mKeyguardViewController.resetSecurityContainer();
- for (KeyguardResetCallback callback : new ArrayList<>(mResetCallbacks)) {
+ for (KeyguardResetCallback callback : mResetCallbacks) {
callback.onKeyguardReset();
}
}
@@ -602,7 +603,7 @@ public class KeyguardBouncer {
}
public void addKeyguardResetCallback(KeyguardResetCallback callback) {
- mResetCallbacks.add(callback);
+ mResetCallbacks.addIfAbsent(callback);
}
public void removeKeyguardResetCallback(KeyguardResetCallback callback) {
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 e368aad31ac8..7ca8652e1b3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -57,21 +57,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.
*/
@@ -88,6 +73,16 @@ public class KeyguardClockPositionAlgorithm {
private int mContainerTopPadding;
/**
+ * Top margin of notifications introduced by presence of split shade header / status bar
+ */
+ private int mSplitShadeTopNotificationsMargin;
+
+ /**
+ * Target margin for notifications and clock from the top of the screen in split shade
+ */
+ private int mSplitShadeTargetTopMargin;
+
+ /**
* @see NotificationPanelViewController#getExpandedFraction()
*/
private float mPanelExpansion;
@@ -152,6 +147,10 @@ public class KeyguardClockPositionAlgorithm {
public void loadDimens(Resources res) {
mStatusViewBottomMargin = res.getDimensionPixelSize(
R.dimen.keyguard_status_view_bottom_margin);
+ mSplitShadeTopNotificationsMargin =
+ res.getDimensionPixelSize(R.dimen.split_shade_header_height);
+ mSplitShadeTargetTopMargin =
+ res.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin);
mContainerTopPadding =
res.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin);
@@ -195,29 +194,47 @@ public class KeyguardClockPositionAlgorithm {
1.0f /* panelExpansion */, 1.0f /* darkAmount */);
result.clockAlpha = getClockAlpha(y);
result.stackScrollerPadding = getStackScrollerPadding(y);
- result.stackScrollerPaddingExpanded = mBypassEnabled ? mUnlockedStackScrollerPadding
- : getClockY(1.0f, mDarkAmount) + mKeyguardStatusHeight;
+ result.stackScrollerPaddingExpanded = getStackScrollerPaddingExpanded();
result.clockX = (int) interpolate(0, burnInPreventionOffsetX(), mDarkAmount);
result.clockScale = interpolate(getBurnInScale(), 1.0f, 1.0f - mDarkAmount);
}
+ private int getStackScrollerPaddingExpanded() {
+ if (mBypassEnabled) {
+ return mUnlockedStackScrollerPadding;
+ } else if (mIsSplitShade) {
+ return getClockY(1.0f, mDarkAmount);
+ } else {
+ return getClockY(1.0f, mDarkAmount) + mKeyguardStatusHeight;
+ }
+ }
+
private int getStackScrollerPadding(int clockYPosition) {
if (mBypassEnabled) {
return (int) (mUnlockedStackScrollerPadding + mOverStretchAmount);
} else if (mIsSplitShade) {
- return clockYPosition;
+ return Math.max(0, clockYPosition - mSplitShadeTopNotificationsMargin);
} else {
return clockYPosition + mKeyguardStatusHeight;
}
}
public float getMinStackScrollerPadding() {
- return mBypassEnabled ? mUnlockedStackScrollerPadding
- : mMinTopMargin + mKeyguardStatusHeight;
+ if (mBypassEnabled) {
+ return mUnlockedStackScrollerPadding;
+ } else if (mIsSplitShade) {
+ return Math.max(mSplitShadeTargetTopMargin, mMinTopMargin);
+ } else {
+ return mMinTopMargin + mKeyguardStatusHeight;
+ }
}
private int getExpandedPreferredClockY() {
- return mMinTopMargin + mUserSwitchHeight;
+ if (mIsSplitShade) {
+ return Math.max(mSplitShadeTargetTopMargin, mMinTopMargin);
+ } else {
+ return mMinTopMargin;
+ }
}
public int getLockscreenStatusViewHeight() {
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 03f3b0cab65c..f068a8ec8294 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -238,35 +238,32 @@ public class KeyguardStatusBarView extends RelativeLayout {
}
}
- @Override
- public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ /** Should only be called from {@link KeyguardStatusBarViewController}. */
+ WindowInsets updateWindowInsets(
+ WindowInsets insets,
+ StatusBarContentInsetsProvider insetsProvider) {
mLayoutState = LAYOUT_NONE;
- if (updateLayoutConsideringCutout()) {
+ if (updateLayoutConsideringCutout(insetsProvider)) {
requestLayout();
}
return super.onApplyWindowInsets(insets);
}
- private boolean updateLayoutConsideringCutout() {
+ private boolean updateLayoutConsideringCutout(StatusBarContentInsetsProvider insetsProvider) {
mDisplayCutout = getRootWindowInsets().getDisplayCutout();
updateKeyguardStatusBarHeight();
-
- Pair<Integer, Integer> cornerCutoutMargins =
- StatusBarWindowView.cornerCutoutMargins(mDisplayCutout, getDisplay());
- updatePadding(cornerCutoutMargins);
- if (mDisplayCutout == null || cornerCutoutMargins != null) {
+ updatePadding(insetsProvider);
+ if (mDisplayCutout == null || insetsProvider.currentRotationHasCornerCutout()) {
return updateLayoutParamsNoCutout();
} else {
return updateLayoutParamsForCutout();
}
}
- private void updatePadding(Pair<Integer, Integer> cornerCutoutMargins) {
+ private void updatePadding(StatusBarContentInsetsProvider insetsProvider) {
final int waterfallTop =
mDisplayCutout == null ? 0 : mDisplayCutout.getWaterfallInsets().top;
- mPadding =
- StatusBarWindowView.paddingNeededForCutoutAndRoundedCorner(
- mDisplayCutout, cornerCutoutMargins, mRoundedCornerPadding);
+ mPadding = insetsProvider.getStatusBarContentInsetsForCurrentRotation();
// consider privacy dot space
final int minLeft = (isLayoutRtl() && mIsPrivacyDotEnabled)
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 90550818bbdd..e7d5724fa9bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -91,6 +91,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final BiometricUnlockController mBiometricUnlockController;
private final SysuiStatusBarStateController mStatusBarStateController;
+ private final StatusBarContentInsetsProvider mInsetsProvider;
private final ConfigurationController.ConfigurationListener mConfigurationListener =
new ConfigurationController.ConfigurationListener() {
@@ -228,7 +229,9 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
KeyguardBypassController bypassController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
BiometricUnlockController biometricUnlockController,
- SysuiStatusBarStateController statusBarStateController) {
+ SysuiStatusBarStateController statusBarStateController,
+ StatusBarContentInsetsProvider statusBarContentInsetsProvider
+ ) {
super(view);
mCarrierTextController = carrierTextController;
mConfigurationController = configurationController;
@@ -244,6 +247,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mBiometricUnlockController = biometricUnlockController;
mStatusBarStateController = statusBarStateController;
+ mInsetsProvider = statusBarContentInsetsProvider;
mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
mKeyguardStateController.addCallback(
@@ -287,6 +291,9 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
mTintedIconManager.setBlockList(mBlockedIcons);
mStatusBarIconController.addIconGroup(mTintedIconManager);
}
+ mView.setOnApplyWindowInsetsListener(
+ (view, windowInsets) -> mView.updateWindowInsets(windowInsets, mInsetsProvider));
+
onThemeChanged();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index 2a13e6bbd37e..e565a44e7e1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -45,7 +45,6 @@ import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.keyguard.FaceAuthScreenBrightnessController;
import com.android.systemui.statusbar.NotificationMediaManager;
import libcore.io.IoUtils;
@@ -53,7 +52,6 @@ import libcore.io.IoUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Objects;
-import java.util.Optional;
import javax.inject.Inject;
@@ -70,7 +68,6 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen
private final WallpaperManager mWallpaperManager;
private final KeyguardUpdateMonitor mUpdateMonitor;
private final Handler mH;
- private final Optional<FaceAuthScreenBrightnessController> mFaceAuthScreenBrightnessController;
private boolean mCached;
private Bitmap mCache;
@@ -86,14 +83,12 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen
KeyguardUpdateMonitor keyguardUpdateMonitor,
DumpManager dumpManager,
NotificationMediaManager mediaManager,
- Optional<FaceAuthScreenBrightnessController> faceAuthScreenBrightnessController,
@Main Handler mainHandler) {
dumpManager.registerDumpable(getClass().getSimpleName(), this);
mWallpaperManager = wallpaperManager;
mCurrentUserId = ActivityManager.getCurrentUser();
mUpdateMonitor = keyguardUpdateMonitor;
mMediaManager = mediaManager;
- mFaceAuthScreenBrightnessController = faceAuthScreenBrightnessController;
mH = mainHandler;
if (iWallpaperManager != null) {
@@ -132,14 +127,6 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen
return LoaderResult.success(null);
}
- Bitmap faceAuthWallpaper = null;
- if (mFaceAuthScreenBrightnessController.isPresent()) {
- faceAuthWallpaper = mFaceAuthScreenBrightnessController.get().getFaceAuthWallpaper();
- if (faceAuthWallpaper != null) {
- return LoaderResult.success(faceAuthWallpaper);
- }
- }
-
// Prefer the selected user (when specified) over the current user for the FLAG_SET_LOCK
// wallpaper.
final int lockWallpaperUserId =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 6516abd143ed..e66ad6144072 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -6,6 +6,7 @@ import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Rect;
import android.os.Bundle;
+import android.os.Trace;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
@@ -38,6 +39,7 @@ import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.wm.shell.bubbles.Bubbles;
import java.util.ArrayList;
@@ -336,12 +338,14 @@ public class NotificationIconAreaController implements
}
private void updateNotificationIcons() {
+ Trace.beginSection("NotificationIconAreaController.updateNotificationIcons");
updateStatusBarIcons();
updateShelfIcons();
updateCenterIcon();
updateAodNotificationIcons();
applyNotificationIconsTint();
+ Trace.endSection();
}
private void updateShelfIcons() {
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 233acfe601a7..988034f9c5fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -22,6 +22,7 @@ import static androidx.constraintlayout.widget.ConstraintSet.END;
import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;
import static androidx.constraintlayout.widget.ConstraintSet.START;
import static androidx.constraintlayout.widget.ConstraintSet.TOP;
+import static androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
@@ -34,9 +35,9 @@ import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
-import static com.android.systemui.statusbar.phone.PanelBar.STATE_CLOSED;
-import static com.android.systemui.statusbar.phone.PanelBar.STATE_OPEN;
-import static com.android.systemui.statusbar.phone.PanelBar.STATE_OPENING;
+import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_CLOSED;
+import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_OPEN;
+import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_OPENING;
import static java.lang.Float.isNaN;
@@ -98,6 +99,7 @@ import com.android.internal.policy.SystemBarUtils;
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.KeyguardStatusView;
import com.android.keyguard.KeyguardStatusViewController;
+import com.android.keyguard.KeyguardUnfoldTransition;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.LockIconViewController;
import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent;
@@ -116,6 +118,7 @@ import com.android.systemui.controls.dagger.ControlsComponent;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeLog;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.media.KeyguardMediaController;
@@ -169,12 +172,15 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
+import com.android.systemui.statusbar.phone.panelstate.PanelState;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
+import com.android.systemui.unfold.SysUIUnfoldComponent;
import com.android.systemui.util.Utils;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.wallet.controller.QuickAccessWalletController;
@@ -185,6 +191,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -419,6 +426,9 @@ public class NotificationPanelViewController extends PanelViewController {
private boolean mIsFullWidth;
private boolean mBlockingExpansionForCurrentTouch;
+ // TODO (b/204204226): no longer needed once refactor is complete
+ private final boolean mUseCombinedQSHeaders;
+
/**
* Following variables maintain state of events when input focus transfer may occur.
*/
@@ -438,7 +448,6 @@ public class NotificationPanelViewController extends PanelViewController {
private boolean mPulsing;
private boolean mUserSetupComplete;
- private int mQsNotificationTopPadding;
private boolean mHideIconsDuringLaunchAnimation = true;
private int mStackScrollerMeasuringPass;
private ArrayList<Consumer<ExpandableNotificationRow>>
@@ -600,6 +609,8 @@ public class NotificationPanelViewController extends PanelViewController {
private boolean mStatusViewCentered = true;
+ private Optional<KeyguardUnfoldTransition> mKeyguardUnfoldTransition;
+
private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() {
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
@@ -687,8 +698,11 @@ public class NotificationPanelViewController extends PanelViewController {
SplitShadeHeaderController splitShadeHeaderController,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
LockscreenGestureLogger lockscreenGestureLogger,
+ PanelExpansionStateManager panelExpansionStateManager,
NotificationRemoteInputManager remoteInputManager,
- ControlsComponent controlsComponent) {
+ Optional<SysUIUnfoldComponent> unfoldComponent,
+ ControlsComponent controlsComponent,
+ FeatureFlags featureFlags) {
super(view,
falsingManager,
dozeLog,
@@ -700,6 +714,7 @@ public class NotificationPanelViewController extends PanelViewController {
flingAnimationUtilsBuilder.get(),
statusBarTouchableRegionManager,
lockscreenGestureLogger,
+ panelExpansionStateManager,
ambientState);
mView = view;
mVibratorHelper = vibratorHelper;
@@ -768,6 +783,8 @@ public class NotificationPanelViewController extends PanelViewController {
new DynamicPrivacyControlListener();
dynamicPrivacyController.addListener(dynamicPrivacyControlListener);
+ panelExpansionStateManager.addStateListener(this::onPanelStateChanged);
+
mBottomAreaShadeAlphaAnimator = ValueAnimator.ofFloat(1f, 0);
mBottomAreaShadeAlphaAnimator.addUpdateListener(animation -> {
mBottomAreaShadeAlpha = (float) animation.getAnimatedValue();
@@ -801,8 +818,11 @@ public class NotificationPanelViewController extends PanelViewController {
}
mMaxKeyguardNotifications = resources.getInteger(R.integer.keyguard_max_notification_count);
+ mKeyguardUnfoldTransition = unfoldComponent.map(c -> c.getKeyguardUnfoldTransition());
updateUserSwitcherFlags();
onFinishInflate();
+
+ mUseCombinedQSHeaders = featureFlags.useCombinedQSHeaders();
}
private void onFinishInflate() {
@@ -829,11 +849,12 @@ public class NotificationPanelViewController extends PanelViewController {
.getKeyguardStatusBarViewController();
mKeyguardStatusBarViewController.init();
+ mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent);
updateViewControllers(
mView.findViewById(R.id.keyguard_status_view),
userAvatarContainer,
keyguardUserSwitcherView);
- mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent);
+
NotificationStackScrollLayout stackScrollLayout = mView.findViewById(
R.id.notification_stack_scroller);
mNotificationStackScrollLayoutController.attach(stackScrollLayout);
@@ -884,6 +905,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
mTapAgainViewController.init();
+ mKeyguardUnfoldTransition.ifPresent(u -> u.setup(mView));
}
@Override
@@ -1002,6 +1024,9 @@ public class NotificationPanelViewController extends PanelViewController {
} else {
constraintSet.connect(R.id.qs_frame, END, PARENT_ID, END);
constraintSet.connect(R.id.notification_stack_scroller, START, PARENT_ID, START);
+ if (mUseCombinedQSHeaders) {
+ constraintSet.constrainHeight(R.id.split_shade_status_bar, WRAP_CONTENT);
+ }
}
constraintSet.getConstraint(R.id.notification_stack_scroller).layout.mWidth = panelWidth;
constraintSet.getConstraint(R.id.qs_frame).layout.mWidth = qsWidth;
@@ -1124,6 +1149,8 @@ public class NotificationPanelViewController extends PanelViewController {
mBarState);
}
setKeyguardBottomAreaVisibility(mBarState, false);
+
+ mKeyguardUnfoldTransition.ifPresent(u -> u.setup(mView));
}
private void attachSplitShadeMediaPlayerContainer(FrameLayout container) {
@@ -1537,7 +1564,7 @@ public class NotificationPanelViewController extends PanelViewController {
// it's possible that nothing animated, so we replicate the termination
// conditions of panelExpansionChanged here
// TODO(b/200063118): This can likely go away in a future refactor CL.
- mBar.updateState(STATE_CLOSED);
+ getPanelExpansionStateManager().updateState(STATE_CLOSED);
}
}
@@ -1622,7 +1649,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
public void fling(float vel, boolean expand) {
- GestureRecorder gr = ((PhoneStatusBarView) mBar).mBar.getGestureRecorder();
+ GestureRecorder gr = mStatusBar.getGestureRecorder();
if (gr != null) {
gr.tag("fling " + ((vel > 0) ? "open" : "closed"), "notifications,v=" + vel);
}
@@ -2179,7 +2206,7 @@ public class NotificationPanelViewController extends PanelViewController {
mQs.setExpanded(mQsExpanded);
}
- private void setQsExpansion(float height) {
+ void setQsExpansion(float height) {
height = Math.min(Math.max(height, mQsMinExpansionHeight), mQsMaxExpansionHeight);
mQsFullyExpanded = height == mQsMaxExpansionHeight && mQsMaxExpansionHeight != 0;
if (height > mQsMinExpansionHeight && !mQsExpanded && !mStackScrollerOverscrolling
@@ -2206,10 +2233,6 @@ public class NotificationPanelViewController extends PanelViewController {
mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
false /* dismissShade */, true /* afterKeyguardGone */, false /* deferred */);
}
- for (int i = 0; i < mExpansionListeners.size(); i++) {
- mExpansionListeners.get(i).onQsExpansionChanged(
- mQsMaxExpansionHeight != 0 ? mQsExpansionHeight / mQsMaxExpansionHeight : 0);
- }
if (DEBUG) {
mView.invalidate();
}
@@ -2218,12 +2241,22 @@ public class NotificationPanelViewController extends PanelViewController {
private void updateQsExpansion() {
if (mQs == null) return;
float qsExpansionFraction = computeQsExpansionFraction();
- mQs.setQsExpansion(qsExpansionFraction, getExpandedFraction(), getHeaderTranslation());
+ float squishiness = mNotificationStackScrollLayoutController
+ .getNotificationSquishinessFraction();
+ mQs.setQsExpansion(qsExpansionFraction, getExpandedFraction(), getHeaderTranslation(),
+ mQsExpandImmediate || mQsExpanded ? 1f : squishiness);
+ mSplitShadeHeaderController.setQsExpandedFraction(qsExpansionFraction);
mMediaHierarchyManager.setQsExpansion(qsExpansionFraction);
int qsPanelBottomY = calculateQsBottomPosition(qsExpansionFraction);
mScrimController.setQsPosition(qsExpansionFraction, qsPanelBottomY);
setQSClippingBounds();
- mNotificationStackScrollLayoutController.setQsExpansionFraction(qsExpansionFraction);
+
+ // Only need to notify the notification stack when we're not in split screen mode. If we
+ // do, then the notification panel starts scrolling along with the QS.
+ if (!mShouldUseSplitNotificationShade) {
+ mNotificationStackScrollLayoutController.setQsExpansionFraction(qsExpansionFraction);
+ }
+
mDepthController.setQsPanelExpansion(qsExpansionFraction);
}
@@ -2376,7 +2409,7 @@ public class NotificationPanelViewController extends PanelViewController {
// qsTranslation should only be positive during pulse expansion because it's
// already translating in from the top
qsTranslation = Math.max(0, (top - mQs.getHeader().getHeight()) / 2.0f);
- } else {
+ } else if (!mShouldUseSplitNotificationShade) {
qsTranslation = (top - mQs.getHeader().getHeight()) * QS_PARALLAX_AMOUNT;
}
}
@@ -3525,7 +3558,12 @@ public class NotificationPanelViewController extends PanelViewController {
mNotificationStackScrollLayoutController.setPulsing(pulsing, animatePulse);
}
- public void setAmbientIndicationBottomPadding(int ambientIndicationBottomPadding) {
+ public void setAmbientIndicationTop(int ambientIndicationTop, boolean ambientTextVisible) {
+ int ambientIndicationBottomPadding = 0;
+ if (ambientTextVisible) {
+ int stackBottom = mNotificationStackScrollLayoutController.getView().getBottom();
+ ambientIndicationBottomPadding = stackBottom - ambientIndicationTop;
+ }
if (mAmbientIndicationBottomPadding != ambientIndicationBottomPadding) {
mAmbientIndicationBottomPadding = ambientIndicationBottomPadding;
updateMaxDisplayedNotifications(true);
@@ -3765,45 +3803,6 @@ public class NotificationPanelViewController extends PanelViewController {
private long mLastTouchDownTime = -1L;
@Override
- public boolean onTouchForwardedFromStatusBar(MotionEvent event) {
- // TODO(b/202981994): Move the touch debugging in this method to a central location.
- // (Right now, it's split between StatusBar and here.)
-
- // If panels aren't enabled, ignore the gesture and don't pass it down to the
- // panel view.
- if (!mCommandQueue.panelsEnabled()) {
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- Log.v(
- TAG,
- String.format(
- "onTouchForwardedFromStatusBar: "
- + "panel disabled, ignoring touch at (%d,%d)",
- (int) event.getX(),
- (int) event.getY()
- )
- );
- }
- return false;
- }
-
- // If the view that would receive the touch is disabled, just have status bar eat
- // the gesture.
- if (event.getAction() == MotionEvent.ACTION_DOWN && !mView.isEnabled()) {
- Log.v(TAG,
- String.format(
- "onTouchForwardedFromStatusBar: "
- + "panel view disabled, eating touch at (%d,%d)",
- (int) event.getX(),
- (int) event.getY()
- )
- );
- return true;
- }
-
- return mView.dispatchTouchEvent(event);
- }
-
- @Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (mBlockTouches || mQs.disallowPanelTouches()) {
return false;
@@ -3914,6 +3913,55 @@ public class NotificationPanelViewController extends PanelViewController {
};
}
+ private final PhoneStatusBarView.TouchEventHandler mStatusBarViewTouchEventHandler =
+ new PhoneStatusBarView.TouchEventHandler() {
+ @Override
+ public void onInterceptTouchEvent(MotionEvent event) {
+ mStatusBar.onTouchEvent(event);
+ }
+
+ @Override
+ public boolean handleTouchEvent(MotionEvent event) {
+ mStatusBar.onTouchEvent(event);
+
+ // TODO(b/202981994): Move the touch debugging in this method to a central
+ // location. (Right now, it's split between StatusBar and here.)
+
+ // If panels aren't enabled, ignore the gesture and don't pass it down to the
+ // panel view.
+ if (!mCommandQueue.panelsEnabled()) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ Log.v(
+ TAG,
+ String.format(
+ "onTouchForwardedFromStatusBar: "
+ + "panel disabled, ignoring touch at (%d,%d)",
+ (int) event.getX(),
+ (int) event.getY()
+ )
+ );
+ }
+ return false;
+ }
+
+ // If the view that would receive the touch is disabled, just have status bar
+ // eat the gesture.
+ if (event.getAction() == MotionEvent.ACTION_DOWN && !mView.isEnabled()) {
+ Log.v(TAG,
+ String.format(
+ "onTouchForwardedFromStatusBar: "
+ + "panel view disabled, eating touch at (%d,%d)",
+ (int) event.getX(),
+ (int) event.getY()
+ )
+ );
+ return true;
+ }
+
+ return mView.dispatchTouchEvent(event);
+ }
+ };
+
@Override
protected PanelViewController.OnConfigurationChangedListener
createOnConfigurationChangedListener() {
@@ -4650,39 +4698,29 @@ public class NotificationPanelViewController extends PanelViewController {
mView.removeCallbacks(mMaybeHideExpandedRunnable);
}
- private final PanelBar.PanelStateChangeListener mPanelStateChangeListener =
- new PanelBar.PanelStateChangeListener() {
-
- @PanelBar.PanelState
- private int mCurrentState = STATE_CLOSED;
+ @PanelState
+ private int mCurrentPanelState = STATE_CLOSED;
- @Override
- public void onStateChanged(@PanelBar.PanelState int state) {
- mAmbientState.setIsShadeOpening(state == STATE_OPENING);
- updateQSExpansionEnabledAmbient();
-
- if (state == STATE_OPEN && mCurrentState != state) {
- mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
- }
- if (state == STATE_OPENING) {
- mStatusBar.makeExpandedVisible(false);
- }
- if (state == STATE_CLOSED) {
- // Close the status bar in the next frame so we can show the end of the
- // animation.
- mView.post(mMaybeHideExpandedRunnable);
- }
- mCurrentState = state;
- }
- };
+ private void onPanelStateChanged(@PanelState int state) {
+ mAmbientState.setIsShadeOpening(state == STATE_OPENING);
+ updateQSExpansionEnabledAmbient();
- public PanelBar.PanelStateChangeListener getPanelStateChangeListener() {
- return mPanelStateChangeListener;
+ if (state == STATE_OPEN && mCurrentPanelState != state) {
+ mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+ }
+ if (state == STATE_OPENING) {
+ mStatusBar.makeExpandedVisible(false);
+ }
+ if (state == STATE_CLOSED) {
+ // Close the status bar in the next frame so we can show the end of the
+ // animation.
+ mView.post(mMaybeHideExpandedRunnable);
+ }
+ mCurrentPanelState = state;
}
-
/** Returns the handler that the status bar should forward touches to. */
public PhoneStatusBarView.TouchEventHandler getStatusBarTouchEventHandler() {
- return getTouchHandler()::onTouchForwardedFromStatusBar;
+ return mStatusBarViewTouchEventHandler;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index 36bd31b2efe3..01587f7fe98c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -54,7 +54,9 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.systemui.tuner.TunerService;
import java.io.FileDescriptor;
@@ -105,7 +107,8 @@ public class NotificationShadeWindowViewController {
private boolean mExpandingBelowNotch;
private final DockManager mDockManager;
private final NotificationPanelViewController mNotificationPanelViewController;
- private final StatusBarWindowView mStatusBarWindowView;
+ private final PanelExpansionStateManager mPanelExpansionStateManager;
+ private final StatusBarWindowController mStatusBarWindowController;
// Used for determining view / touch intersection
private int[] mTempLocation = new int[2];
@@ -134,7 +137,8 @@ public class NotificationShadeWindowViewController {
NotificationShadeDepthController depthController,
NotificationShadeWindowView notificationShadeWindowView,
NotificationPanelViewController notificationPanelViewController,
- StatusBarWindowView statusBarWindowView,
+ PanelExpansionStateManager panelExpansionStateManager,
+ StatusBarWindowController statusBarWindowController,
NotificationStackScrollLayoutController notificationStackScrollLayoutController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
LockIconViewController lockIconViewController) {
@@ -157,8 +161,9 @@ public class NotificationShadeWindowViewController {
mShadeController = shadeController;
mDockManager = dockManager;
mNotificationPanelViewController = notificationPanelViewController;
+ mPanelExpansionStateManager = panelExpansionStateManager;
mDepthController = depthController;
- mStatusBarWindowView = statusBarWindowView;
+ mStatusBarWindowController = statusBarWindowController;
mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mLockIconViewController = lockIconViewController;
@@ -442,7 +447,7 @@ public class NotificationShadeWindowViewController {
setDragDownHelper(mLockscreenShadeTransitionController.getTouchHelper());
mDepthController.setRoot(mView);
- mNotificationPanelViewController.addExpansionListener(mDepthController);
+ mPanelExpansionStateManager.addExpansionListener(mDepthController);
}
public NotificationShadeWindowView getView() {
@@ -496,7 +501,7 @@ public class NotificationShadeWindowViewController {
if (statusBarView != null) {
mBarTransitions = new PhoneStatusBarTransitions(
statusBarView,
- mStatusBarWindowView.findViewById(R.id.status_bar_container));
+ mStatusBarWindowController.getBackgroundView());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
deleted file mode 100644
index e90258db8571..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2012 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 java.lang.Float.isNaN;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.IntDef;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.widget.FrameLayout;
-
-import androidx.annotation.Nullable;
-
-import java.lang.annotation.Retention;
-
-public abstract class PanelBar extends FrameLayout {
- public static final boolean DEBUG = false;
- public static final String TAG = PanelBar.class.getSimpleName();
- private static final boolean SPEW = false;
- private static final String PANEL_BAR_SUPER_PARCELABLE = "panel_bar_super_parcelable";
- private static final String STATE = "state";
- protected float mPanelFraction;
-
- public static final void LOG(String fmt, Object... args) {
- if (!DEBUG) return;
- Log.v(TAG, String.format(fmt, args));
- }
-
- /** Enum for the current state of the panel. */
- @Retention(SOURCE)
- @IntDef({STATE_CLOSED, STATE_OPENING, STATE_OPEN})
- @interface PanelState {}
- public static final int STATE_CLOSED = 0;
- public static final int STATE_OPENING = 1;
- public static final int STATE_OPEN = 2;
-
- @Nullable private PanelStateChangeListener mPanelStateChangeListener;
- private int mState = STATE_CLOSED;
- private boolean mTracking;
-
- /** Updates the panel state if necessary. */
- public void updateState(@PanelState int state) {
- if (DEBUG) LOG("update state: %d -> %d", mState, state);
- if (mState != state) {
- go(state);
- }
- }
-
- private void go(@PanelState int state) {
- if (DEBUG) LOG("go state: %d -> %d", mState, state);
- mState = state;
- if (mPanelStateChangeListener != null) {
- mPanelStateChangeListener.onStateChanged(state);
- }
- }
-
- @Override
- protected Parcelable onSaveInstanceState() {
- Bundle bundle = new Bundle();
- bundle.putParcelable(PANEL_BAR_SUPER_PARCELABLE, super.onSaveInstanceState());
- bundle.putInt(STATE, mState);
- return bundle;
- }
-
- @Override
- protected void onRestoreInstanceState(Parcelable state) {
- if (state == null || !(state instanceof Bundle)) {
- super.onRestoreInstanceState(state);
- return;
- }
-
- Bundle bundle = (Bundle) state;
- super.onRestoreInstanceState(bundle.getParcelable(PANEL_BAR_SUPER_PARCELABLE));
- if (((Bundle) state).containsKey(STATE)) {
- go(bundle.getInt(STATE, STATE_CLOSED));
- }
- }
-
- public PanelBar(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- }
-
- /** Sets the listener that will be notified of panel state changes. */
- public void setPanelStateChangeListener(PanelStateChangeListener listener) {
- mPanelStateChangeListener = listener;
- }
-
- /**
- * @param frac the fraction from the expansion in [0, 1]
- * @param expanded whether the panel is currently expanded; this is independent from the
- * fraction as the panel also might be expanded if the fraction is 0
- */
- public void panelExpansionChanged(float frac, boolean expanded) {
- if (isNaN(frac)) {
- throw new IllegalArgumentException("frac cannot be NaN");
- }
- boolean fullyClosed = true;
- boolean fullyOpened = false;
- if (SPEW) LOG("panelExpansionChanged: start state=%d, f=%.1f", mState, frac);
- mPanelFraction = frac;
- // adjust any other panels that may be partially visible
- if (expanded) {
- if (mState == STATE_CLOSED) {
- go(STATE_OPENING);
- }
- fullyClosed = false;
- fullyOpened = frac >= 1f;
- }
- if (fullyOpened && !mTracking) {
- go(STATE_OPEN);
- } else if (fullyClosed && !mTracking && mState != STATE_CLOSED) {
- go(STATE_CLOSED);
- }
-
- if (SPEW) LOG("panelExpansionChanged: end state=%d [%s%s ]", mState,
- fullyOpened?" fullyOpened":"", fullyClosed?" fullyClosed":"");
- }
-
- public boolean isClosed() {
- return mState == STATE_CLOSED;
- }
-
- public void onTrackingStarted() {
- mTracking = true;
- }
-
- public void onTrackingStopped(boolean expand) {
- mTracking = false;
- }
-
- /** An interface that will be notified of panel state changes. */
- public interface PanelStateChangeListener {
- /** Called when the state changes. */
- void onStateChanged(@PanelState int state);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 481401b3eb7b..249f9886253c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -23,7 +23,7 @@ import android.view.MotionEvent;
import android.widget.FrameLayout;
public abstract class PanelView extends FrameLayout {
- public static final boolean DEBUG = PanelBar.DEBUG;
+ public static final boolean DEBUG = false;
public static final String TAG = PanelView.class.getSimpleName();
private PanelViewController.TouchHandler mTouchHandler;
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 e5296af86b81..2823d985102f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -59,15 +59,15 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.wm.shell.animation.FlingAnimationUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
public abstract class PanelViewController {
- public static final boolean DEBUG = PanelBar.DEBUG;
+ public static final boolean DEBUG = PanelView.DEBUG;
public static final String TAG = PanelView.class.getSimpleName();
private static final int NO_FIXED_DURATION = -1;
private static final long SHADE_OPEN_SPRING_OUT_DURATION = 350L;
@@ -86,7 +86,6 @@ public abstract class PanelViewController {
private boolean mVibrateOnOpening;
protected boolean mIsLaunchAnimationRunning;
private int mFixedDuration = NO_FIXED_DURATION;
- protected ArrayList<PanelExpansionListener> mExpansionListeners = new ArrayList<>();
protected float mOverExpansion;
/**
@@ -154,8 +153,6 @@ public abstract class PanelViewController {
private boolean mAnimateAfterExpanding;
private boolean mIsFlinging;
- PanelBar mBar;
-
private String mViewName;
private float mInitialTouchY;
private float mInitialTouchX;
@@ -185,6 +182,7 @@ public abstract class PanelViewController {
protected final SysuiStatusBarStateController mStatusBarStateController;
protected final AmbientState mAmbientState;
protected final LockscreenGestureLogger mLockscreenGestureLogger;
+ private final PanelExpansionStateManager mPanelExpansionStateManager;
private final TouchHandler mTouchHandler;
protected abstract void onExpandingFinished();
@@ -211,20 +209,25 @@ public abstract class PanelViewController {
return mAmbientState;
}
- public PanelViewController(PanelView view,
- FalsingManager falsingManager, DozeLog dozeLog,
+ public PanelViewController(
+ PanelView view,
+ FalsingManager falsingManager,
+ DozeLog dozeLog,
KeyguardStateController keyguardStateController,
- SysuiStatusBarStateController statusBarStateController, VibratorHelper vibratorHelper,
+ SysuiStatusBarStateController statusBarStateController,
+ VibratorHelper vibratorHelper,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
LatencyTracker latencyTracker,
FlingAnimationUtils.Builder flingAnimationUtilsBuilder,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
LockscreenGestureLogger lockscreenGestureLogger,
+ PanelExpansionStateManager panelExpansionStateManager,
AmbientState ambientState) {
mAmbientState = ambientState;
mView = view;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mLockscreenGestureLogger = lockscreenGestureLogger;
+ mPanelExpansionStateManager = panelExpansionStateManager;
mTouchHandler = createTouchHandler();
mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
@@ -289,10 +292,6 @@ public abstract class PanelViewController {
: mTouchSlop;
}
- protected TouchHandler getTouchHandler() {
- return mTouchHandler;
- }
-
private void addMovement(MotionEvent event) {
// Add movement to velocity tracker using raw screen X and Y coordinates instead
// of window coordinates because the window frame may be moving at the same time.
@@ -457,7 +456,6 @@ public abstract class PanelViewController {
protected void onTrackingStopped(boolean expand) {
mTracking = false;
- mBar.onTrackingStopped(expand);
mStatusBar.onTrackingStopped(expand);
updatePanelExpansionAndVisibility();
}
@@ -465,7 +463,6 @@ public abstract class PanelViewController {
protected void onTrackingStarted() {
endClosing();
mTracking = true;
- mBar.onTrackingStarted();
mStatusBar.onTrackingStarted();
notifyExpandingStarted();
updatePanelExpansionAndVisibility();
@@ -843,10 +840,6 @@ public abstract class PanelViewController {
return mTracking;
}
- public void setBar(PanelBar panelBar) {
- mBar = panelBar;
- }
-
public void collapse(boolean delayed, float speedUpFactor) {
if (DEBUG) logf("collapse: " + this);
if (canPanelBeCollapsed()) {
@@ -1084,13 +1077,9 @@ public abstract class PanelViewController {
* {@link #updateVisibility()}? That would allow us to make this method private.
*/
public void updatePanelExpansionAndVisibility() {
- if (mBar != null) {
- mBar.panelExpansionChanged(mExpandedFraction, isExpanded());
- }
+ mPanelExpansionStateManager.onPanelExpansionChanged(
+ mExpandedFraction, isExpanded(), mTracking);
updateVisibility();
- for (int i = 0; i < mExpansionListeners.size(); i++) {
- mExpansionListeners.get(i).onPanelExpansionChanged(mExpandedFraction, mTracking);
- }
}
public boolean isExpanded() {
@@ -1102,10 +1091,6 @@ public abstract class PanelViewController {
&& !mIsSpringBackAnimation;
}
- public void addExpansionListener(PanelExpansionListener panelExpansionListener) {
- mExpansionListeners.add(panelExpansionListener);
- }
-
protected abstract boolean isPanelVisibleBecauseOfHeadsUp();
/**
@@ -1172,17 +1157,7 @@ public abstract class PanelViewController {
return new OnConfigurationChangedListener();
}
- public abstract class TouchHandler implements View.OnTouchListener {
- /**
- * Method called when a touch has occurred on {@link PhoneStatusBarView}.
- *
- * Touches that occur on the status bar view may have ramifications for the notification
- * panel (e.g. a touch that pulls down the shade could start on the status bar), so we need
- * to notify the panel controller when these touches occur.
- *
- * Returns true if the event was handled and false otherwise.
- */
- public abstract boolean onTouchForwardedFromStatusBar(MotionEvent event);
+ public class TouchHandler implements View.OnTouchListener {
public boolean onInterceptTouchEvent(MotionEvent event) {
if (mInstantExpanding || !mNotificationsDragEnabled || mTouchDisabled || (mMotionAborted
@@ -1453,4 +1428,8 @@ public abstract class PanelViewController {
protected float getExpansionFraction() {
return mExpandedFraction;
}
+
+ protected PanelExpansionStateManager getPanelExpansionStateManager() {
+ return mPanelExpansionStateManager;
+ }
}
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 883313bdc096..1a0b55a747c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -16,23 +16,21 @@
package com.android.systemui.statusbar.phone;
-import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
-import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Pair;
import android.view.DisplayCutout;
-import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.view.accessibility.AccessibilityEvent;
+import android.widget.FrameLayout;
import android.widget.LinearLayout;
import com.android.internal.policy.SystemBarUtils;
@@ -42,18 +40,12 @@ import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.util.leak.RotationUtils;
-import java.util.List;
import java.util.Objects;
-public class PhoneStatusBarView extends PanelBar {
+public class PhoneStatusBarView extends FrameLayout {
private static final String TAG = "PhoneStatusBarView";
- private static final boolean DEBUG = StatusBar.DEBUG;
- private static final boolean DEBUG_GESTURES = false;
private final StatusBarContentInsetsProvider mContentInsetsProvider;
- StatusBar mBar;
-
- private ScrimController mScrimController;
private DarkReceiver mBattery;
private DarkReceiver mClock;
private int mRotationOrientation = -1;
@@ -65,8 +57,6 @@ public class PhoneStatusBarView extends PanelBar {
private DisplayCutout mDisplayCutout;
private int mStatusBarHeight;
@Nullable
- private List<StatusBar.ExpansionChangedListener> mExpansionChangedListeners;
- @Nullable
private TouchEventHandler mTouchEventHandler;
/**
@@ -79,23 +69,10 @@ public class PhoneStatusBarView extends PanelBar {
mContentInsetsProvider = Dependency.get(StatusBarContentInsetsProvider.class);
}
- public void setBar(StatusBar bar) {
- mBar = bar;
- }
-
- public void setExpansionChangedListeners(
- @Nullable List<StatusBar.ExpansionChangedListener> listeners) {
- mExpansionChangedListeners = listeners;
- }
-
void setTouchEventHandler(TouchEventHandler handler) {
mTouchEventHandler = handler;
}
- public void setScrimController(ScrimController scrimController) {
- mScrimController = scrimController;
- }
-
@Override
public void onFinishInflate() {
mBattery = findViewById(R.id.battery);
@@ -182,7 +159,6 @@ public class PhoneStatusBarView extends PanelBar {
@Override
public boolean onTouchEvent(MotionEvent event) {
- mBar.onTouchEvent(event);
if (mTouchEventHandler == null) {
Log.w(
TAG,
@@ -199,20 +175,10 @@ public class PhoneStatusBarView extends PanelBar {
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- mBar.onTouchEvent(event);
+ mTouchEventHandler.onInterceptTouchEvent(event);
return super.onInterceptTouchEvent(event);
}
- @Override
- public void panelExpansionChanged(float frac, boolean expanded) {
- super.panelExpansionChanged(frac, expanded);
- if (mExpansionChangedListeners != null) {
- for (StatusBar.ExpansionChangedListener listener : mExpansionChangedListeners) {
- listener.onExpansionChanged(frac, expanded);
- }
- }
- }
-
public void updateResources() {
mCutoutSideNudge = getResources().getDimensionPixelSize(
R.dimen.display_cutout_margin_consumption);
@@ -249,17 +215,18 @@ public class PhoneStatusBarView extends PanelBar {
private void updateLayoutForCutout() {
updateStatusBarHeight();
- updateCutoutLocation(StatusBarWindowView.cornerCutoutMargins(mDisplayCutout, getDisplay()));
+ updateCutoutLocation();
updateSafeInsets();
}
- private void updateCutoutLocation(Pair<Integer, Integer> cornerCutoutMargins) {
+ private void updateCutoutLocation() {
// Not all layouts have a cutout (e.g., Car)
if (mCutoutSpace == null) {
return;
}
- if (mDisplayCutout == null || mDisplayCutout.isEmpty() || cornerCutoutMargins != null) {
+ boolean hasCornerCutout = mContentInsetsProvider.currentRotationHasCornerCutout();
+ if (mDisplayCutout == null || mDisplayCutout.isEmpty() || hasCornerCutout) {
mCenterIconSpace.setVisibility(View.VISIBLE);
mCutoutSpace.setVisibility(View.GONE);
return;
@@ -269,8 +236,7 @@ public class PhoneStatusBarView extends PanelBar {
mCutoutSpace.setVisibility(View.VISIBLE);
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mCutoutSpace.getLayoutParams();
- Rect bounds = new Rect();
- boundsFromDirection(mDisplayCutout, Gravity.TOP, bounds);
+ Rect bounds = mDisplayCutout.getBoundingRectTop();
bounds.left = bounds.left + mCutoutSideNudge;
bounds.right = bounds.right - mCutoutSideNudge;
@@ -279,27 +245,37 @@ public class PhoneStatusBarView extends PanelBar {
}
private void updateSafeInsets() {
- Rect contentRect = mContentInsetsProvider
- .getStatusBarContentInsetsForRotation(RotationUtils.getExactRotation(getContext()));
-
- Point size = new Point();
- getDisplay().getRealSize(size);
+ Pair<Integer, Integer> insets = mContentInsetsProvider
+ .getStatusBarContentInsetsForCurrentRotation();
setPadding(
- contentRect.left,
+ insets.first,
getPaddingTop(),
- size.x - contentRect.right,
+ insets.second,
getPaddingBottom());
}
/**
- * A handler repsonsible for all touch event handling on the status bar.
+ * A handler responsible for all touch event handling on the status bar.
+ *
+ * Touches that occur on the status bar view may have ramifications for the notification
+ * panel (e.g. a touch that pulls down the shade could start on the status bar), so this
+ * interface provides a way to notify the panel controller when these touches occur.
*
- * The handler will be notified each time {@link this#onTouchEvent} is called, and the return
- * value from the handler will be returned from {@link this#onTouchEvent}.
+ * The handler will be notified each time {@link PhoneStatusBarView#onTouchEvent} and
+ * {@link PhoneStatusBarView#onInterceptTouchEvent} are called.
**/
public interface TouchEventHandler {
- /** Called each time {@link this#onTouchEvent} is called. */
+ /** Called each time {@link PhoneStatusBarView#onInterceptTouchEvent} is called. */
+ void onInterceptTouchEvent(MotionEvent event);
+
+ /**
+ * Called each time {@link PhoneStatusBarView#onTouchEvent} is called.
+ *
+ * Should return true if the touch was handled by this handler and false otherwise. The
+ * return value from the handler will be returned from
+ * {@link PhoneStatusBarView#onTouchEvent}.
+ */
boolean handleTouchEvent(MotionEvent event);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index de21e73f8100..256b069a0080 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -21,21 +21,21 @@ import android.view.ViewGroup
import android.view.ViewTreeObserver
import com.android.systemui.R
import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator
-import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.unfold.SysUIUnfoldComponent
import com.android.systemui.unfold.UNFOLD_STATUS_BAR
-import com.android.systemui.unfold.config.UnfoldTransitionConfig
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
import com.android.systemui.util.ViewController
+import com.android.systemui.util.kotlin.getOrNull
+import java.util.Optional
import javax.inject.Inject
import javax.inject.Named
-import dagger.Lazy
/** Controller for [PhoneStatusBarView]. */
class PhoneStatusBarViewController private constructor(
view: PhoneStatusBarView,
@Named(UNFOLD_STATUS_BAR) private val progressProvider: ScopedUnfoldTransitionProgressProvider?,
private val moveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?,
- touchEventHandler: PhoneStatusBarView.TouchEventHandler,
+ touchEventHandler: PhoneStatusBarView.TouchEventHandler
) : ViewController<PhoneStatusBarView>(view) {
override fun onViewAttached() {
@@ -115,21 +115,21 @@ class PhoneStatusBarViewController private constructor(
}
class Factory @Inject constructor(
+ private val unfoldComponent: Optional<SysUIUnfoldComponent>,
@Named(UNFOLD_STATUS_BAR)
- private val progressProvider: Lazy<ScopedUnfoldTransitionProgressProvider>,
- private val moveFromCenterController: Lazy<StatusBarMoveFromCenterAnimationController>,
- private val unfoldConfig: UnfoldTransitionConfig,
+ private val progressProvider: Optional<ScopedUnfoldTransitionProgressProvider>
) {
fun create(
view: PhoneStatusBarView,
touchEventHandler: PhoneStatusBarView.TouchEventHandler
- ): PhoneStatusBarViewController {
- return PhoneStatusBarViewController(
+ ) =
+ PhoneStatusBarViewController(
view,
- if (unfoldConfig.isEnabled) progressProvider.get() else null,
- if (unfoldConfig.isEnabled) moveFromCenterController.get() else null,
+ progressProvider.getOrNull(),
+ unfoldComponent.map {
+ it.getStatusBarMoveFromCenterAnimationController()
+ }.getOrNull(),
touchEventHandler
)
- }
}
}
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 1921357ddf7c..1077347eab0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -53,6 +53,7 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.statusbar.notification.stack.ViewState;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.AlarmTimeout;
@@ -233,7 +234,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
KeyguardUpdateMonitor keyguardUpdateMonitor, DockManager dockManager,
ConfigurationController configurationController, @Main Executor mainExecutor,
- UnlockedScreenOffAnimationController unlockedScreenOffAnimationController) {
+ UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
+ PanelExpansionStateManager panelExpansionStateManager) {
mScrimStateListener = lightBarController::setScrimState;
mDefaultScrimAlpha = BUSY_SCRIM_ALPHA;
@@ -269,6 +271,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
ScrimController.this.onThemeChanged();
}
});
+ panelExpansionStateManager.addExpansionListener(
+ (fraction, expanded, tracking) -> setRawPanelExpansionFraction(fraction)
+ );
mColors = new GradientColors();
}
@@ -481,11 +486,12 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
*
* The expansion fraction is tied to the scrim opacity.
*
- * See {@link PanelBar#panelExpansionChanged}.
+ * See {@link PanelExpansionListener#onPanelExpansionChanged}.
*
* @param rawPanelExpansionFraction From 0 to 1 where 0 means collapsed and 1 expanded.
*/
- public void setRawPanelExpansionFraction(
+ @VisibleForTesting
+ void setRawPanelExpansionFraction(
@FloatRange(from = 0.0, to = 1.0) float rawPanelExpansionFraction) {
if (isNaN(rawPanelExpansionFraction)) {
throw new IllegalArgumentException("rawPanelExpansionFraction should not be NaN");
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 a7ecd0619d26..c814622ff074 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone
import android.view.View
+import androidx.constraintlayout.motion.widget.MotionLayout
import com.android.systemui.R
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.battery.BatteryMeterView
@@ -37,21 +38,42 @@ class SplitShadeHeaderController @Inject constructor(
batteryMeterViewController: BatteryMeterViewController
) {
+ companion object {
+ private val HEADER_TRANSITION_ID = R.id.header_transition
+ private val SPLIT_HEADER_TRANSITION_ID = R.id.split_header_transition
+ }
+
+ private val combinedHeaders = featureFlags.useCombinedQSHeaders()
// TODO(b/194178072) Handle RSSI hiding when multi carrier
private val iconManager: StatusBarIconController.IconManager
private val qsCarrierGroupController: QSCarrierGroupController
private var visible = false
+ set(value) {
+ if (field == value) {
+ return
+ }
+ field = value
+ updateListeners()
+ }
var shadeExpanded = false
set(value) {
+ if (field == value) {
+ return
+ }
field = value
updateVisibility()
+ updatePosition()
}
var splitShadeMode = false
set(value) {
+ if (field == value) {
+ return
+ }
field = value
updateVisibility()
+ updateConstraints()
}
var shadeExpandedFraction = -1f
@@ -62,6 +84,28 @@ class SplitShadeHeaderController @Inject constructor(
}
}
+ var qsExpandedFraction = -1f
+ set(value) {
+ if (visible && field != value) {
+ field = value
+ updateVisibility()
+ updatePosition()
+ }
+ }
+
+ init {
+ if (statusBar is MotionLayout) {
+ val context = statusBar.context
+ val resources = statusBar.resources
+ statusBar.getConstraintSet(R.id.qqs_header_constraint)
+ .load(context, resources.getXml(R.xml.qqs_header))
+ statusBar.getConstraintSet(R.id.qs_header_constraint)
+ .load(context, resources.getXml(R.xml.qs_header))
+ statusBar.getConstraintSet(R.id.split_header_constraint)
+ .load(context, resources.getXml(R.xml.split_header))
+ }
+ }
+
init {
batteryMeterViewController.init()
val batteryIcon: BatteryMeterView = statusBar.findViewById(R.id.batteryRemainingIcon)
@@ -75,18 +119,45 @@ class SplitShadeHeaderController @Inject constructor(
qsCarrierGroupController = qsCarrierGroupControllerBuilder
.setQSCarrierGroup(statusBar.findViewById(R.id.carrier_group))
.build()
+ updateVisibility()
+ updateConstraints()
}
private fun updateVisibility() {
- val shouldBeVisible = shadeExpanded && splitShadeMode
- if (visible != shouldBeVisible) {
- visible = shouldBeVisible
- statusBar.visibility = if (shouldBeVisible) View.VISIBLE else View.GONE
- updateListeners(shouldBeVisible)
+ val visibility = if (!splitShadeMode && !combinedHeaders) {
+ View.GONE
+ } else if (shadeExpanded) {
+ View.VISIBLE
+ } else {
+ View.INVISIBLE
+ }
+ if (statusBar.visibility != visibility) {
+ statusBar.visibility = visibility
+ visible = visibility == View.VISIBLE
+ }
+ }
+
+ private fun updateConstraints() {
+ if (!combinedHeaders) {
+ return
+ }
+ statusBar as MotionLayout
+ if (splitShadeMode) {
+ statusBar.setTransition(SPLIT_HEADER_TRANSITION_ID)
+ } else {
+ statusBar.setTransition(HEADER_TRANSITION_ID)
+ statusBar.transitionToStart()
+ updatePosition()
+ }
+ }
+
+ private fun updatePosition() {
+ if (statusBar is MotionLayout && !splitShadeMode && visible) {
+ statusBar.setProgress(qsExpandedFraction)
}
}
- private fun updateListeners(visible: Boolean) {
+ private fun updateListeners() {
qsCarrierGroupController.setListening(visible)
if (visible) {
statusBarIconController.addIconGroup(iconManager)
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 bc50893d9a64..cbaa4683c364 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -129,7 +129,6 @@ import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.ActivityIntentHelper;
import com.android.systemui.AutoReinflateContainer;
import com.android.systemui.DejankUtils;
-import com.android.systemui.Dumpable;
import com.android.systemui.EventLogTags;
import com.android.systemui.InitController;
import com.android.systemui.Prefs;
@@ -137,7 +136,6 @@ import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.DelegateLaunchAnimatorController;
-import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.biometrics.AuthRippleController;
@@ -174,7 +172,7 @@ import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanelController;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.scrim.ScrimView;
-import com.android.systemui.settings.brightness.BrightnessSlider;
+import com.android.systemui.settings.brightness.BrightnessSliderController;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.AutoHideUiElement;
import com.android.systemui.statusbar.BackDropView;
@@ -207,6 +205,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
@@ -219,6 +218,7 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -229,11 +229,9 @@ import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.systemui.tuner.TunerService;
-import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
-import com.android.systemui.unfold.UnfoldTransitionWallpaperController;
-import com.android.systemui.unfold.config.UnfoldTransitionConfig;
-import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider;
+import com.android.systemui.util.DumpUtilsKt;
import com.android.systemui.util.WallpaperController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.MessageRouter;
@@ -247,7 +245,6 @@ import com.android.wm.shell.startingsurface.StartingSurface;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.StringWriter;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -337,12 +334,17 @@ public class StatusBar extends SystemUI implements
}
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
- private boolean mCallingFadingAwayAfterReveal;
private StatusBarCommandQueueCallbacks mCommandQueueCallbacks;
void setWindowState(int state) {
mStatusBarWindowState = state;
mStatusBarWindowHidden = state == WINDOW_STATE_HIDDEN;
+ mStatusBarHideIconsForBouncerManager.setStatusBarWindowHidden(mStatusBarWindowHidden);
+ if (getStatusBarView() != null) {
+ // Should #updateHideIconsForBouncer always be called, regardless of whether we have a
+ // status bar view? If so, we can make #updateHideIconsForBouncer private.
+ mStatusBarHideIconsForBouncerManager.updateHideIconsForBouncer(/* animate= */ false);
+ }
}
void acquireGestureWakeLock(long time) {
@@ -362,14 +364,6 @@ public class StatusBar extends SystemUI implements
return mStatusBarMode;
}
- boolean getWereIconsJustHidden() {
- return mWereIconsJustHidden;
- }
-
- void setWereIconsJustHidden(boolean justHidden) {
- mWereIconsJustHidden = justHidden;
- }
-
void resendMessage(int msg) {
mMessageRouter.cancelMessages(msg);
mMessageRouter.sendMessage(msg);
@@ -439,10 +433,6 @@ public class StatusBar extends SystemUI implements
mCommandQueueCallbacks.animateCollapsePanels(flags, force);
}
- public interface ExpansionChangedListener {
- void onExpansionChanged(float expansion, boolean expanded);
- }
-
/**
* The {@link StatusBarState} of the status bar.
*/
@@ -471,7 +461,7 @@ public class StatusBar extends SystemUI implements
private AuthRippleController mAuthRippleController;
private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
protected NotificationShadeWindowController mNotificationShadeWindowController;
- protected StatusBarWindowController mStatusBarWindowController;
+ private final StatusBarWindowController mStatusBarWindowController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@VisibleForTesting
DozeServiceHost mDozeServiceHost;
@@ -503,7 +493,6 @@ public class StatusBar extends SystemUI implements
private final StatusBarNotificationActivityStarter.Builder
mStatusBarNotificationActivityStarterBuilder;
private final ShadeController mShadeController;
- private final StatusBarWindowView mStatusBarWindowView;
private final LightsOutNotifController mLightsOutNotifController;
private final InitController mInitController;
@@ -517,6 +506,7 @@ public class StatusBar extends SystemUI implements
private final SystemStatusAnimationScheduler mAnimationScheduler;
private final StatusBarLocationPublisher mStatusBarLocationPublisher;
private final StatusBarIconController mStatusBarIconController;
+ private final StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
// expanded notifications
// the sliding/resizing panel within the notification window
@@ -535,18 +525,17 @@ public class StatusBar extends SystemUI implements
private final int[] mAbsPos = new int[2];
+ private final NotifShadeEventSource mNotifShadeEventSource;
protected final NotificationEntryManager mEntryManager;
private final NotificationGutsManager mGutsManager;
private final NotificationLogger mNotificationLogger;
private final NotificationViewHierarchyManager mViewHierarchyManager;
+ private final PanelExpansionStateManager mPanelExpansionStateManager;
private final KeyguardViewMediator mKeyguardViewMediator;
protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
- private final BrightnessSlider.Factory mBrightnessSliderFactory;
+ private final BrightnessSliderController.Factory mBrightnessSliderFactory;
private final FeatureFlags mFeatureFlags;
- private final UnfoldTransitionConfig mUnfoldTransitionConfig;
- private final Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealOverlayAnimation;
- private final Lazy<NaturalRotationUnfoldProgressProvider> mNaturalUnfoldProgressProvider;
- private final Lazy<UnfoldTransitionWallpaperController> mUnfoldWallpaperController;
+
private final WallpaperController mWallpaperController;
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private final MessageRouter mMessageRouter;
@@ -554,8 +543,6 @@ public class StatusBar extends SystemUI implements
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
private final TunerService mTunerService;
- private final List<ExpansionChangedListener> mExpansionChangedListeners;
-
// Flags for disabling the status bar
// Two variables becaseu the first one evidently ran out of room for new flags.
private int mDisabled1 = 0;
@@ -652,10 +639,7 @@ public class StatusBar extends SystemUI implements
private int mLastLoggedStateFingerprint;
private boolean mTopHidesStatusBar;
private boolean mStatusBarWindowHidden;
- private boolean mHideIconsForBouncer;
private boolean mIsOccluded;
- private boolean mWereIconsJustHidden;
- private boolean mBouncerWasShowingWhenHidden;
private boolean mIsLaunchingActivityOverLockscreen;
private final UserSwitcherController mUserSwitcherController;
@@ -677,7 +661,6 @@ public class StatusBar extends SystemUI implements
private HeadsUpAppearanceController mHeadsUpAppearanceController;
private final ActivityLaunchAnimator mActivityLaunchAnimator;
- private final DialogLaunchAnimator mDialogLaunchAnimator;
private NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
protected StatusBarNotificationPresenter mPresenter;
private NotificationActivityStarter mNotificationActivityStarter;
@@ -707,6 +690,7 @@ public class StatusBar extends SystemUI implements
NotificationsController notificationsController,
LightBarController lightBarController,
AutoHideController autoHideController,
+ StatusBarWindowController statusBarWindowController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
PulseExpansionHandler pulseExpansionHandler,
NotificationWakeUpCoordinator notificationWakeUpCoordinator,
@@ -718,11 +702,13 @@ public class StatusBar extends SystemUI implements
FalsingManager falsingManager,
FalsingCollector falsingCollector,
BroadcastDispatcher broadcastDispatcher,
+ NotifShadeEventSource notifShadeEventSource,
NotificationEntryManager notificationEntryManager,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
NotificationInterruptStateProvider notificationInterruptStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
+ PanelExpansionStateManager panelExpansionStateManager,
KeyguardViewMediator keyguardViewMediator,
DisplayMetrics displayMetrics,
MetricsLogger metricsLogger,
@@ -764,7 +750,6 @@ public class StatusBar extends SystemUI implements
StatusBarNotificationActivityStarter.Builder
statusBarNotificationActivityStarterBuilder,
ShadeController shadeController,
- StatusBarWindowView statusBarWindowView,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
ViewMediatorCallback viewMediatorCallback,
InitController initController,
@@ -781,16 +766,13 @@ public class StatusBar extends SystemUI implements
Lazy<NotificationShadeDepthController> notificationShadeDepthControllerLazy,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
NotificationIconAreaController notificationIconAreaController,
- BrightnessSlider.Factory brightnessSliderFactory,
- UnfoldTransitionConfig unfoldTransitionConfig,
- Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation,
- Lazy<UnfoldTransitionWallpaperController> unfoldTransitionWallpaperController,
- Lazy<NaturalRotationUnfoldProgressProvider> naturalRotationUnfoldProgressProvider,
+ BrightnessSliderController.Factory brightnessSliderFactory,
WallpaperController wallpaperController,
OngoingCallController ongoingCallController,
SystemStatusAnimationScheduler animationScheduler,
StatusBarLocationPublisher locationPublisher,
StatusBarIconController statusBarIconController,
+ StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
LockscreenShadeTransitionController lockscreenShadeTransitionController,
FeatureFlags featureFlags,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
@@ -802,12 +784,12 @@ public class StatusBar extends SystemUI implements
Optional<StartingSurface> startingSurfaceOptional,
TunerService tunerService,
DumpManager dumpManager,
- ActivityLaunchAnimator activityLaunchAnimator,
- DialogLaunchAnimator dialogLaunchAnimator) {
+ ActivityLaunchAnimator activityLaunchAnimator) {
super(context);
mNotificationsController = notificationsController;
mLightBarController = lightBarController;
mAutoHideController = autoHideController;
+ mStatusBarWindowController = statusBarWindowController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mPulseExpansionHandler = pulseExpansionHandler;
mWakeUpCoordinator = notificationWakeUpCoordinator;
@@ -823,11 +805,13 @@ public class StatusBar extends SystemUI implements
mFalsingCollector = falsingCollector;
mFalsingManager = falsingManager;
mBroadcastDispatcher = broadcastDispatcher;
+ mNotifShadeEventSource = notifShadeEventSource;
mEntryManager = notificationEntryManager;
mGutsManager = notificationGutsManager;
mNotificationLogger = notificationLogger;
mNotificationInterruptStateProvider = notificationInterruptStateProvider;
mViewHierarchyManager = notificationViewHierarchyManager;
+ mPanelExpansionStateManager = panelExpansionStateManager;
mKeyguardViewMediator = keyguardViewMediator;
mDisplayMetrics = displayMetrics;
mMetricsLogger = metricsLogger;
@@ -868,7 +852,6 @@ public class StatusBar extends SystemUI implements
mSplitScreenOptional = splitScreenOptional;
mStatusBarNotificationActivityStarterBuilder = statusBarNotificationActivityStarterBuilder;
mShadeController = shadeController;
- mStatusBarWindowView = statusBarWindowView;
mLightsOutNotifController = lightsOutNotifController;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mKeyguardViewMediatorCallback = viewMediatorCallback;
@@ -881,15 +864,12 @@ public class StatusBar extends SystemUI implements
mDemoModeController = demoModeController;
mNotificationIconAreaController = notificationIconAreaController;
mBrightnessSliderFactory = brightnessSliderFactory;
- mUnfoldTransitionConfig = unfoldTransitionConfig;
- mUnfoldLightRevealOverlayAnimation = unfoldLightRevealOverlayAnimation;
- mNaturalUnfoldProgressProvider = naturalRotationUnfoldProgressProvider;
- mUnfoldWallpaperController = unfoldTransitionWallpaperController;
mWallpaperController = wallpaperController;
mOngoingCallController = ongoingCallController;
mAnimationScheduler = animationScheduler;
mStatusBarLocationPublisher = locationPublisher;
mStatusBarIconController = statusBarIconController;
+ mStatusBarHideIconsForBouncerManager = statusBarHideIconsForBouncerManager;
mFeatureFlags = featureFlags;
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
mMainHandler = mainHandler;
@@ -903,10 +883,7 @@ public class StatusBar extends SystemUI implements
mStartingSurfaceOptional = startingSurfaceOptional;
lockscreenShadeTransitionController.setStatusbar(this);
- mExpansionChangedListeners = new ArrayList<>();
- addExpansionChangedListener(
- (expansion, expanded) -> mScrimController.setRawPanelExpansionFraction(expansion));
- addExpansionChangedListener(this::onPanelExpansionChanged);
+ mPanelExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged);
mBubbleExpandListener =
(isExpanding, key) -> mContext.getMainExecutor().execute(() -> {
@@ -916,7 +893,6 @@ public class StatusBar extends SystemUI implements
mActivityIntentHelper = new ActivityIntentHelper(mContext);
mActivityLaunchAnimator = activityLaunchAnimator;
- mDialogLaunchAnimator = dialogLaunchAnimator;
// The status bar background may need updating when the ongoing call status changes.
mOngoingCallController.addCallback((animate) -> maybeUpdateBarMode());
@@ -932,8 +908,6 @@ public class StatusBar extends SystemUI implements
data -> mCommandQueueCallbacks.animateExpandSettingsPanel(data.mSubpanel));
mMessageRouter.subscribeTo(MSG_LAUNCH_TRANSITION_TIMEOUT,
id -> onLaunchTransitionTimeout());
-
- dumpManager.registerDumpable(this);
}
@Override
@@ -961,6 +935,7 @@ public class StatusBar extends SystemUI implements
mDisplay = mContext.getDisplay();
mDisplayId = mDisplay.getDisplayId();
updateDisplaySize();
+ mStatusBarHideIconsForBouncerManager.setDisplayId(mDisplayId);
// start old BaseStatusBar.start().
mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
@@ -1078,12 +1053,6 @@ public class StatusBar extends SystemUI implements
mFalsingManager.addFalsingBeliefListener(mFalsingBeliefListener);
- if (mUnfoldTransitionConfig.isEnabled()) {
- mUnfoldLightRevealOverlayAnimation.get().init();
- mUnfoldWallpaperController.get().init();
- mNaturalUnfoldProgressProvider.get().init();
- }
-
mPluginManager.addPluginListener(
new PluginListener<OverlayPlugin>() {
private final ArraySet<OverlayPlugin> mOverlays = new ArraySet<>();
@@ -1156,32 +1125,20 @@ public class StatusBar extends SystemUI implements
mNotificationLogger.setUpWithContainer(notifListContainer);
mNotificationIconAreaController.setupShelf(mNotificationShelfController);
- mNotificationPanelViewController.addExpansionListener(mWakeUpCoordinator);
- mNotificationPanelViewController.addExpansionListener(
- this::dispatchPanelExpansionForKeyguardDismiss);
+ mPanelExpansionStateManager.addExpansionListener(mWakeUpCoordinator);
mUserSwitcherController.init(mNotificationShadeWindowView);
// Allow plugins to reference DarkIconDispatcher and StatusBarStateController
mPluginDependencyProvider.allowPluginDependency(DarkIconDispatcher.class);
mPluginDependencyProvider.allowPluginDependency(StatusBarStateController.class);
- FragmentHostManager.get(mStatusBarWindowView)
+ mStatusBarWindowController.getFragmentHostManager()
.addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
CollapsedStatusBarFragment statusBarFragment =
(CollapsedStatusBarFragment) fragment;
PhoneStatusBarView oldStatusBarView = mStatusBarView;
mStatusBarView = (PhoneStatusBarView) statusBarFragment.getView();
- mStatusBarView.setBar(this);
- mStatusBarView.setPanelStateChangeListener(
- mNotificationPanelViewController.getPanelStateChangeListener());
- mStatusBarView.setScrimController(mScrimController);
- mStatusBarView.setExpansionChangedListeners(mExpansionChangedListeners);
- for (ExpansionChangedListener listener : mExpansionChangedListeners) {
- sendInitialExpansionAmount(listener);
- }
-
- mNotificationPanelViewController.setBar(mStatusBarView);
mPhoneStatusBarViewController = mPhoneStatusBarViewControllerFactory
.create(mStatusBarView, mNotificationPanelViewController
@@ -1234,9 +1191,11 @@ public class StatusBar extends SystemUI implements
mAnimationScheduler,
mStatusBarLocationPublisher,
mNotificationIconAreaController,
+ mPanelExpansionStateManager,
mFeatureFlags,
() -> Optional.of(this),
mStatusBarIconController,
+ mStatusBarHideIconsForBouncerManager,
mKeyguardStateController,
mNetworkController,
mStatusBarStateController,
@@ -1408,12 +1367,6 @@ public class StatusBar extends SystemUI implements
mDeviceProvisionedController.addCallback(mUserSetupObserver);
mUserSetupObserver.onUserSetupChanged();
- for (ExpansionChangedListener listener : mExpansionChangedListeners) {
- // The initial expansion amount comes from mNotificationPanelViewController, so we
- // should send the amount once we've fully set up that controller.
- sendInitialExpansionAmount(listener);
- }
-
// disable profiling bars, since they overlap and clutter the output on app windows
ThreadedRenderer.overrideProperty("disableProfileBars", "true");
@@ -1423,15 +1376,15 @@ public class StatusBar extends SystemUI implements
/**
- * When swiping up to dismiss the lock screen, the panel expansion goes from 1f to 0f. This
- * results in the clock/notifications/other content disappearing off the top of the screen.
+ * When swiping up to dismiss the lock screen, the panel expansion fraction goes from 1f to 0f.
+ * This results in the clock/notifications/other content disappearing off the top of the screen.
*
- * We also use the expansion amount to animate in the app/launcher surface from the bottom of
+ * We also use the expansion fraction to animate in the app/launcher surface from the bottom of
* the screen, 'pushing' off the notifications and other content. To do this, we dispatch the
- * expansion amount to the KeyguardViewMediator if we're in the process of dismissing the
+ * expansion fraction to the KeyguardViewMediator if we're in the process of dismissing the
* keyguard.
*/
- private void dispatchPanelExpansionForKeyguardDismiss(float expansion, boolean trackingTouch) {
+ private void dispatchPanelExpansionForKeyguardDismiss(float fraction, boolean trackingTouch) {
// Things that mean we're not dismissing the keyguard, and should ignore this expansion:
// - Keyguard isn't even visible.
// - Keyguard is visible, but can't be dismissed (swiping up will show PIN/password prompt).
@@ -1450,12 +1403,14 @@ public class StatusBar extends SystemUI implements
|| mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()
|| mKeyguardUnlockAnimationController.isUnlockingWithSmartSpaceTransition()) {
mKeyguardStateController.notifyKeyguardDismissAmountChanged(
- 1f - expansion, trackingTouch);
+ 1f - fraction, trackingTouch);
}
}
- private void onPanelExpansionChanged(float frac, boolean expanded) {
- if (frac == 0 || frac == 1) {
+ private void onPanelExpansionChanged(float fraction, boolean expanded, boolean tracking) {
+ dispatchPanelExpansionForKeyguardDismiss(fraction, tracking);
+
+ if (fraction == 0 || fraction == 1) {
if (getNavigationBarView() != null) {
getNavigationBarView().onStatusBarPanelStateChanged();
}
@@ -1506,6 +1461,7 @@ public class StatusBar extends SystemUI implements
mDynamicPrivacyController,
mKeyguardStateController,
mKeyguardIndicationController,
+ mFeatureFlags,
this /* statusBar */,
mShadeController,
mLockscreenShadeTransitionController,
@@ -1513,6 +1469,7 @@ public class StatusBar extends SystemUI implements
mViewHierarchyManager,
mLockscreenUserManager,
mStatusBarStateController,
+ mNotifShadeEventSource,
mEntryManager,
mMediaManager,
mGutsManager,
@@ -1607,7 +1564,6 @@ public class StatusBar extends SystemUI implements
.getNotificationShadeWindowViewController();
mNotificationShadeWindowController.setNotificationShadeView(mNotificationShadeWindowView);
mNotificationShadeWindowViewController.setupExpandedStatusBar();
- mStatusBarWindowController = statusBarComponent.getStatusBarWindowController();
mNotificationPanelViewController = statusBarComponent.getNotificationPanelViewController();
statusBarComponent.getLockIconViewController().init();
mStackScrollerController = statusBarComponent.getNotificationStackScrollLayoutController();
@@ -1665,8 +1621,11 @@ public class StatusBar extends SystemUI implements
});
mStatusBarKeyguardViewManager.registerStatusBar(
/* statusBar= */ this,
- mNotificationPanelViewController, mBiometricUnlockController,
- mStackScroller, mKeyguardBypassController);
+ mNotificationPanelViewController,
+ mPanelExpansionStateManager,
+ mBiometricUnlockController,
+ mStackScroller,
+ mKeyguardBypassController);
mKeyguardIndicationController
.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
@@ -1687,10 +1646,6 @@ public class StatusBar extends SystemUI implements
return mNotificationShadeWindowView;
}
- public StatusBarWindowView getStatusBarWindow() {
- return mStatusBarWindowView;
- }
-
public NotificationShadeWindowViewController getNotificationShadeWindowViewController() {
return mNotificationShadeWindowViewController;
}
@@ -1915,7 +1870,7 @@ public class StatusBar extends SystemUI implements
mNotificationLogger.onPanelExpandedChanged(isExpanded);
}
mPanelExpanded = isExpanded;
- updateHideIconsForBouncer(false /* animate */);
+ mStatusBarHideIconsForBouncerManager.setPanelExpandedAndTriggerUpdate(isExpanded);
mNotificationShadeWindowController.setPanelExpanded(isExpanded);
mStatusBarStateController.setPanelExpanded(isExpanded);
if (isExpanded && mStatusBarStateController.getState() != StatusBarState.KEYGUARD) {
@@ -1959,46 +1914,8 @@ public class StatusBar extends SystemUI implements
public void setOccluded(boolean occluded) {
mIsOccluded = occluded;
+ mStatusBarHideIconsForBouncerManager.setIsOccludedAndTriggerUpdate(occluded);
mScrimController.setKeyguardOccluded(occluded);
- updateHideIconsForBouncer(false /* animate */);
- }
-
- public boolean hideStatusBarIconsForBouncer() {
- return mHideIconsForBouncer || mWereIconsJustHidden;
- }
-
- /**
- * Decides if the status bar (clock + notifications + signal cluster) should be visible
- * or not when showing the bouncer.
- *
- * We want to hide it when:
- * • User swipes up on the keyguard
- * • Locked activity that doesn't show a status bar requests the bouncer
- *
- * @param animate should the change of the icons be animated.
- */
- void updateHideIconsForBouncer(boolean animate) {
- boolean hideBecauseApp = mTopHidesStatusBar && mIsOccluded
- && (mStatusBarWindowHidden || mBouncerShowing);
- boolean hideBecauseKeyguard = !mPanelExpanded && !mIsOccluded && mBouncerShowing;
- boolean shouldHideIconsForBouncer = hideBecauseApp || hideBecauseKeyguard;
- if (mHideIconsForBouncer != shouldHideIconsForBouncer) {
- mHideIconsForBouncer = shouldHideIconsForBouncer;
- if (!shouldHideIconsForBouncer && mBouncerWasShowingWhenHidden) {
- // We're delaying the showing, since most of the time the fullscreen app will
- // hide the icons again and we don't want them to fade in and out immediately again.
- mWereIconsJustHidden = true;
- mMainExecutor.executeDelayed(() -> {
- mWereIconsJustHidden = false;
- mCommandQueue.recomputeDisableFlags(mDisplayId, true);
- }, 500);
- } else {
- mCommandQueue.recomputeDisableFlags(mDisplayId, animate);
- }
- }
- if (shouldHideIconsForBouncer) {
- mBouncerWasShowingWhenHidden = mBouncerShowing;
- }
}
public boolean headsUpShouldBeVisible() {
@@ -2417,7 +2334,7 @@ public class StatusBar extends SystemUI implements
pw.print(" mDozing="); pw.println(mDozing);
pw.print(" mWallpaperSupported= "); pw.println(mWallpaperSupported);
- pw.println(" StatusBarWindowView: ");
+ pw.println(" ShadeWindowView: ");
if (mNotificationShadeWindowViewController != null) {
mNotificationShadeWindowViewController.dump(fd, pw, args);
dumpBarTransitions(pw, "PhoneStatusBarTransitions",
@@ -2439,8 +2356,14 @@ public class StatusBar extends SystemUI implements
}
pw.println(" mStackScroller: ");
if (mStackScroller != null) {
- pw.print (" ");
- ((Dumpable) mStackScroller).dump(fd, pw, args);
+ DumpUtilsKt.withIndenting(pw, ipw -> {
+ // Triple indent until we rewrite the rest of this dump()
+ ipw.increaseIndent();
+ ipw.increaseIndent();
+ mStackScroller.dump(fd, ipw, args);
+ ipw.decreaseIndent();
+ ipw.decreaseIndent();
+ });
}
pw.println(" Theme:");
String nightMode = mUiModeManager == null ? "null" : mUiModeManager.getNightMode() + "";
@@ -2462,6 +2385,8 @@ public class StatusBar extends SystemUI implements
if (mLightRevealScrim != null) {
pw.println(
+ "mLightRevealScrim.getRevealEffect(): " + mLightRevealScrim.getRevealEffect());
+ pw.println(
"mLightRevealScrim.getRevealAmount(): " + mLightRevealScrim.getRevealAmount());
}
@@ -2648,26 +2573,12 @@ public class StatusBar extends SystemUI implements
private ActivityLaunchAnimator.Controller wrapAnimationController(
ActivityLaunchAnimator.Controller animationController, boolean dismissShade) {
View rootView = animationController.getLaunchContainer().getRootView();
- if (rootView == mStatusBarWindowView) {
- // We are animating a view in the status bar. We have to make sure that the status bar
- // window matches the full screen during the animation and that we are expanding the
- // view below the other status bar text.
- animationController.setLaunchContainer(
- mStatusBarWindowController.getLaunchAnimationContainer());
-
- return new DelegateLaunchAnimatorController(animationController) {
- @Override
- public void onLaunchAnimationStart(boolean isExpandingFullyAbove) {
- getDelegate().onLaunchAnimationStart(isExpandingFullyAbove);
- mStatusBarWindowController.setLaunchAnimationRunning(true);
- }
- @Override
- public void onLaunchAnimationEnd(boolean isExpandingFullyAbove) {
- getDelegate().onLaunchAnimationEnd(isExpandingFullyAbove);
- mStatusBarWindowController.setLaunchAnimationRunning(false);
- }
- };
+ Optional<ActivityLaunchAnimator.Controller> controllerFromStatusBar =
+ mStatusBarWindowController.wrapAnimationControllerIfInStatusBar(
+ rootView, animationController);
+ if (controllerFromStatusBar.isPresent()) {
+ return controllerFromStatusBar.get();
}
if (dismissShade && rootView == mNotificationShadeWindowView) {
@@ -3146,20 +3057,8 @@ public class StatusBar extends SystemUI implements
public void fadeKeyguardWhilePulsing() {
mNotificationPanelViewController.fadeOut(0, FADE_KEYGUARD_DURATION_PULSING,
()-> {
- Runnable finishFading = () -> {
- mCallingFadingAwayAfterReveal = false;
- hideKeyguard();
- mStatusBarKeyguardViewManager.onKeyguardFadedAway();
- };
- if (mLightRevealScrim.getRevealAmount() != 1.0f) {
- mCallingFadingAwayAfterReveal = true;
- // We're still revealing the Light reveal, let's only go to keyguard once
- // that has finished and nothing moves anymore.
- // Going there introduces lots of jank
- mLightRevealScrim.setFullyRevealedRunnable(finishFading);
- } else {
- finishFading.run();
- }
+ hideKeyguard();
+ mStatusBarKeyguardViewManager.onKeyguardFadedAway();
}).start();
}
@@ -3473,17 +3372,24 @@ public class StatusBar extends SystemUI implements
return;
}
- if (wakingUp && mWakefulnessLifecycle.getLastWakeReason()
- == PowerManager.WAKE_REASON_POWER_BUTTON
- || !wakingUp && mWakefulnessLifecycle.getLastSleepReason()
- == PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON) {
+ final boolean wakingUpFromPowerButton = wakingUp
+ && !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)
+ && mWakefulnessLifecycle.getLastWakeReason()
+ == PowerManager.WAKE_REASON_POWER_BUTTON;
+ final boolean sleepingFromPowerButton = !wakingUp
+ && mWakefulnessLifecycle.getLastSleepReason()
+ == PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON;
+
+ if (wakingUpFromPowerButton || sleepingFromPowerButton) {
mLightRevealScrim.setRevealEffect(mPowerButtonReveal);
+ mLightRevealScrim.setRevealAmount(1f - mStatusBarStateController.getDozeAmount());
} else if (!wakingUp || !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)) {
// If we're going to sleep, but it's not from the power button, use the default reveal.
// If we're waking up, only use the default reveal if the biometric controller didn't
// already set it to the circular reveal because we're waking up from a fingerprint/face
// auth.
mLightRevealScrim.setRevealEffect(LiftReveal.INSTANCE);
+ mLightRevealScrim.setRevealAmount(1f - mStatusBarStateController.getDozeAmount());
}
}
@@ -3563,7 +3469,7 @@ public class StatusBar extends SystemUI implements
mKeyguardBypassController.setBouncerShowing(bouncerShowing);
mPulseExpansionHandler.setBouncerShowing(bouncerShowing);
setBouncerShowingForStatusBarComponents(bouncerShowing);
- updateHideIconsForBouncer(true /* animate */);
+ mStatusBarHideIconsForBouncerManager.setBouncerShowingAndTriggerUpdate(bouncerShowing);
mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */);
updateScrimController();
if (!mBouncerShowing) {
@@ -4257,24 +4163,6 @@ public class StatusBar extends SystemUI implements
return mTransientShown;
}
-
- public void addExpansionChangedListener(@NonNull ExpansionChangedListener listener) {
- mExpansionChangedListeners.add(listener);
- sendInitialExpansionAmount(listener);
- }
-
- private void sendInitialExpansionAmount(ExpansionChangedListener expansionChangedListener) {
- if (mNotificationPanelViewController != null) {
- expansionChangedListener.onExpansionChanged(
- mNotificationPanelViewController.getExpandedFraction(),
- mNotificationPanelViewController.isExpanded());
- }
- }
-
- public void removeExpansionChangedListener(@NonNull ExpansionChangedListener listener) {
- mExpansionChangedListeners.remove(listener);
- }
-
private void updateLightRevealScrimVisibility() {
if (mLightRevealScrim == null) {
// status bar may not be inflated yet
@@ -4324,7 +4212,7 @@ public class StatusBar extends SystemUI implements
+ "mStatusBarKeyguardViewManager was null");
return;
}
- if (mKeyguardStateController.isKeyguardFadingAway() && !mCallingFadingAwayAfterReveal) {
+ if (mKeyguardStateController.isKeyguardFadingAway()) {
mStatusBarKeyguardViewManager.onKeyguardFadedAway();
}
}
@@ -4486,8 +4374,6 @@ public class StatusBar extends SystemUI implements
&& !mBiometricUnlockController.isWakeAndUnlock()) {
mLightRevealScrim.setRevealAmount(1f - linear);
}
-
- mDialogLaunchAnimator.onDozeAmountChanged(linear);
}
@Override
@@ -4562,5 +4448,4 @@ public class StatusBar extends SystemUI implements
return mStartingSurfaceOptional.get().getBackgroundColor(task);
}
};
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
index bb1daa252cdf..a77a097f0453 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java
@@ -95,6 +95,7 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks {
private final SysuiStatusBarStateController mStatusBarStateController;
private final NotificationShadeWindowView mNotificationShadeWindowView;
private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
+ private final StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
private final PowerManager mPowerManager;
private final VibratorHelper mVibratorHelper;
private final Optional<Vibrator> mVibratorOptional;
@@ -132,6 +133,7 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks {
SysuiStatusBarStateController statusBarStateController,
NotificationShadeWindowView notificationShadeWindowView,
NotificationStackScrollLayoutController notificationStackScrollLayoutController,
+ StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
PowerManager powerManager,
VibratorHelper vibratorHelper,
Optional<Vibrator> vibratorOptional,
@@ -158,6 +160,7 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks {
mStatusBarStateController = statusBarStateController;
mNotificationShadeWindowView = notificationShadeWindowView;
mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
+ mStatusBarHideIconsForBouncerManager = statusBarHideIconsForBouncerManager;
mPowerManager = powerManager;
mVibratorHelper = vibratorHelper;
mVibratorOptional = vibratorOptional;
@@ -509,14 +512,8 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks {
@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 */);
+ mStatusBarHideIconsForBouncerManager
+ .setTopAppHidesStatusBarAndTriggerUpdate(topAppHidesStatusBar);
}
@Override
@@ -534,13 +531,11 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks {
if (StatusBar.DEBUG_WINDOW_STATE) {
Log.d(StatusBar.TAG, "Status bar " + windowStateToString(state));
}
- if (mStatusBar.getStatusBarView() != null) {
- if (!showing && mStatusBarStateController.getState() == StatusBarState.SHADE) {
+ if (mStatusBar.getStatusBarView() != null
+ && !showing
+ && mStatusBarStateController.getState() == StatusBarState.SHADE) {
mNotificationPanelViewController.collapsePanel(
false /* animate */, false /* delayed */, 1.0f /* speedUpFactor */);
- }
-
- mStatusBar.updateHideIconsForBouncer(false /* animate */);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
index 16d7f983d0f3..b7988bcc6f45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
@@ -18,13 +18,14 @@ package com.android.systemui.statusbar.phone
import android.content.Context
import android.content.res.Resources
+import android.graphics.Point
import android.graphics.Rect
import android.util.LruCache
import android.util.Pair
import android.view.DisplayCutout
-import android.view.View.LAYOUT_DIRECTION_RTL
-import android.view.WindowMetrics
+
import androidx.annotation.VisibleForTesting
+
import com.android.internal.policy.SystemBarUtils
import com.android.systemui.Dumpable
import com.android.systemui.R
@@ -32,16 +33,18 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.policy.CallbackController
import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.util.leak.RotationUtils
import com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE
import com.android.systemui.util.leak.RotationUtils.ROTATION_NONE
import com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE
import com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN
import com.android.systemui.util.leak.RotationUtils.Rotation
+import com.android.systemui.util.leak.RotationUtils.getExactRotation
import com.android.systemui.util.leak.RotationUtils.getResourcesForRotation
+
import java.io.FileDescriptor
import java.io.PrintWriter
import java.lang.Math.max
+
import javax.inject.Inject
/**
@@ -112,62 +115,135 @@ class StatusBarContentInsetsProvider @Inject constructor(
}
/**
+ * Some views may need to care about whether or not the current top display cutout is located
+ * in the corner rather than somewhere in the center. In the case of a corner cutout, the
+ * status bar area is contiguous.
+ */
+ fun currentRotationHasCornerCutout(): Boolean {
+ val cutout = context.display.cutout ?: return false
+ val topBounds = cutout.boundingRectTop
+
+ val point = Point()
+ context.display.getRealSize(point)
+
+ return topBounds.left <= 0 || topBounds.right >= point.y
+ }
+
+ /**
* Calculates the maximum bounding rectangle for the privacy chip animation + ongoing privacy
* dot in the coordinates relative to the given rotation.
+ *
+ * @param rotation the rotation for which the bounds are required. This is an absolute value
+ * (i.e., ROTATION_NONE will always return the same bounds regardless of the context
+ * from which this method is called)
*/
fun getBoundingRectForPrivacyChipForRotation(@Rotation rotation: Int): Rect {
var insets = insetsCache[getCacheKey(rotation = rotation)]
- val rotatedResources = getResourcesForRotation(rotation, context)
if (insets == null) {
- insets = getStatusBarContentInsetsForRotation(rotation, rotatedResources)
+ insets = getStatusBarContentAreaForRotation(rotation)
}
+ val rotatedResources = getResourcesForRotation(rotation, context)
+
val dotWidth = rotatedResources.getDimensionPixelSize(R.dimen.ongoing_appops_dot_diameter)
val chipWidth = rotatedResources.getDimensionPixelSize(
R.dimen.ongoing_appops_chip_max_width)
- val isRtl = context.resources.configuration.layoutDirection == LAYOUT_DIRECTION_RTL
+ val isRtl = configurationController.isLayoutRtl
return getPrivacyChipBoundingRectForInsets(insets, dotWidth, chipWidth, isRtl)
}
/**
- * Calculates the necessary left and right locations for the status bar contents invariant of
- * the current device rotation, in the target rotation's coordinates
+ * Calculate the distance from the left and right edges of the screen to the status bar
+ * content area. This differs from the content area rects in that these values can be used
+ * directly as padding.
+ *
+ * @param rotation the target rotation for which to calculate insets
+ */
+ fun getStatusBarContentInsetsForRotation(@Rotation rotation: Int): Pair<Int, Int> {
+ val key = getCacheKey(rotation)
+
+ val point = Point()
+ context.display.getRealSize(point)
+ // Target rotation can be a different orientation than the current device rotation
+ point.orientToRotZero(getExactRotation(context))
+ val width = point.logicalWidth(rotation)
+
+ val area = insetsCache[key] ?: getAndSetCalculatedAreaForRotation(
+ rotation, getResourcesForRotation(rotation, context), key)
+
+ return Pair(area.left, width - area.right)
+ }
+
+ /**
+ * Calculate the left and right insets for the status bar content in the device's current
+ * rotation
+ * @see getStatusBarContentAreaForRotation
+ */
+ fun getStatusBarContentInsetsForCurrentRotation(): Pair<Int, Int> {
+ return getStatusBarContentInsetsForRotation(getExactRotation(context))
+ }
+
+ /**
+ * Calculates the area of the status bar contents invariant of the current device rotation,
+ * in the target rotation's coordinates
+ *
+ * @param rotation the rotation for which the bounds are required. This is an absolute value
+ * (i.e., ROTATION_NONE will always return the same bounds regardless of the context
+ * from which this method is called)
*/
@JvmOverloads
- fun getStatusBarContentInsetsForRotation(
- @Rotation rotation: Int,
- rotatedResources: Resources = getResourcesForRotation(rotation, context)
+ fun getStatusBarContentAreaForRotation(
+ @Rotation rotation: Int
+ ): Rect {
+ val key = getCacheKey(rotation)
+ return insetsCache[key] ?: getAndSetCalculatedAreaForRotation(
+ rotation, getResourcesForRotation(rotation, context), key)
+ }
+
+ /**
+ * Get the status bar content area for the given rotation, in absolute bounds
+ */
+ fun getStatusBarContentAreaForCurrentRotation(): Rect {
+ val rotation = getExactRotation(context)
+ return getStatusBarContentAreaForRotation(rotation)
+ }
+
+ private fun getAndSetCalculatedAreaForRotation(
+ @Rotation targetRotation: Int,
+ rotatedResources: Resources,
+ key: CacheKey
): Rect {
- val key = getCacheKey(rotation = rotation)
- return insetsCache[key] ?: getCalculatedInsetsForRotation(rotation, rotatedResources)
- .also {
- insetsCache.put(key, it)
- }
+ return getCalculatedAreaForRotation(targetRotation, rotatedResources)
+ .also {
+ insetsCache.put(key, it)
+ }
}
- private fun getCalculatedInsetsForRotation(
+ private fun getCalculatedAreaForRotation(
@Rotation targetRotation: Int,
rotatedResources: Resources
): Rect {
val dc = context.display.cutout
- val currentRotation = RotationUtils.getExactRotation(context)
+ val currentRotation = getExactRotation(context)
- val isRtl = rotatedResources.configuration.layoutDirection == LAYOUT_DIRECTION_RTL
val roundedCornerPadding = rotatedResources
.getDimensionPixelSize(R.dimen.rounded_corner_content_padding)
- val minDotWidth = if (isPrivacyDotEnabled)
+ val minDotPadding = if (isPrivacyDotEnabled)
rotatedResources.getDimensionPixelSize(R.dimen.ongoing_appops_dot_min_padding)
else 0
+ val dotWidth = if (isPrivacyDotEnabled)
+ rotatedResources.getDimensionPixelSize(R.dimen.ongoing_appops_dot_diameter)
+ else 0
val minLeft: Int
val minRight: Int
- if (isRtl) {
- minLeft = max(minDotWidth, roundedCornerPadding)
+ if (configurationController.isLayoutRtl) {
+ minLeft = max(minDotPadding, roundedCornerPadding)
minRight = roundedCornerPadding
} else {
minLeft = roundedCornerPadding
- minRight = max(minDotWidth, roundedCornerPadding)
+ minRight = max(minDotPadding, roundedCornerPadding)
}
return calculateInsetsForRotationWithRotatedResources(
@@ -175,9 +251,11 @@ class StatusBarContentInsetsProvider @Inject constructor(
targetRotation,
dc,
context.resources.configuration.windowConfiguration.maxBounds,
- SystemBarUtils.getStatusBarHeight(context),
+ SystemBarUtils.getStatusBarHeightForRotation(context, targetRotation),
minLeft,
- minRight)
+ minRight,
+ configurationController.isLayoutRtl,
+ dotWidth)
}
fun getStatusBarPaddingTop(@Rotation rotation: Int? = null): Int {
@@ -246,10 +324,13 @@ fun getPrivacyChipBoundingRectForInsets(
*
* @param currentRotation current device rotation
* @param targetRotation rotation for which to calculate the status bar content rect
- * @param displayCutout [DisplayCutout] for the curren display. possibly null
- * @param windowMetrics [WindowMetrics] for the current window
+ * @param displayCutout [DisplayCutout] for the current display. possibly null
+ * @param maxBounds the display bounds in our current rotation
* @param statusBarHeight height of the status bar for the target rotation
- * @param roundedCornerPadding from rounded_corner_content_padding
+ * @param minLeft the minimum padding to enforce on the left
+ * @param minRight the minimum padding to enforce on the right
+ * @param isRtl current layout direction is Right-To-Left or not
+ * @param dotWidth privacy dot image width (0 if privacy dot is disabled)
*
* @see [RotationUtils#getResourcesForRotation]
*/
@@ -260,7 +341,9 @@ fun calculateInsetsForRotationWithRotatedResources(
maxBounds: Rect,
statusBarHeight: Int,
minLeft: Int,
- minRight: Int
+ minRight: Int,
+ isRtl: Boolean,
+ dotWidth: Int
): Rect {
/*
TODO: Check if this is ever used for devices with no rounded corners
@@ -279,6 +362,8 @@ fun calculateInsetsForRotationWithRotatedResources(
maxBounds.height(),
minLeft,
minRight,
+ isRtl,
+ dotWidth,
targetRotation,
currentRotation)
@@ -296,6 +381,8 @@ fun calculateInsetsForRotationWithRotatedResources(
* @param cHeight display height in our current rotation
* @param minLeft the minimum padding to enforce on the left
* @param minRight the minimum padding to enforce on the right
+ * @param isRtl current layout direction is Right-To-Left or not
+ * @param dotWidth privacy dot image width (0 if privacy dot is disabled)
* @param targetRotation the rotation for which to calculate margins
* @param currentRotation the rotation from which the display cutout was generated
*
@@ -311,6 +398,8 @@ private fun getStatusBarLeftRight(
cHeight: Int,
minLeft: Int,
minRight: Int,
+ isRtl: Boolean,
+ dotWidth: Int,
@Rotation targetRotation: Int,
@Rotation currentRotation: Int
): Rect {
@@ -345,13 +434,16 @@ private fun getStatusBarLeftRight(
}
if (cutoutRect.touchesLeftEdge(relativeRotation, cWidth, cHeight)) {
-
- val l = max(minLeft, cutoutRect.logicalWidth(relativeRotation))
- leftMargin = max(l, leftMargin)
+ var logicalWidth = cutoutRect.logicalWidth(relativeRotation)
+ if (isRtl) logicalWidth += dotWidth
+ leftMargin = max(logicalWidth, leftMargin)
} else if (cutoutRect.touchesRightEdge(relativeRotation, cWidth, cHeight)) {
- val logicalWidth = cutoutRect.logicalWidth(relativeRotation)
- rightMargin = max(minRight, logicalWidth)
+ var logicalWidth = cutoutRect.logicalWidth(relativeRotation)
+ if (!isRtl) logicalWidth += dotWidth
+ rightMargin = max(rightMargin, logicalWidth)
}
+ // TODO(b/203626889): Fix the scenario when config_mainBuiltInDisplayCutoutRectApproximation
+ // is very close to but not directly touch edges.
}
return Rect(leftMargin, 0, logicalDisplayWidth - rightMargin, sbHeight)
@@ -445,3 +537,22 @@ private fun Rect.logicalWidth(@Rotation rot: Int): Int {
private fun Int.isHorizontal(): Boolean {
return this == ROTATION_LANDSCAPE || this == ROTATION_SEASCAPE
}
+
+private fun Point.orientToRotZero(@Rotation rot: Int) {
+ when (rot) {
+ ROTATION_NONE, ROTATION_UPSIDE_DOWN -> return
+ else -> {
+ // swap width and height to zero-orient bounds
+ val yTmp = y
+ y = x
+ x = yTmp
+ }
+ }
+}
+
+private fun Point.logicalWidth(@Rotation rot: Int): Int {
+ return when (rot) {
+ ROTATION_NONE, ROTATION_UPSIDE_DOWN -> x
+ else -> y
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
index ca877af150da..6eeae7f29839 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
@@ -24,6 +24,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
import javax.inject.Inject;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt
new file mode 100644
index 000000000000..d2181d0480d2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt
@@ -0,0 +1,133 @@
+package com.android.systemui.statusbar.phone
+
+import com.android.systemui.Dumpable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.util.concurrency.DelayableExecutor
+import java.io.FileDescriptor
+import java.io.PrintWriter
+import javax.inject.Inject
+
+/**
+ * A class that manages if the status bar (clock + notifications + signal cluster) should be visible
+ * or not when showing the bouncer.
+ *
+ * We want to hide it when:
+ * • User swipes up on the keyguard
+ * • Locked activity that doesn't show a status bar requests the bouncer.
+ *
+ * [getShouldHideStatusBarIconsForBouncer] is the main exported method for this class. The other
+ * methods set state variables that are used in the calculation or manually trigger an update.
+ */
+@SysUISingleton
+class StatusBarHideIconsForBouncerManager @Inject constructor(
+ private val commandQueue: CommandQueue,
+ @Main private val mainExecutor: DelayableExecutor,
+ dumpManager: DumpManager
+) : Dumpable {
+ // State variables set by external classes.
+ private var panelExpanded: Boolean = false
+ private var isOccluded: Boolean = false
+ private var bouncerShowing: Boolean = false
+ private var topAppHidesStatusBar: Boolean = false
+ private var statusBarWindowHidden: Boolean = false
+ private var displayId: Int = 0
+
+ // State variables calculated internally.
+ private var hideIconsForBouncer: Boolean = false
+ private var bouncerWasShowingWhenHidden: Boolean = false
+ private var wereIconsJustHidden: Boolean = false
+
+ init {
+ dumpManager.registerDumpable(this)
+ }
+
+ /** Returns true if the status bar icons should be hidden in the bouncer. */
+ fun getShouldHideStatusBarIconsForBouncer(): Boolean {
+ return hideIconsForBouncer || wereIconsJustHidden
+ }
+
+ fun setStatusBarWindowHidden(statusBarWindowHidden: Boolean) {
+ this.statusBarWindowHidden = statusBarWindowHidden
+ }
+
+ fun setDisplayId(displayId: Int) {
+ this.displayId = displayId
+ }
+
+ fun setPanelExpandedAndTriggerUpdate(panelExpanded: Boolean) {
+ this.panelExpanded = panelExpanded
+ updateHideIconsForBouncer(animate = false)
+ }
+
+ fun setIsOccludedAndTriggerUpdate(isOccluded: Boolean) {
+ this.isOccluded = isOccluded
+ updateHideIconsForBouncer(animate = false)
+ }
+
+ fun setBouncerShowingAndTriggerUpdate(bouncerShowing: Boolean) {
+ this.bouncerShowing = bouncerShowing
+ updateHideIconsForBouncer(animate = true)
+ }
+
+ fun setTopAppHidesStatusBarAndTriggerUpdate(topAppHidesStatusBar: Boolean) {
+ this.topAppHidesStatusBar = topAppHidesStatusBar
+ if (!topAppHidesStatusBar && wereIconsJustHidden) {
+ // Immediately update the icon hidden state, since that should only apply if we're
+ // staying fullscreen.
+ wereIconsJustHidden = false
+ commandQueue.recomputeDisableFlags(displayId, /* animate= */ true)
+ }
+ updateHideIconsForBouncer(animate = true)
+ }
+
+ /**
+ * Updates whether the status bar icons should be hidden in the bouncer. May trigger
+ * [commandQueue.recomputeDisableFlags] if the icon visibility status changes.
+ */
+ fun updateHideIconsForBouncer(animate: Boolean) {
+ val hideBecauseApp =
+ topAppHidesStatusBar &&
+ isOccluded &&
+ (statusBarWindowHidden || bouncerShowing)
+ val hideBecauseKeyguard = !panelExpanded && !isOccluded && bouncerShowing
+ val shouldHideIconsForBouncer = hideBecauseApp || hideBecauseKeyguard
+ if (hideIconsForBouncer != shouldHideIconsForBouncer) {
+ hideIconsForBouncer = shouldHideIconsForBouncer
+ if (!shouldHideIconsForBouncer && bouncerWasShowingWhenHidden) {
+ // We're delaying the showing, since most of the time the fullscreen app will
+ // hide the icons again and we don't want them to fade in and out immediately again.
+ wereIconsJustHidden = true
+ mainExecutor.executeDelayed(
+ {
+ wereIconsJustHidden = false
+ commandQueue.recomputeDisableFlags(displayId, true)
+ },
+ 500
+ )
+ } else {
+ commandQueue.recomputeDisableFlags(displayId, animate)
+ }
+ }
+ if (shouldHideIconsForBouncer) {
+ bouncerWasShowingWhenHidden = bouncerShowing
+ }
+ }
+
+ override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+ pw.println("---- State variables set externally ----")
+ pw.println("panelExpanded=$panelExpanded")
+ pw.println("isOccluded=$isOccluded")
+ pw.println("bouncerShowing=$bouncerShowing")
+ pw.println("topAppHideStatusBar=$topAppHidesStatusBar")
+ pw.println("statusBarWindowHidden=$statusBarWindowHidden")
+ pw.println("displayId=$displayId")
+
+ pw.println("---- State variables calculated internally ----")
+ pw.println("hideIconsForBouncer=$hideIconsForBouncer")
+ pw.println("bouncerWasShowingWhenHidden=$bouncerWasShowingWhenHidden")
+ pw.println("wereIconsJustHidden=$wereIconsJustHidden")
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 07489a91f128..7ab4a1ec237e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -51,7 +51,6 @@ import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.DejankUtils;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dock.DockManager;
-import com.android.systemui.keyguard.FaceAuthScreenBrightnessController;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.navigationbar.NavigationModeController;
@@ -64,13 +63,14 @@ import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Objects;
-import java.util.Optional;
import javax.inject.Inject;
@@ -109,7 +109,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
private final ConfigurationController mConfigurationController;
private final NavigationModeController mNavigationModeController;
private final NotificationShadeWindowController mNotificationShadeWindowController;
- private final Optional<FaceAuthScreenBrightnessController> mFaceAuthScreenBrightnessController;
private final KeyguardBouncer.Factory mKeyguardBouncerFactory;
private final WakefulnessLifecycle mWakefulnessLifecycle;
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@@ -242,7 +241,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
DockManager dockManager,
NotificationShadeWindowController notificationShadeWindowController,
KeyguardStateController keyguardStateController,
- Optional<FaceAuthScreenBrightnessController> faceAuthScreenBrightnessController,
NotificationMediaManager notificationMediaManager,
KeyguardBouncer.Factory keyguardBouncerFactory,
WakefulnessLifecycle wakefulnessLifecycle,
@@ -260,7 +258,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mKeyguardUpdateManager = keyguardUpdateMonitor;
mStatusBarStateController = sysuiStatusBarStateController;
mDockManager = dockManager;
- mFaceAuthScreenBrightnessController = faceAuthScreenBrightnessController;
mKeyguardBouncerFactory = keyguardBouncerFactory;
mWakefulnessLifecycle = wakefulnessLifecycle;
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
@@ -271,6 +268,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
@Override
public void registerStatusBar(StatusBar statusBar,
NotificationPanelViewController notificationPanelViewController,
+ PanelExpansionStateManager panelExpansionStateManager,
BiometricUnlockController biometricUnlockController,
View notificationContainer,
KeyguardBypassController bypassController) {
@@ -280,16 +278,13 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
ViewGroup container = mStatusBar.getBouncerContainer();
mBouncer = mKeyguardBouncerFactory.create(container, mExpansionCallback);
mNotificationPanelViewController = notificationPanelViewController;
- notificationPanelViewController.addExpansionListener(this);
+ if (panelExpansionStateManager != null) {
+ panelExpansionStateManager.addExpansionListener(this);
+ }
mBypassController = bypassController;
mNotificationContainer = notificationContainer;
mKeyguardMessageAreaController = mKeyguardMessageAreaFactory.create(
KeyguardMessageArea.findSecurityMessageDisplay(container));
- mFaceAuthScreenBrightnessController.ifPresent((it) -> {
- View overlay = new View(mContext);
- container.addView(overlay);
- it.attach(overlay);
- });
registerListeners();
}
@@ -333,7 +328,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
@Override
- public void onPanelExpansionChanged(float expansion, boolean tracking) {
+ public void onPanelExpansionChanged(float fraction, boolean expanded, boolean tracking) {
// We don't want to translate the bounce when:
// • Keyguard is occluded, because we're in a FLAG_SHOW_WHEN_LOCKED activity and need to
// conserve the original animation.
@@ -346,14 +341,14 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
} else if (mShowing) {
if (!isWakeAndUnlocking() && !mStatusBar.isInLaunchTransition()) {
- mBouncer.setExpansion(expansion);
+ mBouncer.setExpansion(fraction);
}
- if (expansion != KeyguardBouncer.EXPANSION_HIDDEN && tracking
+ if (fraction != KeyguardBouncer.EXPANSION_HIDDEN && tracking
&& !mKeyguardStateController.canDismissLockScreen()
&& !mBouncer.isShowing() && !mBouncer.isAnimatingAway()) {
mBouncer.show(false /* resetSecuritySelection */, false /* scrimmed */);
}
- } else if (mPulsing && expansion == KeyguardBouncer.EXPANSION_VISIBLE) {
+ } else if (mPulsing && fraction == KeyguardBouncer.EXPANSION_VISIBLE) {
// Panel expanded while pulsing but didn't translate the bouncer (because we are
// unlocked.) Let's simply wake-up to dismiss the lock screen.
mStatusBar.wakeUpIfDozing(SystemClock.uptimeMillis(), mStatusBar.getBouncerContainer(),
@@ -632,7 +627,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED,
SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__OCCLUDED);
if (mStatusBar.isInLaunchTransition()) {
- mOccluded = true;
+ setOccludedAndUpdateStates(true);
mStatusBar.fadeKeyguardAfterLaunchTransition(null /* beforeFading */,
new Runnable() {
@Override
@@ -645,7 +640,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
if (mStatusBar.isLaunchingActivityOverLockscreen()) {
- mOccluded = true;
+ setOccludedAndUpdateStates(true);
// When isLaunchingActivityOverLockscreen() is true, we know for sure that the post
// collapse runnables will be run.
@@ -660,7 +655,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN);
}
boolean isOccluding = !mOccluded && occluded;
- mOccluded = occluded;
+ setOccludedAndUpdateStates(occluded);
if (mShowing) {
mMediaManager.updateMediaMetaData(false, animate && !occluded);
}
@@ -677,6 +672,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
}
+ private void setOccludedAndUpdateStates(boolean occluded) {
+ mOccluded = occluded;
+ updateStates();
+ }
+
public boolean isOccluded() {
return mOccluded;
}
@@ -917,7 +917,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
@Override
public boolean bouncerIsOrWillBeShowing() {
- return mBouncer.isShowing() || mBouncer.getShowingSoon();
+ return isBouncerShowing() || mBouncer.getShowingSoon();
}
public boolean isFullscreenBouncer() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt
index 8ef186c316f9..805ddf5fc180 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt
@@ -17,19 +17,17 @@ package com.android.systemui.statusbar.phone
import android.view.View
import android.view.WindowManager
-import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator
import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator.ViewCenterProvider
-import com.android.systemui.unfold.UNFOLD_STATUS_BAR
+import com.android.systemui.unfold.SysUIUnfoldScope
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
import javax.inject.Inject
-import javax.inject.Named
-@SysUISingleton
+@SysUIUnfoldScope
class StatusBarMoveFromCenterAnimationController @Inject constructor(
- @Named(UNFOLD_STATUS_BAR) private val progressProvider: ScopedUnfoldTransitionProgressProvider,
- private val windowManager: WindowManager,
+ private val progressProvider: ScopedUnfoldTransitionProgressProvider,
+ private val windowManager: WindowManager
) {
private val transitionListener = TransitionListener()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index c655964e64bc..ecd5c985154c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -17,9 +17,7 @@ package com.android.systemui.statusbar.phone;
import static com.android.systemui.statusbar.phone.StatusBar.CLOSE_PANEL_WHEN_EMPTIED;
import static com.android.systemui.statusbar.phone.StatusBar.DEBUG;
import static com.android.systemui.statusbar.phone.StatusBar.MULTIUSER_DEBUG;
-import static com.android.systemui.statusbar.phone.StatusBar.SPEW;
-import android.annotation.Nullable;
import android.app.KeyguardManager;
import android.content.Context;
import android.os.RemoteException;
@@ -36,7 +34,6 @@ import android.widget.TextView;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.widget.MessagingGroup;
import com.android.internal.widget.MessagingMessage;
import com.android.keyguard.KeyguardUpdateMonitor;
@@ -44,6 +41,7 @@ import com.android.systemui.Dependency;
import com.android.systemui.ForegroundServiceNotificationListener;
import com.android.systemui.InitController;
import com.android.systemui.R;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.statusbar.CommandQueue;
@@ -59,10 +57,10 @@ import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.AboveShelfObserver;
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.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -88,6 +86,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
private final NotificationViewHierarchyManager mViewHierarchyManager;
private final NotificationLockscreenUserManager mLockscreenUserManager;
private final SysuiStatusBarStateController mStatusBarStateController;
+ private final NotifShadeEventSource mNotifShadeEventSource;
private final NotificationEntryManager mEntryManager;
private final NotificationMediaManager mMediaManager;
private final NotificationGutsManager mGutsManager;
@@ -100,6 +99,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
private final DozeScrimController mDozeScrimController;
private final ScrimController mScrimController;
private final KeyguardIndicationController mKeyguardIndicationController;
+ private final FeatureFlags mFeatureFlags;
private final StatusBar mStatusBar;
private final ShadeController mShadeController;
private final LockscreenShadeTransitionController mShadeTransitionController;
@@ -127,6 +127,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
DynamicPrivacyController dynamicPrivacyController,
KeyguardStateController keyguardStateController,
KeyguardIndicationController keyguardIndicationController,
+ FeatureFlags featureFlags,
StatusBar statusBar,
ShadeController shadeController,
LockscreenShadeTransitionController shadeTransitionController,
@@ -134,6 +135,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
NotificationViewHierarchyManager notificationViewHierarchyManager,
NotificationLockscreenUserManager lockscreenUserManager,
SysuiStatusBarStateController sysuiStatusBarStateController,
+ NotifShadeEventSource notifShadeEventSource,
NotificationEntryManager notificationEntryManager,
NotificationMediaManager notificationMediaManager,
NotificationGutsManager notificationGutsManager,
@@ -148,6 +150,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
mHeadsUpManager = headsUp;
mDynamicPrivacyController = dynamicPrivacyController;
mKeyguardIndicationController = keyguardIndicationController;
+ mFeatureFlags = featureFlags;
// TODO: use KeyguardStateController#isOccluded to remove this dependency
mStatusBar = statusBar;
mShadeController = shadeController;
@@ -156,6 +159,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
mViewHierarchyManager = notificationViewHierarchyManager;
mLockscreenUserManager = lockscreenUserManager;
mStatusBarStateController = sysuiStatusBarStateController;
+ mNotifShadeEventSource = notifShadeEventSource;
mEntryManager = notificationEntryManager;
mMediaManager = notificationMediaManager;
mGutsManager = notificationGutsManager;
@@ -186,30 +190,18 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
mNotificationPanel.createRemoteInputDelegate());
initController.addPostInitTask(() -> {
- NotificationEntryListener notificationEntryListener = new NotificationEntryListener() {
- @Override
- public void onEntryRemoved(
- @Nullable NotificationEntry entry,
- NotificationVisibility visibility,
- boolean removedByUser,
- int reason) {
- StatusBarNotificationPresenter.this.onNotificationRemoved(
- entry.getKey(), entry.getSbn(), reason);
- if (removedByUser) {
- maybeEndAmbientPulse();
- }
- }
- };
-
mKeyguardIndicationController.init();
mViewHierarchyManager.setUpWithPresenter(this,
stackScrollerController.getNotificationListContainer());
- mEntryManager.setUpWithPresenter(this);
- mEntryManager.addNotificationEntryListener(notificationEntryListener);
- mEntryManager.addNotificationLifetimeExtender(mHeadsUpManager);
- mEntryManager.addNotificationLifetimeExtender(mGutsManager);
- mEntryManager.addNotificationLifetimeExtenders(
- remoteInputManager.getLifetimeExtenders());
+ mNotifShadeEventSource.setShadeEmptiedCallback(this::maybeClosePanelForShadeEmptied);
+ mNotifShadeEventSource.setNotifRemovedByUserCallback(this::maybeEndAmbientPulse);
+ if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+ mEntryManager.setUpWithPresenter(this);
+ mEntryManager.addNotificationLifetimeExtender(mHeadsUpManager);
+ mEntryManager.addNotificationLifetimeExtender(mGutsManager);
+ mEntryManager.addNotificationLifetimeExtenders(
+ remoteInputManager.getLifetimeExtenders());
+ }
notificationInterruptStateProvider.addSuppressor(mInterruptSuppressor);
mLockscreenUserManager.setUpWithPresenter(this);
mMediaManager.setUpWithPresenter(this);
@@ -226,8 +218,21 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
configurationController.addCallback(this);
}
+ /** Called when the shade has been emptied to attempt to close the shade */
+ private void maybeClosePanelForShadeEmptied() {
+ if (CLOSE_PANEL_WHEN_EMPTIED
+ && !mNotificationPanel.isTracking()
+ && !mNotificationPanel.isQsExpanded()
+ && mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED
+ && !isCollapsing()) {
+ mStatusBarStateController.setState(StatusBarState.KEYGUARD);
+ }
+ }
+
@Override
public void onDensityOrFontScaleChanged() {
+ // TODO(b/145659174): Remove legacy pipeline code
+ if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) return;
MessagingMessage.dropCache();
MessagingGroup.dropCache();
if (!mKeyguardUpdateMonitor.isSwitchingUser()) {
@@ -239,8 +244,10 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
@Override
public void onUiModeChanged() {
+ // TODO(b/145659174): Remove legacy pipeline code
+ if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) return;
if (!mKeyguardUpdateMonitor.isSwitchingUser()) {
- updateNotificationOnUiModeChanged();
+ updateNotificationsOnUiModeChanged();
} else {
mDispatchUiModeChangeOnUserSwitched = true;
}
@@ -251,7 +258,9 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
onDensityOrFontScaleChanged();
}
- private void updateNotificationOnUiModeChanged() {
+ private void updateNotificationsOnUiModeChanged() {
+ // TODO(b/145659174): Remove legacy pipeline code
+ if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) return;
List<NotificationEntry> userNotifications =
mEntryManager.getActiveNotificationsForCurrentUser();
for (int i = 0; i < userNotifications.size(); i++) {
@@ -264,6 +273,8 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
}
private void updateNotificationsOnDensityOrFontScaleChanged() {
+ // TODO(b/145659174): Remove legacy pipeline code
+ if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) return;
List<NotificationEntry> userNotifications =
mEntryManager.getActiveNotificationsForCurrentUser();
for (int i = 0; i < userNotifications.size(); i++) {
@@ -276,6 +287,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
}
}
+
@Override
public boolean isCollapsing() {
return mNotificationPanel.isCollapsing()
@@ -302,27 +314,10 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
mShadeController.addPostCollapseAction(() -> updateNotificationViews(reason));
return;
}
-
mViewHierarchyManager.updateNotificationViews();
-
mNotificationPanel.updateNotificationViews(reason);
}
- private void onNotificationRemoved(String key, StatusBarNotification old, int reason) {
- if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
-
- if (old != null && CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications()
- && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()
- && mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED
- && !isCollapsing()) {
- mStatusBarStateController.setState(StatusBarState.KEYGUARD);
- }
- }
-
- public boolean hasActiveNotifications() {
- return mEntryManager.hasActiveNotifications();
- }
-
@Override
public void onUserSwitched(int newUserId) {
// Begin old BaseStatusBar.userSwitched
@@ -335,7 +330,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
mReinflateNotificationsOnUserSwitched = false;
}
if (mDispatchUiModeChangeOnUserSwitched) {
- updateNotificationOnUiModeChanged();
+ updateNotificationsOnUiModeChanged();
mDispatchUiModeChangeOnUserSwitched = false;
}
updateNotificationViews("user switched");
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 fbd9ef7e3707..9c69f51332a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import android.annotation.NonNull;
import android.content.Context;
import android.os.Handler;
import android.telephony.SubscriptionInfo;
@@ -26,11 +27,11 @@ import com.android.settingslib.mobile.TelephonyIcons;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.statusbar.connectivity.IconState;
+import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
import com.android.systemui.statusbar.connectivity.NetworkController;
-import com.android.systemui.statusbar.connectivity.NetworkController.IconState;
-import com.android.systemui.statusbar.connectivity.NetworkController.MobileDataIndicators;
-import com.android.systemui.statusbar.connectivity.NetworkController.WifiIndicators;
-import com.android.systemui.statusbar.connectivity.NetworkControllerImpl;
+import com.android.systemui.statusbar.connectivity.SignalCallback;
+import com.android.systemui.statusbar.connectivity.WifiIndicators;
import com.android.systemui.statusbar.policy.SecurityController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -44,7 +45,7 @@ import javax.inject.Inject;
/** Controls the signal policies for icons shown in the StatusBar. **/
@SysUISingleton
-public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallback,
+public class StatusBarSignalPolicy implements SignalCallback,
SecurityController.SecurityControllerCallback, Tunable {
private static final String TAG = "StatusBarSignalPolicy";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -169,7 +170,7 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba
}
@Override
- public void setWifiIndicators(WifiIndicators indicators) {
+ public void setWifiIndicators(@NonNull WifiIndicators indicators) {
if (DEBUG) {
Log.d(TAG, "setWifiIndicators: " + indicators);
}
@@ -219,7 +220,7 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba
}
@Override
- public void setCallIndicator(IconState statusIcon, int subId) {
+ public void setCallIndicator(@NonNull IconState statusIcon, int subId) {
if (DEBUG) {
Log.d(TAG, "setCallIndicator: "
+ "statusIcon = " + statusIcon + ","
@@ -247,7 +248,7 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba
}
@Override
- public void setMobileDataIndicators(MobileDataIndicators indicators) {
+ public void setMobileDataIndicators(@NonNull MobileDataIndicators indicators) {
if (DEBUG) {
Log.d(TAG, "setMobileDataIndicators: " + indicators);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 9415d5082d10..cf4aaba107cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -22,7 +22,15 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemProperties;
import android.os.UserHandle;
+import android.util.TypedValue;
+import android.view.ViewGroup;
+import android.view.ViewRootImpl;
import android.view.Window;
import android.view.WindowInsets.Type;
import android.view.WindowManager;
@@ -31,6 +39,7 @@ import android.view.WindowManager.LayoutParams;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.animation.DialogListener;
+import com.android.systemui.animation.DialogListener.DismissReason;
import com.android.systemui.animation.ListenableDialog;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -44,16 +53,31 @@ import java.util.Set;
* The SystemUIDialog registers a listener for the screen off / close system dialogs broadcast,
* and dismisses itself when it receives the broadcast.
*/
-public class SystemUIDialog extends AlertDialog implements ListenableDialog {
+public class SystemUIDialog extends AlertDialog implements ListenableDialog,
+ ViewRootImpl.ConfigChangedCallback {
+ // TODO(b/203389579): Remove this once the dialog width on large screens has been agreed on.
+ private static final String FLAG_TABLET_DIALOG_WIDTH =
+ "persist.systemui.flag_tablet_dialog_width";
+
private final Context mContext;
private final DismissReceiver mDismissReceiver;
private final Set<DialogListener> mDialogListeners = new LinkedHashSet<>();
+ private final Handler mHandler = new Handler();
+
+ private int mLastWidth = Integer.MIN_VALUE;
+ private int mLastHeight = Integer.MIN_VALUE;
+ private int mLastConfigurationWidthDp = -1;
+ private int mLastConfigurationHeightDp = -1;
public SystemUIDialog(Context context) {
this(context, R.style.Theme_SystemUI_Dialog);
}
public SystemUIDialog(Context context, int theme) {
+ this(context, theme, true /* dismissOnDeviceLock */);
+ }
+
+ public SystemUIDialog(Context context, int theme, boolean dismissOnDeviceLock) {
super(context, theme);
mContext = context;
@@ -62,19 +86,113 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog {
attrs.setTitle(getClass().getSimpleName());
getWindow().setAttributes(attrs);
- mDismissReceiver = new DismissReceiver(this);
+ mDismissReceiver = dismissOnDeviceLock ? new DismissReceiver(this) : null;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Configuration config = getContext().getResources().getConfiguration();
+ mLastConfigurationWidthDp = config.screenWidthDp;
+ mLastConfigurationHeightDp = config.screenHeightDp;
+ updateWindowSize();
+ }
+
+ private void updateWindowSize() {
+ // Only the thread that created this dialog can update its window size.
+ if (Looper.myLooper() != mHandler.getLooper()) {
+ mHandler.post(this::updateWindowSize);
+ return;
+ }
+
+ int width = getWidth();
+ int height = getHeight();
+ if (width == mLastWidth && height == mLastHeight) {
+ return;
+ }
+
+ mLastWidth = width;
+ mLastHeight = height;
+ getWindow().setLayout(width, height);
+
+ for (DialogListener listener : new LinkedHashSet<>(mDialogListeners)) {
+ listener.onSizeChanged();
+ }
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration configuration) {
+ if (mLastConfigurationWidthDp != configuration.screenWidthDp
+ || mLastConfigurationHeightDp != configuration.screenHeightDp) {
+ mLastConfigurationWidthDp = configuration.screenWidthDp;
+ mLastConfigurationHeightDp = configuration.compatScreenWidthDp;
+
+ updateWindowSize();
+ }
+ }
+
+ /**
+ * Return this dialog width. This method will be invoked when this dialog is created and when
+ * the device configuration changes, and the result will be used to resize this dialog window.
+ */
+ protected int getWidth() {
+ boolean isOnTablet =
+ mContext.getResources().getConfiguration().smallestScreenWidthDp >= 600;
+ if (!isOnTablet) {
+ return ViewGroup.LayoutParams.MATCH_PARENT;
+ }
+
+ int flagValue = SystemProperties.getInt(FLAG_TABLET_DIALOG_WIDTH, 0);
+ if (flagValue == -1) {
+ // The width of bottom sheets (624dp).
+ return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 624,
+ mContext.getResources().getDisplayMetrics()));
+ } else if (flagValue == -2) {
+ // The suggested small width for all dialogs (348dp)
+ return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 348,
+ mContext.getResources().getDisplayMetrics()));
+ } else if (flagValue > 0) {
+ // Any given width.
+ return Math.round(
+ TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, flagValue,
+ mContext.getResources().getDisplayMetrics()));
+ } else {
+ // By default we use the same width as the notification shade in portrait mode (504dp).
+ return mContext.getResources().getDimensionPixelSize(R.dimen.large_dialog_width);
+ }
+ }
+
+ /**
+ * Return this dialog height. This method will be invoked when this dialog is created and when
+ * the device configuration changes, and the result will be used to resize this dialog window.
+ */
+ protected int getHeight() {
+ return ViewGroup.LayoutParams.WRAP_CONTENT;
}
@Override
protected void onStart() {
super.onStart();
- mDismissReceiver.register();
+
+ if (mDismissReceiver != null) {
+ mDismissReceiver.register();
+ }
+
+ // Listen for configuration changes to resize this dialog window. This is mostly necessary
+ // for foldables that often go from large <=> small screen when folding/unfolding.
+ ViewRootImpl.addConfigCallback(this);
}
@Override
protected void onStop() {
super.onStop();
- mDismissReceiver.unregister();
+
+ if (mDismissReceiver != null) {
+ mDismissReceiver.unregister();
+ }
+
+ ViewRootImpl.removeConfigCallback(this);
}
@Override
@@ -89,10 +207,14 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog {
@Override
public void dismiss() {
+ dismiss(DismissReason.UNKNOWN);
+ }
+
+ private void dismiss(DismissReason reason) {
super.dismiss();
for (DialogListener listener : new LinkedHashSet<>(mDialogListeners)) {
- listener.onDismiss();
+ listener.onDismiss(reason);
}
}
@@ -208,7 +330,11 @@ public class SystemUIDialog extends AlertDialog implements ListenableDialog {
@Override
public void onReceive(Context context, Intent intent) {
- mDialog.dismiss();
+ if (mDialog instanceof SystemUIDialog) {
+ ((SystemUIDialog) mDialog).dismiss(DismissReason.DEVICE_LOCKED);
+ } else {
+ mDialog.dismiss();
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt
index 6a49a6da0d62..4f18f8c597b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt
@@ -3,6 +3,7 @@ package com.android.systemui.statusbar.phone
import android.app.Dialog
import android.content.Context
import android.os.Bundle
+import android.view.ViewGroup
import com.android.systemui.animation.HostDialogProvider
/** An implementation of [HostDialogProvider] to be used when animating SysUI dialogs. */
@@ -16,12 +17,18 @@ class SystemUIHostDialogProvider : HostDialogProvider {
return SystemUIHostDialog(context, theme, onCreateCallback, dismissOverride)
}
+ /**
+ * This host dialog is a SystemUIDialog so that it's displayed above all SystemUI windows. Note
+ * that it is not automatically dismissed when the device is locked, but only when the hosted
+ * (original) dialog is dismissed. That way, the behavior of the dialog (dismissed when locking
+ * or not) is consistent with when the dialog is shown with or without the dialog animator.
+ */
private class SystemUIHostDialog(
context: Context,
theme: Int,
private val onCreateCallback: () -> Unit,
private val dismissOverride: (() -> Unit) -> Unit
- ) : SystemUIDialog(context, theme) {
+ ) : SystemUIDialog(context, theme, false /* dismissOnDeviceLock */) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
onCreateCallback()
@@ -32,5 +39,13 @@ class SystemUIHostDialogProvider : HostDialogProvider {
super.dismiss()
}
}
+
+ override fun getWidth(): Int {
+ return ViewGroup.LayoutParams.MATCH_PARENT
+ }
+
+ override fun getHeight(): Int {
+ return ViewGroup.LayoutParams.MATCH_PARENT
+ }
}
} \ No newline at end of file
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 e2332e923aa4..cddde6487ba2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -161,6 +161,8 @@ class UnlockedScreenOffAnimationController @Inject constructor(
// Done going to sleep, reset this flag.
decidedToAnimateGoingToSleep = null
+ // We need to unset the listener. These are persistent for future animators
+ keyguardView.animate().setListener(null)
}
})
.start()
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 418f5884ef62..e06605eac46f 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
@@ -29,7 +29,6 @@ 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;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
@@ -82,12 +81,6 @@ public interface StatusBarComponent {
NotificationShadeWindowViewController getNotificationShadeWindowViewController();
/**
- * Creates a StatusBarWindowViewController.
- */
- @StatusBarScope
- StatusBarWindowController getStatusBarWindowController();
-
- /**
* Creates a NotificationPanelViewController.
*/
@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 c452a486cbe1..3259f6b8027b 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
@@ -29,7 +29,6 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.InitController;
import com.android.systemui.animation.ActivityLaunchAnimator;
-import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollector;
@@ -48,7 +47,7 @@ import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.PluginDependencyProvider;
import com.android.systemui.recents.ScreenPinningRequest;
-import com.android.systemui.settings.brightness.BrightnessSlider;
+import com.android.systemui.settings.brightness.BrightnessSliderController;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -68,6 +67,7 @@ import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
@@ -92,15 +92,15 @@ import com.android.systemui.statusbar.phone.PhoneStatusBarViewController;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager;
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.StatusBarMoveFromCenterAnimationController;
import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
-import com.android.systemui.statusbar.phone.StatusBarWindowView;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -108,11 +108,8 @@ import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.systemui.tuner.TunerService;
-import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
-import com.android.systemui.unfold.UnfoldTransitionWallpaperController;
-import com.android.systemui.unfold.config.UnfoldTransitionConfig;
-import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider;
import com.android.systemui.util.WallpaperController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.MessageRouter;
@@ -146,6 +143,7 @@ public interface StatusBarPhoneModule {
NotificationsController notificationsController,
LightBarController lightBarController,
AutoHideController autoHideController,
+ StatusBarWindowController statusBarWindowController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
PulseExpansionHandler pulseExpansionHandler,
NotificationWakeUpCoordinator notificationWakeUpCoordinator,
@@ -157,11 +155,13 @@ public interface StatusBarPhoneModule {
FalsingManager falsingManager,
FalsingCollector falsingCollector,
BroadcastDispatcher broadcastDispatcher,
+ NotifShadeEventSource notifShadeEventSource,
NotificationEntryManager notificationEntryManager,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
NotificationInterruptStateProvider notificationInterruptStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
+ PanelExpansionStateManager panelExpansionStateManager,
KeyguardViewMediator keyguardViewMediator,
DisplayMetrics displayMetrics,
MetricsLogger metricsLogger,
@@ -203,7 +203,6 @@ public interface StatusBarPhoneModule {
StatusBarNotificationActivityStarter.Builder
statusBarNotificationActivityStarterBuilder,
ShadeController shadeController,
- StatusBarWindowView statusBarWindowView,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
ViewMediatorCallback viewMediatorCallback,
InitController initController,
@@ -220,17 +219,13 @@ public interface StatusBarPhoneModule {
Lazy<NotificationShadeDepthController> notificationShadeDepthController,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
NotificationIconAreaController notificationIconAreaController,
- BrightnessSlider.Factory brightnessSliderFactory,
- UnfoldTransitionConfig unfoldTransitionConfig,
- Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation,
- Lazy<NaturalRotationUnfoldProgressProvider> naturalRotationUnfoldProgressProvider,
- Lazy<UnfoldTransitionWallpaperController> unfoldTransitionWallpaperController,
- Lazy<StatusBarMoveFromCenterAnimationController> statusBarMoveFromCenterAnimation,
+ BrightnessSliderController.Factory brightnessSliderFactory,
WallpaperController wallpaperController,
OngoingCallController ongoingCallController,
SystemStatusAnimationScheduler animationScheduler,
StatusBarLocationPublisher locationPublisher,
StatusBarIconController statusBarIconController,
+ StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
LockscreenShadeTransitionController transitionController,
FeatureFlags featureFlags,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
@@ -242,13 +237,13 @@ public interface StatusBarPhoneModule {
Optional<StartingSurface> startingSurfaceOptional,
TunerService tunerService,
DumpManager dumpManager,
- ActivityLaunchAnimator activityLaunchAnimator,
- DialogLaunchAnimator dialogLaunchAnimator) {
+ ActivityLaunchAnimator activityLaunchAnimator) {
return new StatusBar(
context,
notificationsController,
lightBarController,
autoHideController,
+ statusBarWindowController,
keyguardUpdateMonitor,
pulseExpansionHandler,
notificationWakeUpCoordinator,
@@ -260,11 +255,13 @@ public interface StatusBarPhoneModule {
falsingManager,
falsingCollector,
broadcastDispatcher,
+ notifShadeEventSource,
notificationEntryManager,
notificationGutsManager,
notificationLogger,
notificationInterruptStateProvider,
notificationViewHierarchyManager,
+ panelExpansionStateManager,
keyguardViewMediator,
displayMetrics,
metricsLogger,
@@ -305,7 +302,6 @@ public interface StatusBarPhoneModule {
lightsOutNotifController,
statusBarNotificationActivityStarterBuilder,
shadeController,
- statusBarWindowView,
statusBarKeyguardViewManager,
viewMediatorCallback,
initController,
@@ -323,15 +319,12 @@ public interface StatusBarPhoneModule {
statusBarTouchableRegionManager,
notificationIconAreaController,
brightnessSliderFactory,
- unfoldTransitionConfig,
- unfoldLightRevealOverlayAnimation,
- unfoldTransitionWallpaperController,
- naturalRotationUnfoldProgressProvider,
wallpaperController,
ongoingCallController,
animationScheduler,
locationPublisher,
statusBarIconController,
+ statusBarHideIconsForBouncerManager,
transitionController,
featureFlags,
keyguardUnlockAnimationController,
@@ -343,7 +336,7 @@ public interface StatusBarPhoneModule {
startingSurfaceOptional,
tunerService,
dumpManager,
- activityLaunchAnimator,
- dialogLaunchAnimator);
+ activityLaunchAnimator
+ );
}
}
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 9de0c46ff078..2765fe37f846 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
@@ -19,11 +19,13 @@ package com.android.systemui.statusbar.phone.dagger;
import android.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewStub;
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.flags.FeatureFlags;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
@@ -126,9 +128,16 @@ public abstract class StatusBarViewModule {
@Provides
@Named(SPLIT_SHADE_HEADER)
@StatusBarComponent.StatusBarScope
- public static View getSlitShadeStatusBarView(
- NotificationShadeWindowView notificationShadeWindowView) {
- return notificationShadeWindowView.findViewById(R.id.split_shade_status_bar);
+ public static View getSplitShadeStatusBarView(
+ NotificationShadeWindowView notificationShadeWindowView,
+ FeatureFlags featureFlags) {
+ ViewStub stub = notificationShadeWindowView.findViewById(R.id.qs_header_stub);
+ int layoutId = featureFlags.useCombinedQSHeaders()
+ ? R.layout.combined_qs_header
+ : R.layout.split_shade_header;
+ stub.setLayoutResource(layoutId);
+ View v = stub.inflate();
+ return v;
}
/** */
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 3806d9a2925c..12258136c011 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -39,8 +39,8 @@ import com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureHandler
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
-import com.android.systemui.statusbar.phone.StatusBarWindowController
import com.android.systemui.statusbar.policy.CallbackController
+import com.android.systemui.statusbar.window.StatusBarWindowController
import com.android.systemui.util.time.SystemClock
import java.io.FileDescriptor
import java.io.PrintWriter
@@ -86,7 +86,7 @@ class OngoingCallController @Inject constructor(
//
// TODO(b/183229367): Remove this function override when b/178406514 is fixed.
override fun onEntryAdded(entry: NotificationEntry) {
- onEntryUpdated(entry)
+ onEntryUpdated(entry, true)
}
override fun onEntryUpdated(entry: NotificationEntry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelExpansionListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionListener.java
index 655a25d22337..b9f806d201b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelExpansionListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionListener.java
@@ -11,28 +11,21 @@
* 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
+ * limitations under the License.
*/
-package com.android.systemui.statusbar.phone;
+package com.android.systemui.statusbar.phone.panelstate;
-/**
- * Panel and QS expansion callbacks.
- */
+/** A listener interface to be notified of expansion events for the notification panel. */
public interface PanelExpansionListener {
/**
* Invoked whenever the notification panel expansion changes, at every animation frame.
* This is the main expansion that happens when the user is swiping up to dismiss the
- * lock screen.
+ * lock screen and swiping to pull down the notification shade.
*
- * @param expansion 0 when collapsed, 1 when expanded.
+ * @param fraction 0 when collapsed, 1 when fully expanded.
+ * @param expanded true if the panel should be considered expanded.
* @param tracking {@code true} when the user is actively dragging the panel.
*/
- void onPanelExpansionChanged(float expansion, boolean tracking);
-
- /**
- * Invoked whenever the QS expansion changes, at every animation frame.
- * @param expansion 0 when collapsed, 1 when expanded.
- */
- default void onQsExpansionChanged(float expansion) {};
+ void onPanelExpansionChanged(float fraction, boolean expanded, boolean tracking);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt
new file mode 100644
index 000000000000..2c7c8e113fc5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt
@@ -0,0 +1,160 @@
+/*
+ * 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.panelstate
+
+import android.annotation.IntDef
+import android.util.Log
+import androidx.annotation.FloatRange
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+
+/**
+ * A class responsible for managing the notification panel's current state.
+ *
+ * TODO(b/200063118): Make this class the one source of truth for the state of panel expansion.
+ */
+@SysUISingleton
+class PanelExpansionStateManager @Inject constructor() {
+
+ private val expansionListeners = mutableListOf<PanelExpansionListener>()
+ private val stateListeners = mutableListOf<PanelStateListener>()
+
+ @PanelState private var state: Int = STATE_CLOSED
+ @FloatRange(from = 0.0, to = 1.0) private var fraction: Float = 0f
+ private var expanded: Boolean = false
+ private var tracking: Boolean = false
+
+ /**
+ * Adds a listener that will be notified when the panel expansion fraction has changed.
+ *
+ * Listener will also be immediately notified with the current values.
+ */
+ fun addExpansionListener(listener: PanelExpansionListener) {
+ expansionListeners.add(listener)
+ listener.onPanelExpansionChanged(fraction, expanded, tracking)
+ }
+
+ /** Removes an expansion listener. */
+ fun removeExpansionListener(listener: PanelExpansionListener) {
+ expansionListeners.remove(listener)
+ }
+
+ /** Adds a listener that will be notified when the panel state has changed. */
+ fun addStateListener(listener: PanelStateListener) {
+ stateListeners.add(listener)
+ }
+
+ /** Removes a state listener. */
+ fun removeStateListener(listener: PanelStateListener) {
+ stateListeners.remove(listener)
+ }
+
+ /** Returns true if the panel is currently closed and false otherwise. */
+ fun isClosed(): Boolean = state == STATE_CLOSED
+
+ /**
+ * Called when the panel expansion has changed.
+ *
+ * @param fraction the fraction from the expansion in [0, 1]
+ * @param expanded whether the panel is currently expanded; this is independent from the
+ * fraction as the panel also might be expanded if the fraction is 0.
+ * @param tracking whether we're currently tracking the user's gesture.
+ */
+ fun onPanelExpansionChanged(
+ @FloatRange(from = 0.0, to = 1.0) fraction: Float,
+ expanded: Boolean,
+ tracking: Boolean
+ ) {
+ require(!fraction.isNaN()) { "fraction cannot be NaN" }
+ val oldState = state
+
+ this.fraction = fraction
+ this.expanded = expanded
+ this.tracking = tracking
+
+ var fullyClosed = true
+ var fullyOpened = false
+
+ if (expanded) {
+ if (this.state == STATE_CLOSED) {
+ updateStateInternal(STATE_OPENING)
+ }
+ fullyClosed = false
+ fullyOpened = fraction >= 1f
+ }
+
+ if (fullyOpened && !tracking) {
+ updateStateInternal(STATE_OPEN)
+ } else if (fullyClosed && !tracking && this.state != STATE_CLOSED) {
+ updateStateInternal(STATE_CLOSED)
+ }
+
+ debugLog(
+ "panelExpansionChanged:" +
+ "start state=${oldState.stateToString()} " +
+ "end state=${state.stateToString()} " +
+ "f=$fraction " +
+ "expanded=$expanded " +
+ "tracking=$tracking" +
+ "${if (fullyOpened) " fullyOpened" else ""} " +
+ if (fullyClosed) " fullyClosed" else ""
+ )
+
+ expansionListeners.forEach { it.onPanelExpansionChanged(fraction, expanded, tracking) }
+ }
+
+ /** Updates the panel state if necessary. */
+ fun updateState(@PanelState state: Int) {
+ debugLog("update state: ${this.state.stateToString()} -> ${state.stateToString()}")
+ if (this.state != state) {
+ updateStateInternal(state)
+ }
+ }
+
+ private fun updateStateInternal(@PanelState state: Int) {
+ debugLog("go state: ${this.state.stateToString()} -> ${state.stateToString()}")
+ this.state = state
+ stateListeners.forEach { it.onPanelStateChanged(state) }
+ }
+
+ private fun debugLog(msg: String) {
+ if (!DEBUG) return
+ Log.v(TAG, msg)
+ }
+}
+
+/** Enum for the current state of the panel. */
+@Retention(AnnotationRetention.SOURCE)
+@IntDef(value = [STATE_CLOSED, STATE_OPENING, STATE_OPEN])
+internal annotation class PanelState
+
+const val STATE_CLOSED = 0
+const val STATE_OPENING = 1
+const val STATE_OPEN = 2
+
+@PanelState
+private fun Int.stateToString(): String {
+ return when (this) {
+ STATE_CLOSED -> "CLOSED"
+ STATE_OPENING -> "OPENING"
+ STATE_OPEN -> "OPEN"
+ else -> this.toString()
+ }
+}
+
+private const val DEBUG = false
+private val TAG = PanelExpansionStateManager::class.simpleName
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelStateListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelStateListener.kt
new file mode 100644
index 000000000000..e29959290355
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelStateListener.kt
@@ -0,0 +1,23 @@
+/*
+ * 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.panelstate
+
+/** A listener interface to be notified of state change events for the notification panel. */
+interface PanelStateListener {
+ /** Called when the panel's expansion state has changed. */
+ fun onPanelStateChanged(@PanelState state: Int)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index 1e5251196379..5bd20ff2d090 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -26,7 +26,7 @@ import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.android.systemui.R;
-import com.android.systemui.settings.brightness.BrightnessSlider;
+import com.android.systemui.settings.brightness.BrightnessSliderController;
import com.android.systemui.settings.brightness.ToggleSlider;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
@@ -46,8 +46,8 @@ public class BrightnessMirrorController
private final NotificationPanelViewController mNotificationPanel;
private final NotificationShadeDepthController mDepthController;
private final ArraySet<BrightnessMirrorListener> mBrightnessMirrorListeners = new ArraySet<>();
- private final BrightnessSlider.Factory mToggleSliderFactory;
- private BrightnessSlider mToggleSliderController;
+ private final BrightnessSliderController.Factory mToggleSliderFactory;
+ private BrightnessSliderController mToggleSliderController;
private final int[] mInt2Cache = new int[2];
private FrameLayout mBrightnessMirror;
private int mBrightnessMirrorBackgroundPadding;
@@ -56,7 +56,7 @@ public class BrightnessMirrorController
public BrightnessMirrorController(NotificationShadeWindowView statusBarWindow,
NotificationPanelViewController notificationPanelViewController,
NotificationShadeDepthController notificationShadeDepthController,
- BrightnessSlider.Factory factory,
+ BrightnessSliderController.Factory factory,
@NonNull Consumer<Boolean> visibilityCallback) {
mStatusBarWindow = statusBarWindow;
mToggleSliderFactory = factory;
@@ -135,9 +135,10 @@ public class BrightnessMirrorController
reinflate();
}
- private BrightnessSlider setMirrorLayout() {
+ private BrightnessSliderController setMirrorLayout() {
Context context = mBrightnessMirror.getContext();
- BrightnessSlider controller = mToggleSliderFactory.create(context, mBrightnessMirror);
+ BrightnessSliderController controller = mToggleSliderFactory.create(context,
+ mBrightnessMirror);
controller.init();
mBrightnessMirror.addView(controller.getRootView(), ViewGroup.LayoutParams.MATCH_PARENT,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index a8097c4d74b0..e0b0dd36ccd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -38,11 +38,10 @@ import com.android.systemui.R;
import com.android.systemui.statusbar.AlertingNotificationManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
+import com.android.systemui.util.ListenerSet;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashSet;
/**
* A manager which handles heads up notifications which is a special mode where
@@ -52,7 +51,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
private static final String TAG = "HeadsUpManager";
private static final String SETTING_HEADS_UP_SNOOZE_LENGTH_MS = "heads_up_snooze_length_ms";
- protected final HashSet<OnHeadsUpChangedListener> mListeners = new HashSet<>();
+ protected final ListenerSet<OnHeadsUpChangedListener> mListeners = new ListenerSet<>();
protected final Context mContext;
@@ -118,7 +117,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
* Adds an OnHeadUpChangedListener to observe events.
*/
public void addListener(@NonNull OnHeadsUpChangedListener listener) {
- mListeners.add(listener);
+ mListeners.addIfAbsent(listener);
}
/**
@@ -158,7 +157,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
NotificationPeekEvent.NOTIFICATION_PEEK, entry.getSbn().getUid(),
entry.getSbn().getPackageName(), entry.getSbn().getInstanceId());
}
- for (OnHeadsUpChangedListener listener : new ArrayList<>(mListeners)) {
+ for (OnHeadsUpChangedListener listener : mListeners) {
if (isPinned) {
listener.onHeadsUpPinned(entry);
} else {
@@ -178,7 +177,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
entry.setHeadsUp(true);
setEntryPinned((HeadsUpEntry) alertEntry, shouldHeadsUpBecomePinned(entry));
EventLogTags.writeSysuiHeadsUpStatus(entry.getKey(), 1 /* visible */);
- for (OnHeadsUpChangedListener listener : new ArrayList<>(mListeners)) {
+ for (OnHeadsUpChangedListener listener : mListeners) {
listener.onHeadsUpStateChanged(entry, true);
}
}
@@ -189,7 +188,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
entry.setHeadsUp(false);
setEntryPinned((HeadsUpEntry) alertEntry, false /* isPinned */);
EventLogTags.writeSysuiHeadsUpStatus(entry.getKey(), 0 /* visible */);
- for (OnHeadsUpChangedListener listener : new ArrayList<>(mListeners)) {
+ for (OnHeadsUpChangedListener listener : mListeners) {
listener.onHeadsUpStateChanged(entry, false);
}
}
@@ -207,7 +206,7 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
if (mHasPinnedNotification) {
MetricsLogger.count(mContext, "note_peek", 1);
}
- for (OnHeadsUpChangedListener listener : new ArrayList<>(mListeners)) {
+ for (OnHeadsUpChangedListener listener : mListeners) {
listener.onHeadsUpPinnedModeChanged(hasPinnedNotification);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 5d7d4809dd57..aa8d95fdb625 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -108,36 +108,36 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private final SendButtonTextWatcher mTextWatcher;
private final TextView.OnEditorActionListener mEditorActionHandler;
- private final UiEventLogger mUiEventLogger;
- private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
- private final List<OnFocusChangeListener> mEditTextFocusChangeListeners = new ArrayList<>();
- private final List<OnSendRemoteInputListener> mOnSendListeners = new ArrayList<>();
+ private final ArrayList<OnSendRemoteInputListener> mOnSendListeners = new ArrayList<>();
+ private final ArrayList<Consumer<Boolean>> mOnVisibilityChangedListeners = new ArrayList<>();
+ private final ArrayList<OnFocusChangeListener> mEditTextFocusChangeListeners =
+ new ArrayList<>();
+
private RemoteEditText mEditText;
private ImageButton mSendButton;
private GradientDrawable mContentBackground;
private ProgressBar mProgressBar;
- private PendingIntent mPendingIntent;
- private RemoteInput[] mRemoteInputs;
- private RemoteInput mRemoteInput;
- private RemoteInputController mController;
-
- private NotificationEntry mEntry;
-
- private boolean mRemoved;
-
+ private ImageView mDelete;
+ private ImageView mDeleteBg;
+ // TODO(b/193539698): remove reveal param fields, turn them into parameters where needed
private int mRevealCx;
private int mRevealCy;
private int mRevealR;
-
private boolean mColorized;
private int mTint;
-
private boolean mResetting;
- private NotificationViewWrapper mWrapper;
- private Consumer<Boolean> mOnVisibilityChangedListener;
+
+ // TODO(b/193539698): move these to a Controller
+ private RemoteInputController mController;
+ private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
+ private final UiEventLogger mUiEventLogger;
+ private NotificationEntry mEntry;
+ private PendingIntent mPendingIntent;
+ private RemoteInput mRemoteInput;
+ private RemoteInput[] mRemoteInputs;
private NotificationRemoteInputManager.BouncerChecker mBouncerChecker;
- private ImageView mDelete;
- private ImageView mDeleteBg;
+ private boolean mRemoved;
+ private NotificationViewWrapper mWrapper;
/**
* Enum for logged notification remote input UiEvents.
@@ -382,7 +382,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private void sendRemoteInput(Intent intent) {
if (mBouncerChecker != null && mBouncerChecker.showBouncerIfNecessary()) {
mEditText.hideIme();
- for (OnSendRemoteInputListener listener : mOnSendListeners) {
+ for (OnSendRemoteInputListener listener : new ArrayList<>(mOnSendListeners)) {
listener.onSendRequestBounced();
}
return;
@@ -399,7 +399,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mController.remoteInputSent(mEntry);
mEntry.setHasSentReply();
- for (OnSendRemoteInputListener listener : mOnSendListeners) {
+ for (OnSendRemoteInputListener listener : new ArrayList<>(mOnSendListeners)) {
listener.onSendRemoteInput();
}
@@ -760,15 +760,32 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mWrapper = wrapper;
}
- public void setOnVisibilityChangedListener(Consumer<Boolean> visibilityChangedListener) {
- mOnVisibilityChangedListener = visibilityChangedListener;
+ /**
+ * Register a listener to be notified when this view's visibility changes.
+ *
+ * Specifically, the passed {@link Consumer} will receive {@code true} when
+ * {@link #getVisibility()} would return {@link View#VISIBLE}, and {@code false} it would return
+ * any other value.
+ */
+ public void addOnVisibilityChangedListener(Consumer<Boolean> listener) {
+ mOnVisibilityChangedListeners.add(listener);
+ }
+
+ /**
+ * Unregister a listener previously registered via
+ * {@link #addOnVisibilityChangedListener(Consumer)}.
+ */
+ public void removeOnVisibilityChangedListener(Consumer<Boolean> listener) {
+ mOnVisibilityChangedListeners.remove(listener);
}
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
- if (changedView == this && mOnVisibilityChangedListener != null) {
- mOnVisibilityChangedListener.accept(visibility == VISIBLE);
+ if (changedView == this) {
+ for (Consumer<Boolean> listener : new ArrayList<>(mOnVisibilityChangedListeners)) {
+ listener.accept(visibility == VISIBLE);
+ }
// Hide soft-keyboard when the input view became invisible
// (i.e. The notification shade collapsed by pressing the home key)
if (visibility != VISIBLE && !mEditText.isVisibleToUser()
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 92908790770a..b6a96a7e49b9 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
@@ -23,6 +23,7 @@ import com.android.internal.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.connectivity.AccessPointController;
import com.android.systemui.statusbar.connectivity.AccessPointControllerImpl;
import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.connectivity.NetworkControllerImpl;
@@ -135,7 +136,7 @@ public interface StatusBarPolicyModule {
/** */
@Binds
- NetworkController.AccessPointController provideAccessPointController(
+ AccessPointController provideAccessPointController(
AccessPointControllerImpl accessPointControllerImpl);
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
index 9d2dbc12c97d..85a6cd224b5f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.phone;
+package com.android.systemui.statusbar.window;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.view.ViewRootImpl.INSETS_LAYOUT_GENERALIZATION;
@@ -37,13 +37,20 @@ import android.util.Log;
import android.view.Gravity;
import android.view.IWindowManager;
import android.view.Surface;
+import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.R;
+import com.android.systemui.animation.ActivityLaunchAnimator;
+import com.android.systemui.animation.DelegateLaunchAnimatorController;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
+
+import java.util.Optional;
import javax.inject.Inject;
@@ -63,7 +70,9 @@ public class StatusBarWindowController {
private int mBarHeight = -1;
private final State mCurrentState = new State();
- private final ViewGroup mStatusBarView;
+ private final ViewGroup mStatusBarWindowView;
+ // The container in which we should run launch animations started from the status bar and
+ // expanding into the opening window.
private final ViewGroup mLaunchAnimationContainer;
private WindowManager.LayoutParams mLp;
private final WindowManager.LayoutParams mLpChanged;
@@ -71,17 +80,17 @@ public class StatusBarWindowController {
@Inject
public StatusBarWindowController(
Context context,
+ @StatusBarWindowModule.InternalWindowView StatusBarWindowView statusBarWindowView,
WindowManager windowManager,
IWindowManager iWindowManager,
- StatusBarWindowView statusBarWindowView,
StatusBarContentInsetsProvider contentInsetsProvider,
@Main Resources resources) {
mContext = context;
mWindowManager = windowManager;
mIWindowManager = iWindowManager;
mContentInsetsProvider = contentInsetsProvider;
- mStatusBarView = statusBarWindowView;
- mLaunchAnimationContainer = mStatusBarView.findViewById(
+ mStatusBarWindowView = statusBarWindowView;
+ mLaunchAnimationContainer = mStatusBarWindowView.findViewById(
R.id.status_bar_launch_animation_container);
mLpChanged = new WindowManager.LayoutParams();
mResources = resources;
@@ -119,13 +128,63 @@ public class StatusBarWindowController {
// hardware-accelerated.
mLp = getBarLayoutParams(mContext.getDisplay().getRotation());
- mWindowManager.addView(mStatusBarView, mLp);
+ mWindowManager.addView(mStatusBarWindowView, mLp);
mLpChanged.copyFrom(mLp);
mContentInsetsProvider.addCallback(this::calculateStatusBarLocationsForAllRotations);
calculateStatusBarLocationsForAllRotations();
}
+ /** Adds the given view to the status bar window view. */
+ public void addViewToWindow(View view, ViewGroup.LayoutParams layoutParams) {
+ mStatusBarWindowView.addView(view, layoutParams);
+ }
+
+ /** Returns the status bar window's background view. */
+ public View getBackgroundView() {
+ return mStatusBarWindowView.findViewById(R.id.status_bar_container);
+ }
+
+ /** Returns a fragment host manager for the status bar window view. */
+ public FragmentHostManager getFragmentHostManager() {
+ return FragmentHostManager.get(mStatusBarWindowView);
+ }
+
+ /**
+ * Provides an updated animation controller if we're animating a view in the status bar.
+ *
+ * This is needed because we have to make sure that the status bar window matches the full
+ * screen during the animation and that we are expanding the view below the other status bar
+ * text.
+ *
+ * @param rootView the root view of the animation
+ * @param animationController the default animation controller to use
+ * @return If the animation is on a view in the status bar, returns an Optional containing an
+ * updated animation controller that handles status-bar-related animation details. Returns an
+ * empty optional if the animation is *not* on a view in the status bar.
+ */
+ public Optional<ActivityLaunchAnimator.Controller> wrapAnimationControllerIfInStatusBar(
+ View rootView, ActivityLaunchAnimator.Controller animationController) {
+ if (rootView != mStatusBarWindowView) {
+ return Optional.empty();
+ }
+
+ animationController.setLaunchContainer(mLaunchAnimationContainer);
+ return Optional.of(new DelegateLaunchAnimatorController(animationController) {
+ @Override
+ public void onLaunchAnimationStart(boolean isExpandingFullyAbove) {
+ getDelegate().onLaunchAnimationStart(isExpandingFullyAbove);
+ setLaunchAnimationRunning(true);
+ }
+
+ @Override
+ public void onLaunchAnimationEnd(boolean isExpandingFullyAbove) {
+ getDelegate().onLaunchAnimationEnd(isExpandingFullyAbove);
+ setLaunchAnimationRunning(false);
+ }
+ });
+ }
+
private WindowManager.LayoutParams getBarLayoutParams(int rotation) {
WindowManager.LayoutParams lp = getBarLayoutParamsForRotation(rotation);
lp.paramsForRotation = new WindowManager.LayoutParams[4];
@@ -214,21 +273,11 @@ public class StatusBarWindowController {
}
/**
- * Return the container in which we should run launch animations started from the status bar and
- * expanding into the opening window.
- *
- * @see #setLaunchAnimationRunning
- */
- public ViewGroup getLaunchAnimationContainer() {
- return mLaunchAnimationContainer;
- }
-
- /**
* Set whether a launch animation is currently running. If true, this will ensure that the
* window matches its parent height so that the animation is not clipped by the normal status
* bar height.
*/
- public void setLaunchAnimationRunning(boolean isLaunchAnimationRunning) {
+ private void setLaunchAnimationRunning(boolean isLaunchAnimationRunning) {
if (isLaunchAnimationRunning == mCurrentState.mIsLaunchAnimationRunning) {
return;
}
@@ -246,7 +295,7 @@ public class StatusBarWindowController {
applyForceStatusBarVisibleFlag(state);
applyHeight(state);
if (mLp != null && mLp.copyFrom(mLpChanged) != 0) {
- mWindowManager.updateViewLayout(mStatusBarView, mLp);
+ mWindowManager.updateViewLayout(mStatusBarWindowView, mLp);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowModule.kt
new file mode 100644
index 000000000000..874217a67613
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowModule.kt
@@ -0,0 +1,47 @@
+package com.android.systemui.statusbar.window
+
+import android.view.LayoutInflater
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Module
+import dagger.Provides
+import javax.inject.Qualifier
+
+/** Module providing dependencies related to the status bar window. */
+@Module
+abstract class StatusBarWindowModule {
+ /**
+ * Provides a [StatusBarWindowView].
+ *
+ * Only [StatusBarWindowController] should inject the view.
+ */
+ @Module
+ companion object {
+ @JvmStatic
+ @Provides
+ @SysUISingleton
+ @InternalWindowView
+ fun providesStatusBarWindowView(layoutInflater: LayoutInflater): StatusBarWindowView {
+ return layoutInflater.inflate(
+ R.layout.super_status_bar,
+ /* root= */null
+ ) as StatusBarWindowView?
+ ?: throw IllegalStateException(
+ "R.layout.super_status_bar could not be properly inflated"
+ )
+ }
+ }
+
+ /**
+ * We want [StatusBarWindowView] to be provided to [StatusBarWindowController]'s constructor via
+ * dagger so that we can provide a fake window view when testing the controller. However, we wan
+ * want *only* the controller to be able to inject the window view.
+ *
+ * This protected qualifier annotation achieves this. [StatusBarWindowView] can only be injected
+ * if it's annotated with [InternalWindowView], and only classes inside this [statusbar.window]
+ * package can access the annotation.
+ */
+ @Retention(AnnotationRetention.BINARY)
+ @Qualifier
+ protected annotation class InternalWindowView
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowView.java
index 8465889876b4..06cc96e2e0cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowView.java
@@ -14,40 +14,29 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.phone;
+package com.android.systemui.statusbar.window;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.WindowInsets.Type.systemBars;
-import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
-
import android.content.Context;
import android.graphics.Insets;
-import android.graphics.Point;
-import android.graphics.Rect;
import android.util.AttributeSet;
-import android.util.Pair;
-import android.view.Display;
import android.view.DisplayCutout;
-import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowInsets;
import android.widget.FrameLayout;
-import androidx.annotation.NonNull;
-
-import com.android.systemui.util.leak.RotationUtils;
-
/**
* Status bar view.
*/
public class StatusBarWindowView extends FrameLayout {
public static final String TAG = "PhoneStatusBarWindowView";
- public static final boolean DEBUG = StatusBar.DEBUG;
+ public static final boolean DEBUG = false;
private int mLeftInset = 0;
private int mRightInset = 0;
@@ -111,86 +100,4 @@ public class StatusBarWindowView extends FrameLayout {
}
}
}
-
- /**
- * Compute the padding needed for status bar related views, e.g., PhoneStatusBar,
- * QuickStatusBarHeader and KeyguardStatusBarView).
- *
- * @param cutout
- * @param cornerCutoutPadding
- * @param roundedCornerContentPadding
- * @return
- */
- @NonNull
- public static Pair<Integer, Integer> paddingNeededForCutoutAndRoundedCorner(
- DisplayCutout cutout, Pair<Integer, Integer> cornerCutoutPadding,
- int roundedCornerContentPadding) {
- if (cutout == null) {
- return new Pair<>(roundedCornerContentPadding, roundedCornerContentPadding);
- }
-
- // padding needed for corner cutout.
- int leftCornerCutoutPadding = cutout.getSafeInsetLeft();
- int rightCornerCutoutPadding = cutout.getSafeInsetRight();
- if (cornerCutoutPadding != null) {
- leftCornerCutoutPadding = Math.max(leftCornerCutoutPadding, cornerCutoutPadding.first);
- rightCornerCutoutPadding = Math.max(rightCornerCutoutPadding,
- cornerCutoutPadding.second);
- }
-
- return new Pair<>(
- Math.max(leftCornerCutoutPadding, roundedCornerContentPadding),
- Math.max(rightCornerCutoutPadding, roundedCornerContentPadding));
- }
-
-
- /**
- * Compute the corner cutout margins in portrait mode
- */
- public static Pair<Integer, Integer> cornerCutoutMargins(DisplayCutout cutout,
- Display display) {
- return statusBarCornerCutoutMargins(cutout, display, RotationUtils.ROTATION_NONE, 0);
- }
-
- /**
- * Compute the corner cutout margins in the given orientation (exactRotation)
- */
- public static Pair<Integer, Integer> statusBarCornerCutoutMargins(DisplayCutout cutout,
- Display display, int exactRotation, int statusBarHeight) {
- if (cutout == null) {
- return null;
- }
- Point size = new Point();
- display.getRealSize(size);
-
- Rect bounds = new Rect();
- switch (exactRotation) {
- case RotationUtils.ROTATION_LANDSCAPE:
- boundsFromDirection(cutout, Gravity.LEFT, bounds);
- break;
- case RotationUtils.ROTATION_SEASCAPE:
- boundsFromDirection(cutout, Gravity.RIGHT, bounds);
- break;
- case RotationUtils.ROTATION_NONE:
- boundsFromDirection(cutout, Gravity.TOP, bounds);
- break;
- case RotationUtils.ROTATION_UPSIDE_DOWN:
- // we assume the cutout is always on top in portrait mode
- return null;
- }
-
- if (statusBarHeight >= 0 && bounds.top > statusBarHeight) {
- return null;
- }
-
- if (bounds.left <= 0) {
- return new Pair<>(bounds.right, 0);
- }
-
- if (bounds.right >= size.x) {
- return new Pair<>(0, size.x - bounds.left);
- }
-
- return null;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index cd5865f58c85..426bc91a606d 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -259,8 +259,13 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added.");
reevaluateSystemTheme(true /* forceReload */);
} else if (Intent.ACTION_WALLPAPER_CHANGED.equals(intent.getAction())) {
- mAcceptColorEvents = true;
- Log.i(TAG, "Allowing color events again");
+ if (intent.getBooleanExtra(WallpaperManager.EXTRA_FROM_FOREGROUND_APP, false)) {
+ mAcceptColorEvents = true;
+ Log.i(TAG, "Wallpaper changed, allowing color events again");
+ } else {
+ Log.i(TAG, "Wallpaper changed from background app, "
+ + "keep deferring color events. Accepting: " + mAcceptColorEvents);
+ }
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvWMComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvWMComponent.java
index f678513f2ce6..83706156927b 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvWMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvWMComponent.java
@@ -17,8 +17,8 @@
package com.android.systemui.tv;
import com.android.systemui.dagger.WMComponent;
-import com.android.systemui.dagger.WMSingleton;
-import com.android.systemui.wmshell.TvWMShellModule;
+import com.android.wm.shell.dagger.WMSingleton;
+import com.android.wm.shell.dagger.TvWMShellModule;
import dagger.Subcomponent;
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
new file mode 100644
index 000000000000..b53ab210424f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
@@ -0,0 +1,84 @@
+/*
+ * 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.unfold
+
+import com.android.keyguard.KeyguardUnfoldTransition
+import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
+import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.phone.StatusBarMoveFromCenterAnimationController
+import dagger.BindsInstance
+import dagger.Module
+import dagger.Provides
+import dagger.Subcomponent
+import java.util.Optional
+import javax.inject.Named
+import javax.inject.Scope
+
+@Scope
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class SysUIUnfoldScope
+
+/**
+ * Creates an injectable [SysUIUnfoldComponent] that provides objects that have been scoped with
+ * [@SysUIUnfoldScope]. Since [SysUIUnfoldComponent] depends upon:
+ * * [Optional<UnfoldTransitionProgressProvider>]
+ * * [Optional<ScopedUnfoldTransitionProgressProvider>]
+ * * [Optional<NaturalRotationProgressProvider>]
+ * no objects will get constructed if these parameters are empty.
+ */
+@Module(subcomponents = [SysUIUnfoldComponent::class])
+class SysUIUnfoldModule {
+ constructor() {}
+
+ @Provides
+ @SysUISingleton
+ fun provideSysUIUnfoldComponent(
+ provider: Optional<UnfoldTransitionProgressProvider>,
+ rotationProvider: Optional<NaturalRotationUnfoldProgressProvider>,
+ @Named(UNFOLD_STATUS_BAR) scopedProvider: Optional<ScopedUnfoldTransitionProgressProvider>,
+ factory: SysUIUnfoldComponent.Factory
+ ) =
+ provider.flatMap { p1 ->
+ rotationProvider.flatMap { p2 ->
+ scopedProvider.map { p3 -> factory.create(p1, p2, p3) }
+ }
+ }
+}
+
+@SysUIUnfoldScope
+@Subcomponent
+interface SysUIUnfoldComponent {
+
+ @Subcomponent.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance p1: UnfoldTransitionProgressProvider,
+ @BindsInstance p2: NaturalRotationUnfoldProgressProvider,
+ @BindsInstance p3: ScopedUnfoldTransitionProgressProvider
+ ): SysUIUnfoldComponent
+ }
+
+ fun getKeyguardUnfoldTransition(): KeyguardUnfoldTransition
+
+ fun getStatusBarMoveFromCenterAnimationController(): StatusBarMoveFromCenterAnimationController
+
+ fun getUnfoldTransitionWallpaperController(): UnfoldTransitionWallpaperController
+
+ fun getUnfoldLightRevealOverlayAnimation(): UnfoldLightRevealOverlayAnimation
+}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
index f0760d4e2187..51de132108be 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
@@ -31,7 +31,6 @@ import android.view.SurfaceControlViewHost
import android.view.SurfaceSession
import android.view.WindowManager
import android.view.WindowlessWindowManager
-import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.statusbar.LightRevealEffect
@@ -44,7 +43,7 @@ import java.util.concurrent.Executor
import java.util.function.Consumer
import javax.inject.Inject
-@SysUISingleton
+@SysUIUnfoldScope
class UnfoldLightRevealOverlayAnimation @Inject constructor(
private val context: Context,
private val deviceStateManager: DeviceStateManager,
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/ShellUnfoldProgressProvider.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldProgressProvider.kt
index 4a884359d315..bd04ad8385b2 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/ShellUnfoldProgressProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldProgressProvider.kt
@@ -21,7 +21,7 @@ import com.android.wm.shell.unfold.ShellUnfoldProgressProvider
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider.UnfoldListener
import java.util.concurrent.Executor
-class ShellUnfoldProgressProvider(
+class UnfoldProgressProvider(
private val unfoldProgressProvider: UnfoldTransitionProgressProvider
) : ShellUnfoldProgressProvider {
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
index 7e4ec67e6e18..cebc93182f1e 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
@@ -43,21 +43,27 @@ class UnfoldTransitionModule {
fun provideUnfoldTransitionProgressProvider(
context: Context,
config: UnfoldTransitionConfig,
- screenStatusProvider: LifecycleScreenStatusProvider,
+ screenStatusProvider: Lazy<LifecycleScreenStatusProvider>,
deviceStateManager: DeviceStateManager,
sensorManager: SensorManager,
@Main executor: Executor,
@Main handler: Handler
- ): UnfoldTransitionProgressProvider =
- createUnfoldTransitionProgressProvider(
- context,
- config,
- screenStatusProvider,
- deviceStateManager,
- sensorManager,
- handler,
- executor
- )
+ ) =
+ if (config.isEnabled) {
+ Optional.of(
+ createUnfoldTransitionProgressProvider(
+ context,
+ config,
+ screenStatusProvider.get(),
+ deviceStateManager,
+ sensorManager,
+ handler,
+ executor
+ )
+ )
+ } else {
+ Optional.empty()
+ }
@Provides
@Singleton
@@ -69,33 +75,37 @@ class UnfoldTransitionModule {
fun provideNaturalRotationProgressProvider(
context: Context,
windowManager: IWindowManager,
- unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider
- ): NaturalRotationUnfoldProgressProvider =
- NaturalRotationUnfoldProgressProvider(
- context,
- windowManager,
- unfoldTransitionProgressProvider
- )
+ unfoldTransitionProgressProvider: Optional<UnfoldTransitionProgressProvider>
+ ) =
+ unfoldTransitionProgressProvider.map {
+ provider -> NaturalRotationUnfoldProgressProvider(
+ context,
+ windowManager,
+ provider
+ )
+ }
@Provides
@Named(UNFOLD_STATUS_BAR)
@Singleton
fun provideStatusBarScopedTransitionProvider(
- source: NaturalRotationUnfoldProgressProvider
- ): ScopedUnfoldTransitionProgressProvider =
- ScopedUnfoldTransitionProgressProvider(source)
+ source: Optional<NaturalRotationUnfoldProgressProvider>
+ ) =
+ source.map {
+ provider -> ScopedUnfoldTransitionProgressProvider(provider)
+ }
@Provides
@Singleton
fun provideShellProgressProvider(
config: UnfoldTransitionConfig,
- provider: Lazy<UnfoldTransitionProgressProvider>
+ provider: Optional<UnfoldTransitionProgressProvider>
): Optional<ShellUnfoldProgressProvider> =
- if (config.isEnabled) {
- Optional.ofNullable(ShellUnfoldProgressProvider(provider.get()))
+ if (config.isEnabled && provider.isPresent()) {
+ Optional.of(UnfoldProgressProvider(provider.get()))
} else {
Optional.empty()
}
}
-const val UNFOLD_STATUS_BAR = "unfold_status_bar" \ No newline at end of file
+const val UNFOLD_STATUS_BAR = "unfold_status_bar"
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionWallpaperController.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionWallpaperController.kt
index 4f45aafce416..a184315ab75c 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionWallpaperController.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionWallpaperController.kt
@@ -16,12 +16,11 @@
package com.android.systemui.unfold
-import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
import com.android.systemui.util.WallpaperController
import javax.inject.Inject
-@SysUISingleton
+@SysUIUnfoldScope
class UnfoldTransitionWallpaperController @Inject constructor(
private val unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider,
private val wallpaperController: WallpaperController
diff --git a/packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt b/packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt
new file mode 100644
index 000000000000..9f33c271881d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt
@@ -0,0 +1,75 @@
+/*
+ * 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
+
+import android.util.IndentingPrintWriter
+import android.view.View
+import java.io.PrintWriter
+import java.util.function.Consumer
+
+/**
+ * Run some code that will print to an [IndentingPrintWriter] that wraps the given [PrintWriter].
+ *
+ * If the given [PrintWriter] is an [IndentingPrintWriter], the block will be passed that same
+ * instance with [IndentingPrintWriter.increaseIndent] having been called, and calling
+ * [IndentingPrintWriter.decreaseIndent] after completion of the block, so the passed [PrintWriter]
+ * should not be used before the block completes.
+ */
+inline fun PrintWriter.withIndenting(block: (IndentingPrintWriter) -> Unit) {
+ if (this is IndentingPrintWriter) {
+ this.withIncreasedIndent { block(this) }
+ } else {
+ block(IndentingPrintWriter(this))
+ }
+}
+
+/**
+ * Run some code that will print to an [IndentingPrintWriter] that wraps the given [PrintWriter].
+ *
+ * If the given [PrintWriter] is an [IndentingPrintWriter], the block will be passed that same
+ * instance with [IndentingPrintWriter.increaseIndent] having been called, and calling
+ * [IndentingPrintWriter.decreaseIndent] after completion of the block, so the passed [PrintWriter]
+ * should not be used before the block completes.
+ */
+fun PrintWriter.withIndenting(consumer: Consumer<IndentingPrintWriter>) {
+ if (this is IndentingPrintWriter) {
+ this.withIncreasedIndent { consumer.accept(this) }
+ } else {
+ consumer.accept(IndentingPrintWriter(this))
+ }
+}
+
+/**
+ * Run some code inside a block, with [IndentingPrintWriter.increaseIndent] having been called on
+ * the given argument, and calling [IndentingPrintWriter.decreaseIndent] after completion.
+ */
+inline fun IndentingPrintWriter.withIncreasedIndent(block: () -> Unit) {
+ this.increaseIndent()
+ try {
+ block()
+ } finally {
+ this.decreaseIndent()
+ }
+}
+
+/** Return a readable string for the visibility */
+fun visibilityString(@View.Visibility visibility: Int): String = when (visibility) {
+ View.GONE -> "gone"
+ View.VISIBLE -> "visible"
+ View.INVISIBLE -> "invisible"
+ else -> "unknown:$visibility"
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/ListenerSet.kt b/packages/SystemUI/src/com/android/systemui/util/ListenerSet.kt
new file mode 100644
index 000000000000..0f4193e94196
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/ListenerSet.kt
@@ -0,0 +1,47 @@
+/*
+ * 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
+
+import java.util.concurrent.CopyOnWriteArrayList
+
+/**
+ * A collection of listeners, observers, callbacks, etc.
+ *
+ * This container is optimized for infrequent mutation and frequent iteration, with thread safety
+ * and reentrant-safety guarantees as well.
+ */
+class ListenerSet<E> : Iterable<E> {
+ private val listeners: CopyOnWriteArrayList<E> = CopyOnWriteArrayList()
+
+ /**
+ * A thread-safe, reentrant-safe method to add a listener.
+ * Does nothing if the listener is already in the set.
+ */
+ fun addIfAbsent(element: E): Boolean = listeners.addIfAbsent(element)
+
+ /**
+ * A thread-safe, reentrant-safe method to remove a listener.
+ */
+ fun remove(element: E): Boolean = listeners.remove(element)
+
+ /**
+ * Returns an iterator over the listeners currently in the set. Note that to ensure
+ * [ConcurrentModificationException] is never thrown, this iterator will not reflect changes
+ * made to the set after the iterator is constructed.
+ */
+ override fun iterator(): Iterator<E> = listeners.iterator()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagReader.java b/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt
index 1ae8c1f2a712..5b16ae999aa3 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagReader.java
+++ b/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt
@@ -14,27 +14,19 @@
* limitations under the License.
*/
-package com.android.systemui.flags;
+package com.android.systemui.util
+import android.os.Trace
/**
- * Plugin for loading flag values
+ * Run a block within a [Trace] section.
+ * Calls [Trace.beginSection] before and [Trace.endSection] after the passed block.
*/
-public interface FlagReader {
- /** Returns a boolean value for the given flag. */
- default boolean isEnabled(int id, boolean def) {
- return def;
+inline fun <T> traceSection(tag: String, block: () -> T): T {
+ Trace.beginSection(tag)
+ try {
+ return block()
+ } finally {
+ Trace.endSection()
}
-
- /** 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);
- }
-}
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/nullability.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/nullability.kt
index 92c73a412577..f3b7e0d24a6e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/nullability.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/nullability.kt
@@ -16,7 +16,14 @@
package com.android.systemui.util.kotlin
+import java.util.Optional
+
/**
* If [value] is not null, then returns block(value). Otherwise returns null.
*/
inline fun <T : Any, R> transform(value: T?, block: (T) -> R): R? = value?.let(block)
+
+/**
+ * Assists type-checking to unpack a Java Optional into T?
+ */
+inline fun <T> Optional<T>.getOrNull(): T? = orElse(null)
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java
index e639313ac649..5568f64f5084 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java
@@ -17,6 +17,7 @@
package com.android.systemui.util.sensors;
import android.hardware.SensorManager;
+import android.os.Build;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -56,7 +57,7 @@ import javax.inject.Inject;
*/
class ProximitySensorImpl implements ProximitySensor {
private static final String TAG = "ProxSensor";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG) || Build.IS_DEBUGGABLE;
private static final long SECONDARY_PING_INTERVAL_MS = 5000;
ThresholdSensor mPrimaryThresholdSensor;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index e57059894786..cd6a77836304 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -33,7 +33,11 @@ import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.IVolumeController;
+import android.media.MediaRoute2Info;
+import android.media.MediaRouter2Manager;
+import android.media.RoutingSessionInfo;
import android.media.VolumePolicy;
+import android.media.session.MediaController;
import android.media.session.MediaController.PlaybackInfo;
import android.media.session.MediaSession.Token;
import android.net.Uri;
@@ -71,6 +75,7 @@ import com.android.systemui.util.concurrency.ThreadFactory;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@@ -118,6 +123,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
private final Context mContext;
private final Looper mWorkerLooper;
private final PackageManager mPackageManager;
+ private final MediaRouter2Manager mRouter2Manager;
private final WakefulnessLifecycle mWakefulnessLifecycle;
private AudioManager mAudio;
private IAudioService mAudioService;
@@ -179,6 +185,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
mWorkerLooper = theadFactory.buildLooperOnNewThread(
VolumeDialogControllerImpl.class.getSimpleName());
mWorker = new W(mWorkerLooper);
+ mRouter2Manager = MediaRouter2Manager.getInstance(mContext);
mMediaSessionsCallbacksW = new MediaSessionsCallbacks(mContext);
mMediaSessions = createMediaSessions(mContext, mWorkerLooper, mMediaSessionsCallbacksW);
mAudio = audioManager;
@@ -1149,16 +1156,16 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
private final HashMap<Token, Integer> mRemoteStreams = new HashMap<>();
private int mNextStream = DYNAMIC_STREAM_START_INDEX;
- private final boolean mShowRemoteSessions;
+ private final boolean mVolumeAdjustmentForRemoteGroupSessions;
public MediaSessionsCallbacks(Context context) {
- mShowRemoteSessions = context.getResources().getBoolean(
- com.android.internal.R.bool.config_volumeShowRemoteSessions);
+ mVolumeAdjustmentForRemoteGroupSessions = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions);
}
@Override
public void onRemoteUpdate(Token token, String name, PlaybackInfo pi) {
- if (mShowRemoteSessions) {
+ if (showForSession(token)) {
addStream(token, "onRemoteUpdate");
int stream = 0;
@@ -1190,7 +1197,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
@Override
public void onRemoteVolumeChanged(Token token, int flags) {
- if (mShowRemoteSessions) {
+ if (showForSession(token)) {
addStream(token, "onRemoteVolumeChanged");
int stream = 0;
synchronized (mRemoteStreams) {
@@ -1214,7 +1221,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
@Override
public void onRemoteRemoved(Token token) {
- if (mShowRemoteSessions) {
+ if (showForSession(token)) {
int stream = 0;
synchronized (mRemoteStreams) {
if (!mRemoteStreams.containsKey(token)) {
@@ -1233,14 +1240,41 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
}
public void setStreamVolume(int stream, int level) {
- if (mShowRemoteSessions) {
- final Token t = findToken(stream);
- if (t == null) {
- Log.w(TAG, "setStreamVolume: No token found for stream: " + stream);
- return;
+ final Token token = findToken(stream);
+ if (token == null) {
+ Log.w(TAG, "setStreamVolume: No token found for stream: " + stream);
+ return;
+ }
+ if (showForSession(token)) {
+ mMediaSessions.setVolume(token, level);
+ }
+ }
+
+ private boolean showForSession(Token token) {
+ if (mVolumeAdjustmentForRemoteGroupSessions) {
+ return true;
+ }
+ MediaController ctr = new MediaController(mContext, token);
+ String packageName = ctr.getPackageName();
+ List<RoutingSessionInfo> sessions =
+ mRouter2Manager.getRoutingSessions(packageName);
+ boolean foundNonSystemSession = false;
+ boolean isGroup = false;
+ for (RoutingSessionInfo session : sessions) {
+ if (!session.isSystemSession()) {
+ foundNonSystemSession = true;
+ int selectedRouteCount = session.getSelectedRoutes().size();
+ if (selectedRouteCount > 1) {
+ isGroup = true;
+ break;
+ }
}
- mMediaSessions.setVolume(t, level);
}
+ if (!foundNonSystemSession) {
+ Log.d(TAG, "No routing session for " + packageName);
+ return false;
+ }
+ return !isGroup;
}
private Token findToken(int stream) {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt
new file mode 100644
index 000000000000..164f83dda9b7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt
@@ -0,0 +1,149 @@
+/*
+ * 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.keyguard
+
+import android.testing.AndroidTestingRunner
+import android.view.View
+import android.view.ViewGroup
+import androidx.test.filters.SmallTest
+import com.android.keyguard.KeyguardUnfoldTransition.Companion.LEFT
+import com.android.keyguard.KeyguardUnfoldTransition.Companion.RIGHT
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
+import com.android.systemui.util.mockito.capture
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.verify
+
+/**
+ * Translates items away/towards the hinge when the device is opened/closed. This is controlled by
+ * the set of ids, which also dictact which direction to move and when, via a filter fn.
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class KeyguardUnfoldTransitionTest : SysuiTestCase() {
+
+ @Mock
+ private lateinit var progressProvider: NaturalRotationUnfoldProgressProvider
+
+ @Captor
+ private lateinit var progressListenerCaptor: ArgumentCaptor<TransitionProgressListener>
+
+ @Mock
+ private lateinit var parent: ViewGroup
+
+ private lateinit var keyguardUnfoldTransition: KeyguardUnfoldTransition
+ private lateinit var progressListener: TransitionProgressListener
+ private var xTranslationMax = 0f
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+
+ xTranslationMax = context.resources.getDimensionPixelSize(
+ R.dimen.keyguard_unfold_translation_x).toFloat()
+
+ keyguardUnfoldTransition = KeyguardUnfoldTransition(
+ getContext(),
+ progressProvider
+ )
+
+ verify(progressProvider).addCallback(capture(progressListenerCaptor))
+ progressListener = progressListenerCaptor.value
+
+ keyguardUnfoldTransition.setup(parent)
+ keyguardUnfoldTransition.statusViewCentered = false
+ }
+
+ @Test
+ fun onTransition_noMatchingIds() {
+ // GIVEN no views matching any ids
+ // WHEN the transition starts
+ progressListener.onTransitionStarted()
+ progressListener.onTransitionProgress(.1f)
+
+ // THEN nothing... no exceptions
+ }
+
+ @Test
+ fun onTransition_oneMovesLeft() {
+ // GIVEN one view with a matching id
+ val view = View(getContext())
+ `when`(parent.findViewById<View>(R.id.keyguard_status_area)).thenReturn(view)
+
+ moveAndValidate(listOf(view to LEFT))
+ }
+
+ @Test
+ fun onTransition_oneMovesLeftAndOneMovesRightMultipleTimes() {
+ // GIVEN two views with a matching id
+ val leftView = View(getContext())
+ val rightView = View(getContext())
+ `when`(parent.findViewById<View>(R.id.keyguard_status_area)).thenReturn(leftView)
+ `when`(parent.findViewById<View>(R.id.notification_stack_scroller)).thenReturn(rightView)
+
+ moveAndValidate(listOf(leftView to LEFT, rightView to RIGHT))
+ moveAndValidate(listOf(leftView to LEFT, rightView to RIGHT))
+ }
+
+ @Test
+ fun onTransition_centeredViewDoesNotMove() {
+ keyguardUnfoldTransition.statusViewCentered = true
+
+ val view = View(getContext())
+ `when`(parent.findViewById<View>(R.id.lockscreen_clock_view_large)).thenReturn(view)
+
+ moveAndValidate(listOf(view to 0))
+ }
+
+ private fun moveAndValidate(list: List<Pair<View, Int>>) {
+ // Compare values as ints because -0f != 0f
+
+ // WHEN the transition starts
+ progressListener.onTransitionStarted()
+ progressListener.onTransitionProgress(0f)
+
+ list.forEach { (view, direction) ->
+ assertEquals((-xTranslationMax * direction).toInt(), view.getTranslationX().toInt())
+ }
+
+ // WHEN the transition progresses, translation is updated
+ progressListener.onTransitionProgress(.5f)
+ list.forEach { (view, direction) ->
+ assertEquals(
+ (-xTranslationMax / 2f * direction).toInt(),
+ view.getTranslationX().toInt()
+ )
+ }
+
+ // WHEN the transition ends, translation is completed
+ progressListener.onTransitionProgress(1f)
+ progressListener.onTransitionFinished()
+ list.forEach { (view, _) ->
+ assertEquals(0, view.getTranslationX().toInt())
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index e53b450a895e..ff5960bc33ce 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -87,7 +87,6 @@ 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.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -170,8 +169,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Mock
private TelephonyListenerManager mTelephonyListenerManager;
@Mock
- private FeatureFlags mFeatureFlags;
- @Mock
private InteractionJankMonitor mInteractionJankMonitor;
@Mock
private LatencyTracker mLatencyTracker;
@@ -179,6 +176,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
private ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
// Direct executor
private Executor mBackgroundExecutor = Runnable::run;
+ private Executor mMainExecutor = Runnable::run;
private TestableLooper mTestableLooper;
private TestableKeyguardUpdateMonitor mKeyguardUpdateMonitor;
private TestableContext mSpiedContext;
@@ -474,7 +472,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */);
mTestableLooper.processAllMessages();
- verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt());
+ verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(),
+ anyInt());
verify(mFingerprintManager, never()).detectFingerprint(any(), any(), anyInt());
}
@@ -882,6 +881,25 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
}
@Test
+ public void testRegisterAuthControllerCallback() {
+ assertThat(mKeyguardUpdateMonitor.isUdfpsEnrolled()).isFalse();
+
+ // verify AuthController.Callback is added:
+ ArgumentCaptor<AuthController.Callback> captor = ArgumentCaptor.forClass(
+ AuthController.Callback.class);
+ verify(mAuthController).addCallback(captor.capture());
+ AuthController.Callback callback = captor.getValue();
+
+ // WHEN udfps is now enrolled
+ when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(true);
+ callback.onEnrollmentsChanged();
+
+ // THEN isUdfspEnrolled is TRUE
+ assertThat(mKeyguardUpdateMonitor.isUdfpsEnrolled()).isTrue();
+ }
+
+
+ @Test
public void testStartUdfpsServiceBeginsOnKeyguard() {
// GIVEN
// - status bar state is on the keyguard
@@ -1060,9 +1078,9 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
super(context,
TestableLooper.get(KeyguardUpdateMonitorTest.this).getLooper(),
mBroadcastDispatcher, mDumpManager,
- mRingerModeTracker, mBackgroundExecutor,
+ mRingerModeTracker, mBackgroundExecutor, mMainExecutor,
mStatusBarStateController, mLockPatternUtils,
- mAuthController, mTelephonyListenerManager, mFeatureFlags,
+ mAuthController, mTelephonyListenerManager,
mInteractionJankMonitor, mLatencyTracker);
setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
index 5bcf828afe9f..d4c3840356d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
@@ -12,6 +12,7 @@ import android.view.WindowManager
import android.widget.LinearLayout
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.DialogListener.DismissReason
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
@@ -59,13 +60,20 @@ class DialogLaunchAnimatorTest : SysuiTestCase() {
assertEquals(0, dialog.findViewById<ViewGroup>(android.R.id.content).childCount)
assertEquals(1, hostDialogContent.childCount)
+ // The original dialog content is added to another view that is the same size as the
+ // original dialog window.
val hostDialogRoot = hostDialogContent.getChildAt(0) as ViewGroup
assertEquals(1, hostDialogRoot.childCount)
- assertEquals(dialog.contentView, hostDialogRoot.getChildAt(0))
- // If we are dozing, the host dialog window also fades out.
- runOnMainThreadAndWaitForIdleSync { dialogLaunchAnimator.onDozeAmountChanged(0.5f) }
- assertTrue(hostDialog.window!!.decorView.alpha < 1f)
+ val dialogContentParent = hostDialogRoot.getChildAt(0) as ViewGroup
+ assertEquals(1, dialogContentParent.childCount)
+ assertEquals(TestDialog.DIALOG_WIDTH, dialogContentParent.layoutParams.width)
+ assertEquals(TestDialog.DIALOG_HEIGHT, dialogContentParent.layoutParams.height)
+
+ val dialogContent = dialogContentParent.getChildAt(0)
+ assertEquals(dialog.contentView, dialogContent)
+ assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, dialogContent.layoutParams.width)
+ assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, dialogContent.layoutParams.height)
// Hiding/showing/dismissing the dialog should hide/show/dismiss the host dialog given that
// it's a ListenableDialog.
@@ -78,7 +86,14 @@ class DialogLaunchAnimatorTest : SysuiTestCase() {
assertFalse(dialog.isShowing)
assertFalse(dialog.onStopCalled)
- runOnMainThreadAndWaitForIdleSync { dialog.dismiss() }
+ runOnMainThreadAndWaitForIdleSync {
+ // TODO(b/204561691): Remove this call to disableAllCurrentDialogsExitAnimations() and
+ // make sure that the test still pass on git_master/cf_x86_64_phone-userdebug in
+ // Forrest.
+ dialogLaunchAnimator.disableAllCurrentDialogsExitAnimations()
+
+ dialog.dismiss()
+ }
assertFalse(hostDialog.isShowing)
assertFalse(dialog.isShowing)
assertTrue(hostDialog.wasDismissed)
@@ -129,6 +144,11 @@ class DialogLaunchAnimatorTest : SysuiTestCase() {
}
private class TestDialog(context: Context) : Dialog(context), ListenableDialog {
+ companion object {
+ const val DIALOG_WIDTH = 100
+ const val DIALOG_HEIGHT = 200
+ }
+
private val listeners = hashSetOf<DialogListener>()
val contentView = View(context)
var onStartCalled = false
@@ -141,6 +161,7 @@ class DialogLaunchAnimatorTest : SysuiTestCase() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ window.setLayout(DIALOG_WIDTH, DIALOG_HEIGHT)
setContentView(contentView)
}
@@ -164,7 +185,7 @@ class DialogLaunchAnimatorTest : SysuiTestCase() {
override fun dismiss() {
super.dismiss()
- notifyListeners { onDismiss() }
+ notifyListeners { onDismiss(DismissReason.UNKNOWN) }
}
override fun hide() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt
index 5fee7fbf8705..2d510923b942 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt
@@ -16,8 +16,14 @@
package com.android.systemui.biometrics
+import android.animation.Animator
+import android.graphics.Insets
+import android.app.ActivityManager
+import android.app.ActivityTaskManager
+import android.content.ComponentName
import android.graphics.Rect
import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
import android.hardware.biometrics.BiometricOverlayConstants.REASON_UNKNOWN
import android.hardware.biometrics.SensorProperties
import android.hardware.display.DisplayManager
@@ -33,7 +39,9 @@ import android.view.Display
import android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS
import android.view.DisplayInfo
import android.view.LayoutInflater
+import android.view.Surface
import android.view.View
+import android.view.ViewPropertyAnimator
import android.view.WindowInsets
import android.view.WindowManager
import android.view.WindowMetrics
@@ -41,6 +49,7 @@ import androidx.test.filters.SmallTest
import com.airbnb.lottie.LottieAnimationView
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.recents.OverviewProxyService
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import org.junit.Before
@@ -53,9 +62,13 @@ import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.any
+import org.mockito.Mockito.anyFloat
+import org.mockito.Mockito.anyLong
+import org.mockito.Mockito.anyInt
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
@@ -77,10 +90,14 @@ class SidefpsControllerTest : SysuiTestCase() {
@Mock
lateinit var windowManager: WindowManager
@Mock
+ lateinit var activityTaskManager: ActivityTaskManager
+ @Mock
lateinit var sidefpsView: View
@Mock
lateinit var displayManager: DisplayManager
@Mock
+ lateinit var overviewProxyService: OverviewProxyService
+ @Mock
lateinit var handler: Handler
@Captor
lateinit var overlayCaptor: ArgumentCaptor<View>
@@ -91,45 +108,63 @@ class SidefpsControllerTest : SysuiTestCase() {
@Before
fun setup() {
+ context.addMockSystemService(DisplayManager::class.java, displayManager)
+ context.addMockSystemService(WindowManager::class.java, windowManager)
+
`when`(layoutInflater.inflate(R.layout.sidefps_view, null, false)).thenReturn(sidefpsView)
`when`(sidefpsView.findViewById<LottieAnimationView>(eq(R.id.sidefps_animation)))
.thenReturn(mock(LottieAnimationView::class.java))
+ with(mock(ViewPropertyAnimator::class.java)) {
+ `when`(sidefpsView.animate()).thenReturn(this)
+ `when`(alpha(anyFloat())).thenReturn(this)
+ `when`(setStartDelay(anyLong())).thenReturn(this)
+ `when`(setDuration(anyLong())).thenReturn(this)
+ `when`(setListener(any())).thenAnswer {
+ (it.arguments[0] as Animator.AnimatorListener)
+ .onAnimationEnd(mock(Animator::class.java))
+ this
+ }
+ }
`when`(fingerprintManager.sensorPropertiesInternal).thenReturn(
- listOf(
- FingerprintSensorPropertiesInternal(
- SENSOR_ID,
- SensorProperties.STRENGTH_STRONG,
- 5 /* maxEnrollmentsPerUser */,
- listOf() /* componentInfo */,
- FingerprintSensorProperties.TYPE_POWER_BUTTON,
- true /* resetLockoutRequiresHardwareAuthToken */
- )
- )
- )
- `when`(windowManager.defaultDisplay).thenReturn(
- Display(
- DisplayManagerGlobal.getInstance(),
- DISPLAY_ID,
- DisplayInfo(),
- DEFAULT_DISPLAY_ADJUSTMENTS
+ listOf(
+ FingerprintSensorPropertiesInternal(
+ SENSOR_ID,
+ SensorProperties.STRENGTH_STRONG,
+ 5 /* maxEnrollmentsPerUser */,
+ listOf() /* componentInfo */,
+ FingerprintSensorProperties.TYPE_POWER_BUTTON,
+ true /* resetLockoutRequiresHardwareAuthToken */
)
+ )
)
`when`(windowManager.maximumWindowMetrics).thenReturn(
WindowMetrics(Rect(0, 0, 800, 800), WindowInsets.CONSUMED)
)
+ }
+
+ private fun testWithDisplay(initInfo: DisplayInfo.() -> Unit = {}, block: () -> Unit) {
+ val displayInfo = DisplayInfo()
+ displayInfo.initInfo()
+ val dmGlobal = mock(DisplayManagerGlobal::class.java)
+ val display = Display(dmGlobal, DISPLAY_ID, displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS)
+ `when`(dmGlobal.getDisplayInfo(eq(DISPLAY_ID))).thenReturn(displayInfo)
+ `when`(windowManager.defaultDisplay).thenReturn(display)
sideFpsController = SidefpsController(
- mContext, layoutInflater, fingerprintManager, windowManager, executor,
- displayManager, handler
+ context.createDisplayContext(display), layoutInflater, fingerprintManager,
+ windowManager, activityTaskManager, overviewProxyService, displayManager, executor,
+ handler
)
overlayController = ArgumentCaptor.forClass(ISidefpsController::class.java).apply {
verify(fingerprintManager).setSidefpsController(capture())
}.value
+
+ block()
}
@Test
- fun testSubscribesToOrientationChangesWhenShowingOverlay() {
+ fun testSubscribesToOrientationChangesWhenShowingOverlay() = testWithDisplay {
overlayController.show(SENSOR_ID, REASON_UNKNOWN)
executor.runAllReady()
@@ -141,7 +176,7 @@ class SidefpsControllerTest : SysuiTestCase() {
}
@Test
- fun testShowsAndHides() {
+ fun testShowsAndHides() = testWithDisplay {
overlayController.show(SENSOR_ID, REASON_UNKNOWN)
executor.runAllReady()
@@ -156,7 +191,7 @@ class SidefpsControllerTest : SysuiTestCase() {
}
@Test
- fun testShowsOnce() {
+ fun testShowsOnce() = testWithDisplay {
repeat(5) {
overlayController.show(SENSOR_ID, REASON_UNKNOWN)
executor.runAllReady()
@@ -167,7 +202,7 @@ class SidefpsControllerTest : SysuiTestCase() {
}
@Test
- fun testHidesOnce() {
+ fun testHidesOnce() = testWithDisplay {
overlayController.show(SENSOR_ID, REASON_UNKNOWN)
executor.runAllReady()
@@ -181,10 +216,80 @@ class SidefpsControllerTest : SysuiTestCase() {
}
@Test
- fun testIgnoredForKeyguard() {
- overlayController.show(SENSOR_ID, REASON_AUTH_KEYGUARD)
+ fun testIgnoredForKeyguard() = testWithDisplay {
+ testIgnoredFor(REASON_AUTH_KEYGUARD)
+ }
+
+ @Test
+ fun testShowsForMostSettings() = testWithDisplay {
+ `when`(activityTaskManager.getTasks(anyInt())).thenReturn(listOf(fpEnrollTask()))
+ testIgnoredFor(REASON_AUTH_SETTINGS, ignored = false)
+ }
+
+ @Test
+ fun testIgnoredForVerySpecificSettings() = testWithDisplay {
+ `when`(activityTaskManager.getTasks(anyInt())).thenReturn(listOf(fpSettingsTask()))
+ testIgnoredFor(REASON_AUTH_SETTINGS)
+ }
+
+ private fun testIgnoredFor(reason: Int, ignored: Boolean = true) {
+ overlayController.show(SENSOR_ID, reason)
executor.runAllReady()
- verify(windowManager, never()).addView(any(), any())
+ verify(windowManager, if (ignored) never() else times(1)).addView(any(), any())
+ }
+
+ @Test
+ fun showsWithTaskbar() = testWithDisplay({ rotation = Surface.ROTATION_0 }) {
+ hidesWithTaskbar(visible = true)
+ }
+
+ @Test
+ fun showsWithTaskbar90() = testWithDisplay({ rotation = Surface.ROTATION_90 }) {
+ hidesWithTaskbar(visible = true)
+ }
+
+ @Test
+ fun showsWithTaskbar180() = testWithDisplay({ rotation = Surface.ROTATION_180 }) {
+ hidesWithTaskbar(visible = true)
+ }
+
+ @Test
+ fun showsWithTaskbarCollapsedDown() = testWithDisplay({ rotation = Surface.ROTATION_270 }) {
+ `when`(windowManager.currentWindowMetrics).thenReturn(
+ WindowMetrics(Rect(0, 0, 800, 800), insetsForSmallNavbar())
+ )
+ hidesWithTaskbar(visible = true)
+ }
+
+ @Test
+ fun hidesWithTaskbarDown() = testWithDisplay({ rotation = Surface.ROTATION_270 }) {
+ `when`(windowManager.currentWindowMetrics).thenReturn(
+ WindowMetrics(Rect(0, 0, 800, 800), insetsForLargeNavbar())
+ )
+ hidesWithTaskbar(visible = false)
}
+
+ private fun hidesWithTaskbar(visible: Boolean) {
+ overlayController.show(SENSOR_ID, REASON_UNKNOWN)
+ executor.runAllReady()
+
+ sideFpsController.overviewProxyListener.onTaskbarStatusUpdated(true, false)
+ executor.runAllReady()
+
+ verify(windowManager).addView(any(), any())
+ verify(windowManager, never()).removeView(any())
+ verify(sidefpsView).visibility = if (visible) View.VISIBLE else View.GONE
+ }
+}
+
+private fun insetsForSmallNavbar() = insetsWithBottom(60)
+private fun insetsForLargeNavbar() = insetsWithBottom(100)
+private fun insetsWithBottom(bottom: Int) = WindowInsets.Builder()
+ .setInsets(WindowInsets.Type.navigationBars(), Insets.of(0, 0, 0, bottom))
+ .build()
+private fun fpEnrollTask() = settingsTask(".biometrics.fingerprint.FingerprintEnrollEnrolling")
+private fun fpSettingsTask() = settingsTask(".biometrics.fingerprint.FingerprintSettings")
+private fun settingsTask(cls: String) = ActivityManager.RunningTaskInfo().apply {
+ topActivity = ComponentName.createRelative("com.android.settings", cls)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index deabda35aeae..d90eb73a1595 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -66,6 +66,7 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.Execution;
@@ -219,7 +220,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
mWindowManager,
mStatusBarStateController,
mFgExecutor,
- Optional.of(mStatusBar),
+ new PanelExpansionStateManager(),
mStatusBarKeyguardViewManager,
mDumpManager,
mKeyguardUpdateMonitor,
@@ -404,15 +405,75 @@ public class UdfpsControllerTest extends SysuiTestCase {
}
@Test
- public void showUdfpsOverlay_addsViewToWindow() throws RemoteException {
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ public void showUdfpsOverlay_addsViewToWindow_bp() throws RemoteException {
+ showUdfpsOverlay_addsViewToWindow(BiometricOverlayConstants.REASON_AUTH_BP);
+ }
+
+ @Test
+ public void showUdfpsOverlay_addsViewToWindow_keyguard() throws RemoteException {
+ showUdfpsOverlay_addsViewToWindow(BiometricOverlayConstants.REASON_AUTH_KEYGUARD);
+ }
+
+ @Test
+ public void showUdfpsOverlay_addsViewToWindow_settings() throws RemoteException {
+ showUdfpsOverlay_addsViewToWindow(BiometricOverlayConstants.REASON_AUTH_SETTINGS);
+ }
+
+ @Test
+ public void showUdfpsOverlay_addsViewToWindow_enroll_locate() throws RemoteException {
+ showUdfpsOverlay_addsViewToWindow(BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR);
+ }
+
+ @Test
+ public void showUdfpsOverlay_addsViewToWindow_enroll() throws RemoteException {
+ showUdfpsOverlay_addsViewToWindow(BiometricOverlayConstants.REASON_ENROLL_ENROLLING);
+ }
+
+ @Test
+ public void showUdfpsOverlay_addsViewToWindow_other() throws RemoteException {
+ showUdfpsOverlay_addsViewToWindow(BiometricOverlayConstants.REASON_AUTH_OTHER);
+ }
+
+ private void showUdfpsOverlay_addsViewToWindow(
+ @BiometricOverlayConstants.ShowReason int reason) throws RemoteException {
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID, reason,
+ mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mWindowManager).addView(eq(mUdfpsView), any());
}
@Test
- public void hideUdfpsOverlay_removesViewFromWindow() throws RemoteException {
+ public void hideUdfpsOverlay_removesViewFromWindow_bp() throws RemoteException {
+ hideUdfpsOverlay_removesViewFromWindow(BiometricOverlayConstants.REASON_AUTH_BP);
+ }
+
+ @Test
+ public void hideUdfpsOverlay_removesViewFromWindow_keyguard() throws RemoteException {
+ hideUdfpsOverlay_removesViewFromWindow(BiometricOverlayConstants.REASON_AUTH_KEYGUARD);
+ }
+
+ @Test
+ public void hideUdfpsOverlay_removesViewFromWindow_settings() throws RemoteException {
+ hideUdfpsOverlay_removesViewFromWindow(BiometricOverlayConstants.REASON_AUTH_SETTINGS);
+ }
+
+ @Test
+ public void hideUdfpsOverlay_removesViewFromWindow_enroll_locate() throws RemoteException {
+ hideUdfpsOverlay_removesViewFromWindow(BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR);
+ }
+
+ @Test
+ public void hideUdfpsOverlay_removesViewFromWindow_enroll() throws RemoteException {
+ hideUdfpsOverlay_removesViewFromWindow(BiometricOverlayConstants.REASON_ENROLL_ENROLLING);
+ }
+
+ @Test
+ public void hideUdfpsOverlay_removesViewFromWindow_other() throws RemoteException {
+ hideUdfpsOverlay_removesViewFromWindow(BiometricOverlayConstants.REASON_AUTH_OTHER);
+ }
+
+ private void hideUdfpsOverlay_removesViewFromWindow(
+ @BiometricOverlayConstants.ShowReason int reason) throws RemoteException {
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index 2821f3d21606..0e86964147d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -41,9 +41,10 @@ import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -57,7 +58,6 @@ import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.Optional;
import java.util.List;
@SmallTest
@@ -72,7 +72,7 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
@Mock
private StatusBarStateController mStatusBarStateController;
@Mock
- private StatusBar mStatusBar;
+ private PanelExpansionStateManager mPanelExpansionStateManager;
@Mock
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock
@@ -101,8 +101,8 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
@Captor private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerCaptor;
private StatusBarStateController.StateListener mStatusBarStateListener;
- @Captor private ArgumentCaptor<StatusBar.ExpansionChangedListener> mExpansionListenerCaptor;
- private List<StatusBar.ExpansionChangedListener> mExpansionListeners;
+ @Captor private ArgumentCaptor<PanelExpansionListener> mExpansionListenerCaptor;
+ private List<PanelExpansionListener> mExpansionListeners;
@Captor private ArgumentCaptor<StatusBarKeyguardViewManager.AlternateAuthInterceptor>
mAltAuthInterceptorCaptor;
@@ -121,7 +121,7 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
mController = new UdfpsKeyguardViewController(
mView,
mStatusBarStateController,
- Optional.of(mStatusBar),
+ mPanelExpansionStateManager,
mStatusBarKeyguardViewManager,
mKeyguardUpdateMonitor,
mDumpManager,
@@ -170,8 +170,8 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
mController.onViewDetached();
verify(mStatusBarStateController).removeCallback(mStatusBarStateListener);
- for (StatusBar.ExpansionChangedListener listener : mExpansionListeners) {
- verify(mStatusBar).removeExpansionChangedListener(listener);
+ for (PanelExpansionListener listener : mExpansionListeners) {
+ verify(mPanelExpansionStateManager).removeExpansionListener(listener);
}
verify(mKeyguardStateController).removeCallback(mKeyguardStateControllerCallback);
}
@@ -434,16 +434,16 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
}
private void captureExpansionListeners() {
- verify(mStatusBar, times(2))
- .addExpansionChangedListener(mExpansionListenerCaptor.capture());
+ verify(mPanelExpansionStateManager, times(2))
+ .addExpansionListener(mExpansionListenerCaptor.capture());
// first (index=0) is from super class, UdfpsAnimationViewController.
// second (index=1) is from UdfpsKeyguardViewController
mExpansionListeners = mExpansionListenerCaptor.getAllValues();
}
- private void updateStatusBarExpansion(float expansion, boolean expanded) {
- for (StatusBar.ExpansionChangedListener listener : mExpansionListeners) {
- listener.onExpansionChanged(expansion, expanded);
+ private void updateStatusBarExpansion(float fraction, boolean expanded) {
+ for (PanelExpansionListener listener : mExpansionListeners) {
+ listener.onPanelExpansionChanged(fraction, expanded, /* tracking= */ false);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt
index ee1cc7b1ab71..890b9aec69bf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt
@@ -154,6 +154,28 @@ class ControlsRequestReceiverTest : SysuiTestCase() {
assertNull(wrapper.intent)
}
+ @Test
+ fun testClassCastExceptionComponentName_noCrash() {
+ val badIntent = Intent(ControlsProviderService.ACTION_ADD_CONTROL).apply {
+ putExtra(Intent.EXTRA_COMPONENT_NAME, Intent())
+ putExtra(ControlsProviderService.EXTRA_CONTROL, control)
+ }
+ receiver.onReceive(wrapper, badIntent)
+
+ assertNull(wrapper.intent)
+ }
+
+ @Test
+ fun testClassCastExceptionControl_noCrash() {
+ val badIntent = Intent(ControlsProviderService.ACTION_ADD_CONTROL).apply {
+ putExtra(Intent.EXTRA_COMPONENT_NAME, componentName)
+ putExtra(ControlsProviderService.EXTRA_CONTROL, Intent())
+ }
+ receiver.onReceive(wrapper, badIntent)
+
+ assertNull(wrapper.intent)
+ }
+
class MyWrapper(context: Context) : ContextWrapper(context) {
var intent: Intent? = null
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java
index 172dcda5321f..634763866d02 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java
@@ -18,23 +18,56 @@ package com.android.systemui.flags;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.content.Context;
+
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.util.settings.SecureSettings;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * NOTE: This test is for the version of FeatureFlagManager in src-release, which should not allow
+ * overriding, and should never return any value other than the one provided as the default.
+ */
@SmallTest
public class FeatureFlagManagerTest extends SysuiTestCase {
FeatureFlagManager mFeatureFlagManager;
+ @Mock private Context mContext;
+ @Mock private DumpManager mDumpManager;
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mFeatureFlagManager = new FeatureFlagManager();
+ mFeatureFlagManager = new FeatureFlagManager(mDumpManager);
+ }
+
+ @After
+ public void onFinished() {
+ // The dump manager should be registered with even for the release version, but that's it.
+ verify(mDumpManager).registerDumpable(anyString(), any());
+ verifyNoMoreInteractions(mDumpManager);
}
@Test
@@ -43,4 +76,31 @@ public class FeatureFlagManagerTest extends SysuiTestCase {
// Again, nothing changes.
assertThat(mFeatureFlagManager.isEnabled(1, false)).isFalse();
}
+
+ @Test
+ public void testDump() {
+ // Even if a flag is set before
+ mFeatureFlagManager.setEnabled(1, true);
+
+ // WHEN the flags have been accessed
+ assertFalse(mFeatureFlagManager.isEnabled(1, false));
+ assertTrue(mFeatureFlagManager.isEnabled(2, true));
+
+ // Even if a flag is set after
+ mFeatureFlagManager.setEnabled(2, false);
+
+ // THEN the dump contains the flags and the default values
+ String dump = dumpToString();
+ assertThat(dump).contains(" sysui_flag_1: false\n");
+ assertThat(dump).contains(" sysui_flag_2: true\n");
+ }
+
+ private String dumpToString() {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ mFeatureFlagManager.dump(mock(FileDescriptor.class), pw, new String[0]);
+ pw.flush();
+ String dump = sw.toString();
+ return dump;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java
deleted file mode 100644
index fc6f3fd1d9c6..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.flags;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.res.Resources;
-
-import androidx.annotation.BoolRes;
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.util.wrapper.BuildInfo;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@SmallTest
-public class FeatureFlagReaderTest extends SysuiTestCase {
- @Mock private Resources mResources;
- @Mock private BuildInfo mBuildInfo;
- @Mock private DumpManager mDumpManager;
- @Mock private SystemPropertiesHelper mSystemPropertiesHelper;
- @Mock private FlagReader mFlagReader;
-
- private FeatureFlagReader mReader;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- when(mSystemPropertiesHelper.getBoolean(anyString(), anyBoolean()))
- .thenAnswer(invocation -> invocation.getArgument(1));
-
- defineFlag(FLAG_RESID_0, false);
- defineFlag(FLAG_RESID_1, true);
-
- initialize(true, true);
- }
-
- 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, mDumpManager, mSystemPropertiesHelper, mFlagReader);
- }
-
- @Test
- public void testCantOverrideIfNotDebuggable() {
- // GIVEN that the build is not debuggable
- initialize(false, true);
-
- // GIVEN that a flag has been overridden to true
- overrideFlag(FLAG_RESID_0, true);
-
- // THEN the flag is still false
- assertFalse(mReader.isEnabled(FLAG_RESID_0));
- }
-
- @Test
- public void testCantOverrideIfNotOverrideable() {
- // GIVEN that flags are not overrideable
- initialize(true, false);
-
- // GIVEN that a flag has been overridden to true
- overrideFlag(FLAG_RESID_0, true);
-
- // THEN the flag is still false
- assertFalse(mReader.isEnabled(FLAG_RESID_0));
- }
-
- @Test
- public void testReadFlags() {
- assertFalse(mReader.isEnabled(FLAG_RESID_0));
- assertTrue(mReader.isEnabled(FLAG_RESID_1));
- }
-
- @Test
- public void testOverrideFlags() {
- // GIVEN that flags are overridden
- overrideFlag(FLAG_RESID_0, true);
- overrideFlag(FLAG_RESID_1, false);
-
- // THEN the reader returns the overridden values
- assertTrue(mReader.isEnabled(FLAG_RESID_0));
- assertFalse(mReader.isEnabled(FLAG_RESID_1));
- }
-
- @Test
- public void testThatFlagReadsAreCached() {
- // GIVEN that a flag is overridden
- overrideFlag(FLAG_RESID_0, true);
-
- // WHEN the flag is queried many times
- mReader.isEnabled(FLAG_RESID_0);
- mReader.isEnabled(FLAG_RESID_0);
- mReader.isEnabled(FLAG_RESID_0);
- mReader.isEnabled(FLAG_RESID_0);
-
- // THEN the underlying resource and override are only queried once
- verify(mResources, times(1)).getBoolean(FLAG_RESID_0);
- verify(mSystemPropertiesHelper, times(1))
- .getBoolean(fakeStorageKey(FLAG_RESID_0), false);
- }
-
- private void defineFlag(int resId, boolean value) {
- when(mResources.getBoolean(resId)).thenReturn(value);
- when(mResources.getResourceEntryName(resId)).thenReturn(fakeStorageKey(resId));
- }
-
- private void overrideFlag(int resId, boolean value) {
- when(mSystemPropertiesHelper.getBoolean(eq(fakeStorageKey(resId)), anyBoolean()))
- .thenReturn(value);
- }
-
- private String fakeStorageKey(@BoolRes int resId) {
- return "persist.systemui.flag_testname_" + resId;
- }
-
- private static final int FLAG_RESID_0 = 47;
- private static final int FLAG_RESID_1 = 48;
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsTest.java b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsTest.java
deleted file mode 100644
index a850f70ae318..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsTest.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.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 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<FlagReader.Listener> pluginListenerCaptor =
- ArgumentCaptor.forClass(FlagReader.Listener.class);
- verify(mFeatureFlagReader).addListener(pluginListenerCaptor.capture());
- FlagReader.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<FlagReader.Listener> pluginListenerCaptor =
- ArgumentCaptor.forClass(FlagReader.Listener.class);
- verify(mFeatureFlagReader).addListener(pluginListenerCaptor.capture());
- FlagReader.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/keyguard/AnimatableClockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/AnimatableClockControllerTest.java
index df112840ed87..5a4bb86dba45 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/AnimatableClockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/AnimatableClockControllerTest.java
@@ -40,7 +40,6 @@ import com.android.settingslib.Utils;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.BatteryController;
import org.junit.After;
@@ -69,8 +68,6 @@ public class AnimatableClockControllerTest extends SysuiTestCase {
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
- private KeyguardBypassController mBypassController;
- @Mock
private Resources mResources;
private MockitoSession mStaticMockSession;
@@ -99,7 +96,6 @@ public class AnimatableClockControllerTest extends SysuiTestCase {
mBroadcastDispatcher,
mBatteryController,
mKeyguardUpdateMonitor,
- mBypassController,
mResources
);
mAnimatableClockController.init();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt
deleted file mode 100644
index cb05a6b21b3a..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.keyguard
-
-import android.animation.ValueAnimator
-import android.content.res.Resources
-import android.hardware.biometrics.BiometricSourceType
-import android.os.Handler
-import android.provider.Settings.System.SCREEN_BRIGHTNESS_FLOAT
-import android.testing.AndroidTestingRunner
-import android.util.TypedValue
-import android.view.View
-import androidx.test.filters.SmallTest
-import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.keyguard.KeyguardUpdateMonitorCallback
-import com.android.systemui.Dumpable
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.dump.DumpManager
-import com.android.systemui.statusbar.NotificationShadeWindowController
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.capture
-import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.settings.GlobalSettings
-import com.android.systemui.util.settings.SystemSettings
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.Captor
-import org.mockito.Mock
-import org.mockito.Mockito.`when`
-import org.mockito.Mockito.anyInt
-import org.mockito.Mockito.anyString
-import org.mockito.Mockito.clearInvocations
-import org.mockito.Mockito.never
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-
-const val INITIAL_BRIGHTNESS = 0.5f
-
-@RunWith(AndroidTestingRunner::class)
-@SmallTest
-class FaceAuthScreenBrightnessControllerTest : SysuiTestCase() {
-
- @Mock
- lateinit var whiteOverlay: View
- @Mock
- lateinit var dumpManager: DumpManager
- @Mock
- lateinit var resources: Resources
- @Mock
- lateinit var mainHandler: Handler
- @Mock
- lateinit var globalSettings: GlobalSettings
- @Mock
- lateinit var systemSettings: SystemSettings
- @Mock
- lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
- @Mock
- lateinit var notificationShadeWindowController: NotificationShadeWindowController
- @Mock
- lateinit var animator: ValueAnimator
- @Captor
- lateinit var keyguardUpdateCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback>
- lateinit var faceAuthScreenBrightnessController: FaceAuthScreenBrightnessController
-
- @Before
- fun setup() {
- MockitoAnnotations.initMocks(this)
- faceAuthScreenBrightnessController = object : FaceAuthScreenBrightnessController(
- notificationShadeWindowController, keyguardUpdateMonitor, resources, globalSettings,
- systemSettings, mainHandler, dumpManager, true) {
- override fun createAnimator(start: Float, end: Float) = animator
- }
- `when`(systemSettings.getFloat(eq(SCREEN_BRIGHTNESS_FLOAT))).thenReturn(INITIAL_BRIGHTNESS)
- `when`(systemSettings.getFloat(eq(SCREEN_BRIGHTNESS_FLOAT), eq(1f)))
- .thenReturn(INITIAL_BRIGHTNESS)
- faceAuthScreenBrightnessController.attach(whiteOverlay)
- verify(keyguardUpdateMonitor).registerCallback(capture(keyguardUpdateCallback))
- }
-
- @Test
- fun init_registersDumpManager() {
- verify(dumpManager).registerDumpable(anyString(), any(Dumpable::class.java))
- }
-
- @Test
- fun init_registersKeyguardCallback() {
- verify(keyguardUpdateMonitor)
- .registerCallback(any(KeyguardUpdateMonitorCallback::class.java))
- }
-
- @Test
- fun onBiometricRunningChanged_animatesBrightness() {
- clearInvocations(whiteOverlay)
- keyguardUpdateCallback.value
- .onBiometricRunningStateChanged(true, BiometricSourceType.FACE)
- verify(whiteOverlay).visibility = eq(View.VISIBLE)
- verify(animator).start()
- }
-
- @Test
- fun faceAuthWallpaper_whenFaceIsDisabledForUser() {
- faceAuthScreenBrightnessController.useFaceAuthWallpaper = true
- faceAuthScreenBrightnessController.faceAuthWallpaper
- verify(resources, never()).openRawResource(anyInt(), any(TypedValue::class.java))
- }
-
- @Test
- fun faceAuthWallpaper_whenFaceFlagIsDisabled() {
- faceAuthScreenBrightnessController.useFaceAuthWallpaper = true
- faceAuthScreenBrightnessController.faceAuthWallpaper
- verify(resources, never()).openRawResource(anyInt(), any(TypedValue::class.java))
- }
-
- @Test
- fun faceAuthWallpaper_whenFaceIsEnabledForUser() {
- faceAuthScreenBrightnessController.useFaceAuthWallpaper = true
- `when`(keyguardUpdateMonitor.isFaceAuthEnabledForUser(anyInt())).thenReturn(true)
- faceAuthScreenBrightnessController.faceAuthWallpaper
- verify(resources).openRawResource(anyInt(), any(TypedValue::class.java))
- }
-} \ No newline at end of file
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 1bb660e4cced..6d8645e44fb0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -57,17 +57,21 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.unfold.SysUIUnfoldComponent;
import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
-import com.android.systemui.unfold.config.UnfoldTransitionConfig;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.DeviceConfigProxyFake;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
+import java.util.Optional;
+import java.util.function.Function;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatchers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -90,7 +94,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
private @Mock NavigationModeController mNavigationModeController;
private @Mock KeyguardDisplayManager mKeyguardDisplayManager;
private @Mock DozeParameters mDozeParameters;
- private @Mock UnfoldTransitionConfig mUnfoldTransitionConfig;
+ private @Mock Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent;
+ private @Mock Optional<UnfoldLightRevealOverlayAnimation> mUnfoldAnimationOptional;
private @Mock UnfoldLightRevealOverlayAnimation mUnfoldAnimation;
private @Mock SysuiStatusBarStateController mStatusBarStateController;
private @Mock KeyguardStateController mKeyguardStateController;
@@ -110,6 +115,12 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
when(mLockPatternUtils.getDevicePolicyManager()).thenReturn(mDevicePolicyManager);
when(mPowerManager.newWakeLock(anyInt(), any())).thenReturn(mock(WakeLock.class));
+ when(mSysUIUnfoldComponent.map(
+ ArgumentMatchers.<Function<SysUIUnfoldComponent, UnfoldLightRevealOverlayAnimation>>
+ any()))
+ .thenReturn(mUnfoldAnimationOptional);
+ when(mUnfoldAnimationOptional.isPresent()).thenReturn(true);
+ when(mUnfoldAnimationOptional.get()).thenReturn(mUnfoldAnimation);
mViewMediator = new KeyguardViewMediator(
mContext,
@@ -128,8 +139,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
mNavigationModeController,
mKeyguardDisplayManager,
mDozeParameters,
- mUnfoldTransitionConfig,
- () -> mUnfoldAnimation,
+ mSysUIUnfoldComponent,
mStatusBarStateController,
mKeyguardStateController,
() -> mKeyguardUnlockAnimationController,
@@ -161,8 +171,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public void testUnfoldTransitionEnabledDrawnTasksReady_onScreenTurningOn_callsDrawnCallback()
throws RemoteException {
- when(mUnfoldTransitionConfig.isEnabled()).thenReturn(true);
-
mViewMediator.onScreenTurningOn(mKeyguardDrawnCallback);
TestableLooper.get(this).processAllMessages();
onUnfoldOverlayReady();
@@ -175,7 +183,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public void testUnfoldTransitionDisabledDrawnTasksReady_onScreenTurningOn_callsDrawnCallback()
throws RemoteException {
- when(mUnfoldTransitionConfig.isEnabled()).thenReturn(false);
+ when(mUnfoldAnimationOptional.isPresent()).thenReturn(false);
mViewMediator.onScreenTurningOn(mKeyguardDrawnCallback);
TestableLooper.get(this).processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
index 5e73dbcbc95d..e01583e1cb1e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
@@ -32,6 +32,7 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.PointF;
+import android.graphics.Rect;
import android.graphics.drawable.AnimatedStateListDrawable;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.SensorLocationInternal;
@@ -39,10 +40,10 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Vibrator;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.util.DisplayMetrics;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import androidx.test.filters.SmallTest;
@@ -70,6 +71,7 @@ import com.airbnb.lottie.LottieAnimationView;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
@@ -88,7 +90,7 @@ public class LockIconViewControllerTest extends SysuiTestCase {
private @Mock AnimatedStateListDrawable mIconDrawable;
private @Mock Context mContext;
private @Mock Resources mResources;
- private @Mock DisplayMetrics mDisplayMetrics;
+ private @Mock(answer = Answers.RETURNS_DEEP_STUBS) WindowManager mWindowManager;
private @Mock StatusBarStateController mStatusBarStateController;
private @Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private @Mock KeyguardViewController mKeyguardViewController;
@@ -137,7 +139,9 @@ public class LockIconViewControllerTest extends SysuiTestCase {
when(mLockIconView.getContext()).thenReturn(mContext);
when(mLockIconView.findViewById(R.layout.udfps_aod_lock_icon)).thenReturn(mAodFp);
when(mContext.getResources()).thenReturn(mResources);
- when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
+ when(mContext.getSystemService(WindowManager.class)).thenReturn(mWindowManager);
+ Rect windowBounds = new Rect(0, 0, 800, 1200);
+ when(mWindowManager.getCurrentWindowMetrics().getBounds()).thenReturn(windowBounds);
when(mResources.getString(R.string.accessibility_unlock_button)).thenReturn(UNLOCKED_LABEL);
when(mResources.getDrawable(anyInt(), any())).thenReturn(mIconDrawable);
@@ -212,6 +216,7 @@ public class LockIconViewControllerTest extends SysuiTestCase {
@Test
public void testUpdateFingerprintLocationOnAuthenticatorsRegistered() {
// GIVEN fp sensor location is not available pre-init
+ when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(false);
when(mAuthController.getFingerprintSensorLocation()).thenReturn(null);
when(mAuthController.getUdfpsProps()).thenReturn(null);
mLockIconViewController.init();
@@ -232,7 +237,7 @@ public class LockIconViewControllerTest extends SysuiTestCase {
}
@Test
- public void testLockIconViewBackgroundEnabledWhenUdfpsIsAvailable() {
+ public void testLockIconViewBackgroundEnabledWhenUdfpsIsSupported() {
// GIVEN Udpfs sensor location is available
setupUdfps();
@@ -247,9 +252,9 @@ public class LockIconViewControllerTest extends SysuiTestCase {
}
@Test
- public void testLockIconViewBackgroundDisabledWhenUdfpsIsUnavailable() {
- // GIVEN Udfps sensor location is not available
- when(mAuthController.getUdfpsSensorLocation()).thenReturn(null);
+ public void testLockIconViewBackgroundDisabledWhenUdfpsIsNotSupported() {
+ // GIVEN Udfps sensor location is not supported
+ when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(false);
mLockIconViewController.init();
captureAttachListener();
@@ -365,6 +370,7 @@ public class LockIconViewControllerTest extends SysuiTestCase {
}
private Pair<Integer, PointF> setupUdfps() {
+ when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(true);
final PointF udfpsLocation = new PointF(50, 75);
final int radius = 33;
final FingerprintSensorPropertiesInternal fpProps =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index bf5a6e4086f3..bbeadf62ae0f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -122,7 +122,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
private lateinit var session: MediaSession
private val device = MediaDeviceData(true, null, DEVICE_NAME)
- private val disabledDevice = MediaDeviceData(false, null, null)
+ private val disabledDevice = MediaDeviceData(false, null, "Disabled Device")
@JvmField @Rule val mockito = MockitoJUnit.rule()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
index ab3b20898b23..7dadbad8025f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
@@ -56,6 +56,7 @@ private const val PACKAGE = "PKG"
private const val SESSION_KEY = "SESSION_KEY"
private const val SESSION_TITLE = "SESSION_TITLE"
private const val DEVICE_NAME = "DEVICE_NAME"
+private const val REMOTE_DEVICE_NAME = "REMOTE_DEVICE_NAME"
private const val USER_ID = 0
private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
@@ -195,8 +196,6 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
// THEN the device should be disabled
val data = captureDeviceData(KEY)
assertThat(data.enabled).isFalse()
- assertThat(data.name).isNull()
- assertThat(data.icon).isNull()
}
@Test
@@ -263,6 +262,20 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
}
@Test
+ fun deviceNameFromMR2RouteInfo() {
+ // GIVEN that MR2Manager returns a valid routing session
+ whenever(route.name).thenReturn(REMOTE_DEVICE_NAME)
+ // WHEN a notification is added
+ manager.onMediaDataLoaded(KEY, null, mediaData)
+ fakeBgExecutor.runAllReady()
+ fakeFgExecutor.runAllReady()
+ // THEN it uses the route name (instead of device name)
+ val data = captureDeviceData(KEY)
+ assertThat(data.enabled).isTrue()
+ assertThat(data.name).isEqualTo(REMOTE_DEVICE_NAME)
+ }
+
+ @Test
fun deviceDisabledWhenMR2ReturnsNullRouteInfo() {
// GIVEN that MR2Manager returns null for routing session
whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null)
@@ -273,8 +286,6 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
// THEN the device is disabled
val data = captureDeviceData(KEY)
assertThat(data.enabled).isFalse()
- assertThat(data.name).isNull()
- assertThat(data.icon).isNull()
}
@Test
@@ -294,8 +305,6 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
// THEN the device is disabled
val data = captureDeviceData(KEY)
assertThat(data.enabled).isFalse()
- assertThat(data.name).isNull()
- assertThat(data.icon).isNull()
}
@Test
@@ -315,8 +324,6 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
// THEN the device is disabled
val data = captureDeviceData(KEY)
assertThat(data.enabled).isFalse()
- assertThat(data.name).isNull()
- assertThat(data.icon).isNull()
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index 750600ad1387..52173c13ca6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -212,12 +212,14 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
- assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
- assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(
- mContext.getString(R.string.media_output_dialog_disconnected, TEST_DEVICE_NAME_2));
+ assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mTwoLineTitleText.getText().toString()).isEqualTo(
+ TEST_DEVICE_NAME_2);
+ assertThat(mViewHolder.mSubTitleText.getText().toString()).isEqualTo(
+ mContext.getString(R.string.media_output_dialog_disconnected));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
index bc86ef98c6fe..8cd7d94d8952 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
@@ -22,6 +22,7 @@ import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
+import com.android.internal.graphics.cam.Cam;
import com.android.systemui.SysuiTestCase;
import org.junit.Assert;
@@ -90,4 +91,13 @@ public class ColorSchemeTest extends SysuiTestCase {
List<Integer> rankedSeedColors = ColorScheme.getSeedColors(wallpaperColors);
Assert.assertEquals(rankedSeedColors, List.of(0xffaec00a, 0xffbe0000, 0xffcc040f));
}
+
+ @Test
+ public void testTertiaryHueWrapsProperly() {
+ int colorInt = 0xffB3588A; // H350 C50 T50
+ ColorScheme colorScheme = new ColorScheme(colorInt, false /* darkTheme */);
+ int tertiaryMid = colorScheme.getAccent3().get(colorScheme.getAccent3().size() / 2);
+ Cam cam = Cam.fromInt(tertiaryMid);
+ Assert.assertEquals(cam.getHue(), 50.0, 10.0);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java
index a6ff2e8d2e15..85bc634c28b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java
@@ -22,6 +22,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import android.view.Display;
import android.view.View;
import android.view.WindowInsetsController;
@@ -31,6 +32,8 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.SysuiTestableContext;
+import com.android.systemui.shared.rotation.RotationButton;
+import com.android.systemui.shared.rotation.RotationButtonController;
import com.android.systemui.statusbar.policy.RotationLockController;
import org.junit.Before;
@@ -39,6 +42,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
+import java.util.function.Supplier;
+
/** atest NavigationBarRotationContextTest */
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -50,6 +55,8 @@ public class NavigationBarRotationContextTest extends SysuiTestCase {
InstrumentationRegistry.getContext(), getLeakCheck());
private RotationButtonController mRotationButtonController;
private RotationButton mRotationButton;
+ private int mWindowRotation = DEFAULT_ROTATE;
+ private Supplier<Integer> mWindowRotationSupplier = () -> mWindowRotation;
@Before
public void setup() {
@@ -58,7 +65,15 @@ public class NavigationBarRotationContextTest extends SysuiTestCase {
final View view = new View(mContext);
mRotationButton = mock(RotationButton.class);
- mRotationButtonController = new RotationButtonController(mContext, 0, 0);
+ mRotationButtonController = new RotationButtonController(mContext,
+ /* lightIconColor */ 0,
+ /* darkIconColor */ 0,
+ /* iconCcwStart0 */ 0,
+ /* iconCcwStart90 */ 0,
+ /* iconCwStart0 */ 0,
+ /* iconCwStart90 */ 0,
+ mWindowRotationSupplier
+ );
mRotationButtonController.setRotationButton(mRotationButton,
new RotationButton.RotationButtonUpdatesCallback() {
@Override
@@ -77,16 +92,16 @@ public class NavigationBarRotationContextTest extends SysuiTestCase {
@Test
public void testOnInvalidRotationProposal() {
- mRotationButtonController.onRotationProposal(DEFAULT_ROTATE, DEFAULT_ROTATE + 1,
- false /* isValid */);
+ mWindowRotation = DEFAULT_ROTATE + 1;
+ mRotationButtonController.onRotationProposal(DEFAULT_ROTATE, false /* isValid */);
verify(mRotationButtonController, times(1)).setRotateSuggestionButtonState(
false /* visible */);
}
@Test
public void testOnSameRotationProposal() {
- mRotationButtonController.onRotationProposal(DEFAULT_ROTATE, DEFAULT_ROTATE,
- true /* isValid */);
+ mWindowRotation = DEFAULT_ROTATE;
+ mRotationButtonController.onRotationProposal(DEFAULT_ROTATE, true /* isValid */);
verify(mRotationButtonController, times(1)).setRotateSuggestionButtonState(
false /* visible */);
}
@@ -94,17 +109,17 @@ public class NavigationBarRotationContextTest extends SysuiTestCase {
@Test
public void testOnRotationProposalShowButtonShowNav() {
// No navigation bar should not call to set visibility state
- mRotationButtonController.onBehaviorChanged(
+ mRotationButtonController.onBehaviorChanged(Display.DEFAULT_DISPLAY,
WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
mRotationButtonController.onNavigationBarWindowVisibilityChange(false /* showing */);
verify(mRotationButtonController, times(0)).setRotateSuggestionButtonState(
false /* visible */);
verify(mRotationButtonController, times(0)).setRotateSuggestionButtonState(
true /* visible */);
+ mWindowRotation = DEFAULT_ROTATE + 1;
// No navigation bar with rotation change should not call to set visibility state
- mRotationButtonController.onRotationProposal(DEFAULT_ROTATE, DEFAULT_ROTATE + 1,
- true /* isValid */);
+ mRotationButtonController.onRotationProposal(DEFAULT_ROTATE, true /* isValid */);
verify(mRotationButtonController, times(0)).setRotateSuggestionButtonState(
false /* visible */);
verify(mRotationButtonController, times(0)).setRotateSuggestionButtonState(
@@ -124,10 +139,10 @@ public class NavigationBarRotationContextTest extends SysuiTestCase {
false /* visible */);
verify(mRotationButtonController, times(0)).setRotateSuggestionButtonState(
true /* visible */);
+ mWindowRotation = DEFAULT_ROTATE + 1;
// Navigation bar is visible and rotation requested
- mRotationButtonController.onRotationProposal(DEFAULT_ROTATE, DEFAULT_ROTATE + 1,
- true /* isValid */);
+ mRotationButtonController.onRotationProposal(DEFAULT_ROTATE, true /* isValid */);
verify(mRotationButtonController, times(1)).setRotateSuggestionButtonState(
true /* visible */);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt
index 0a2000107053..36e02cb1df06 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt
@@ -4,7 +4,8 @@ import android.view.Gravity
import android.view.Surface
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.navigationbar.gestural.FloatingRotationButtonPositionCalculator.Position
+import com.android.systemui.shared.rotation.FloatingRotationButtonPositionCalculator
+import com.android.systemui.shared.rotation.FloatingRotationButtonPositionCalculator.Position
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
index e54a6ec46b9c..d2bba361b1f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
@@ -1,7 +1,9 @@
package com.android.systemui.qs
-import com.android.systemui.R
import android.os.UserManager
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.ViewUtils
import android.view.LayoutInflater
import android.view.View
import androidx.test.filters.SmallTest
@@ -9,6 +11,7 @@ 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
@@ -19,8 +22,11 @@ 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 com.google.common.truth.Truth.assertThat
+import org.junit.After
import org.junit.Before
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.Mock
@@ -30,6 +36,8 @@ import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
@SmallTest
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner::class)
class FooterActionsControllerTest : LeakCheckedTest() {
@Mock
private lateinit var userManager: UserManager
@@ -53,10 +61,12 @@ class FooterActionsControllerTest : LeakCheckedTest() {
private val metricsLogger: MetricsLogger = FakeMetricsLogger()
private lateinit var view: FooterActionsView
private val falsingManager: FalsingManagerFake = FalsingManagerFake()
+ private lateinit var testableLooper: TestableLooper
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ testableLooper = TestableLooper.get(this)
injectLeakCheckedDependencies(*LeakCheckedTest.ALL_SUPPORTED_CLASSES)
val fakeTunerService = Dependency.get(TunerService::class.java) as FakeTunerService
@@ -69,7 +79,14 @@ class FooterActionsControllerTest : LeakCheckedTest() {
globalActionsDialog, uiEventLogger, showPMLiteButton = true,
buttonsVisibleState = ExpansionState.EXPANDED)
controller.init()
- controller.onViewAttached()
+ ViewUtils.attachView(view)
+ // View looper is the testable looper associated with the test
+ testableLooper.processAllMessages()
+ }
+
+ @After
+ fun tearDown() {
+ ViewUtils.detachView(view)
}
@Test
@@ -90,4 +107,19 @@ class FooterActionsControllerTest : LeakCheckedTest() {
// Verify Settings wasn't launched.
verify<ActivityStarter>(activityStarter, Mockito.never()).startActivity(any(), anyBoolean())
}
+
+ @Test
+ fun testMultiUserSwitchUpdatedWhenExpansionStarts() {
+ // When expansion starts, listening is set to true
+ val multiUserSwitch = view.requireViewById<View>(R.id.multi_user_switch)
+
+ assertThat(multiUserSwitch.visibility).isNotEqualTo(View.VISIBLE)
+
+ whenever(multiUserSwitchController.isMultiUserEnabled).thenReturn(true)
+
+ controller.setListening(true)
+ testableLooper.processAllMessages()
+
+ assertThat(multiUserSwitch.visibility).isEqualTo(View.VISIBLE)
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt
new file mode 100644
index 000000000000..e2c6ff996199
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt
@@ -0,0 +1,57 @@
+/*
+ * 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 androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.log.LogBufferFactory
+import com.android.systemui.log.LogcatEchoTracker
+import com.android.systemui.statusbar.DisableFlagsLogger
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.mockito.Mockito.mock
+import java.io.PrintWriter
+import java.io.StringWriter
+
+@SmallTest
+class QSFragmentDisableFlagsLoggerTest : SysuiTestCase() {
+
+ private val buffer = LogBufferFactory(DumpManager(), mock(LogcatEchoTracker::class.java))
+ .create("buffer", 10)
+ private val disableFlagsLogger = DisableFlagsLogger(
+ listOf(DisableFlagsLogger.DisableFlag(0b001, 'A', 'a')),
+ listOf(DisableFlagsLogger.DisableFlag(0b001, 'B', 'b'))
+ )
+ private val logger = QSFragmentDisableFlagsLogger(buffer, disableFlagsLogger)
+
+ @Test
+ fun logDisableFlagChange_bufferHasStates() {
+ val state = DisableFlagsLogger.DisableState(0, 1)
+
+ logger.logDisableFlagChange(state, state)
+
+ val stringWriter = StringWriter()
+ buffer.dump(PrintWriter(stringWriter), tailLength = 0)
+ val actualString = stringWriter.toString()
+ val expectedLogString = disableFlagsLogger.getDisableFlagsString(
+ old = null, new = state, newAfterLocalModification = state
+ )
+
+ assertThat(actualString).contains(expectedLogString)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index c4bab738cc03..30664ba3c5c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -183,6 +183,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
mQQSMediaHost,
mBypassController,
mQsComponentFactory,
+ mock(QSFragmentDisableFlagsLogger.class),
mFalsingManager,
mock(DumpManager.class));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
index 06a4ae096d44..3242adbcfad8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
@@ -42,7 +42,7 @@ import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.settings.brightness.BrightnessController;
-import com.android.systemui.settings.brightness.BrightnessSlider;
+import com.android.systemui.settings.brightness.BrightnessSliderController;
import com.android.systemui.settings.brightness.ToggleSlider;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.tuner.TunerService;
@@ -88,9 +88,9 @@ public class QSPanelControllerTest extends SysuiTestCase {
@Mock
private BrightnessController mBrightnessController;
@Mock
- private BrightnessSlider.Factory mToggleSliderViewControllerFactory;
+ private BrightnessSliderController.Factory mToggleSliderViewControllerFactory;
@Mock
- private BrightnessSlider mBrightnessSlider;
+ private BrightnessSliderController mBrightnessSliderController;
@Mock
QSTileImpl mQSTile;
@Mock
@@ -120,7 +120,7 @@ public class QSPanelControllerTest extends SysuiTestCase {
when(mQSTileHost.getTiles()).thenReturn(Collections.singleton(mQSTile));
when(mQSTileHost.createTileView(any(), eq(mQSTile), anyBoolean())).thenReturn(mQSTileView);
when(mToggleSliderViewControllerFactory.create(any(), any()))
- .thenReturn(mBrightnessSlider);
+ .thenReturn(mBrightnessSliderController);
when(mBrightnessControllerFactory.create(any(ToggleSlider.class)))
.thenReturn(mBrightnessController);
when(mQSTileRevealControllerFactory.create(any(), any()))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSquishinessControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSquishinessControllerTest.kt
new file mode 100644
index 000000000000..f41d7b127a9e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSquishinessControllerTest.kt
@@ -0,0 +1,57 @@
+package com.android.systemui.qs
+
+import android.testing.AndroidTestingRunner
+import android.view.ViewGroup
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class QSSquishinessControllerTest : SysuiTestCase() {
+
+ @Mock private lateinit var qqsFooterActionsView: FooterActionsView
+ @Mock private lateinit var qqsFooterActionsViewLP: ViewGroup.MarginLayoutParams
+ @Mock private lateinit var qsAnimator: QSAnimator
+ @Mock private lateinit var qsPanelController: QSPanelController
+ @Mock private lateinit var quickQsPanelController: QuickQSPanelController
+ @Mock private lateinit var tileLayout: TileLayout
+ @Mock private lateinit var pagedTileLayout: PagedTileLayout
+
+ @JvmField @Rule val mockitoRule = MockitoJUnit.rule()
+
+ private lateinit var qsSquishinessController: QSSquishinessController
+
+ @Before
+ fun setup() {
+ qsSquishinessController = QSSquishinessController(qqsFooterActionsView, qsAnimator,
+ qsPanelController, quickQsPanelController)
+ `when`(quickQsPanelController.tileLayout).thenReturn(tileLayout)
+ `when`(qsPanelController.tileLayout).thenReturn(pagedTileLayout)
+ `when`(qqsFooterActionsView.layoutParams).thenReturn(qqsFooterActionsViewLP)
+ }
+
+ @Test
+ fun setSquishiness_requestsAnimatorUpdate() {
+ qsSquishinessController.squishiness = 0.5f
+ verify(qsAnimator, never()).requestAnimatorUpdate()
+
+ qsSquishinessController.squishiness = 0f
+ verify(qsAnimator).requestAnimatorUpdate()
+ }
+
+ @Test
+ fun setSquishiness_updatesTiles() {
+ qsSquishinessController.squishiness = 0.5f
+ verify(tileLayout).setSquishinessFraction(0.5f)
+ verify(pagedTileLayout).setSquishinessFraction(0.5f)
+ }
+} \ No newline at end of file
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 92b9f75936b9..f85167e6aa63 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
@@ -34,6 +34,7 @@ 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.phone.StatusBarContentInsetsProvider
import com.android.systemui.statusbar.phone.StatusBarIconController
import com.android.systemui.statusbar.phone.StatusIconContainer
import com.android.systemui.statusbar.policy.Clock
@@ -50,6 +51,7 @@ import org.junit.runner.RunWith
import org.mockito.Answers
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
+import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
@@ -105,6 +107,8 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
private lateinit var context: Context
@Mock
private lateinit var featureFlags: FeatureFlags
+ @Mock
+ private lateinit var insetsProvider: StatusBarContentInsetsProvider
private val qsExpansionPathInterpolator = QSExpansionPathInterpolator()
@@ -148,7 +152,8 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
qsExpansionPathInterpolator,
batteryMeterViewController,
featureFlags,
- variableDateViewControllerFactory
+ variableDateViewControllerFactory,
+ insetsProvider
)
}
@@ -247,7 +252,7 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
controller.init()
val captor = argumentCaptor<List<String>>()
- verify(view).onAttach(any(), any(), capture(captor))
+ verify(view).onAttach(any(), any(), capture(captor), anyBoolean(), any())
assertThat(captor.value).containsExactly(
mContext.getString(com.android.internal.R.string.status_bar_mobile)
@@ -260,7 +265,7 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
controller.init()
val captor = argumentCaptor<List<String>>()
- verify(view).onAttach(any(), any(), capture(captor))
+ verify(view).onAttach(any(), any(), capture(captor), anyBoolean(), any())
assertThat(captor.value).containsExactly(
mContext.getString(com.android.internal.R.string.status_bar_no_calling),
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 8ae7100e2e60..bd794d6813ec 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
@@ -39,8 +39,10 @@ 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.connectivity.IconState;
+import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
import com.android.systemui.statusbar.connectivity.NetworkController;
-import com.android.systemui.statusbar.connectivity.NetworkController.MobileDataIndicators;
+import com.android.systemui.statusbar.connectivity.SignalCallback;
import com.android.systemui.util.CarrierConfigTracker;
import com.android.systemui.utils.leaks.LeakCheckedTest;
import com.android.systemui.utils.os.FakeHandler;
@@ -57,7 +59,7 @@ import org.mockito.MockitoAnnotations;
public class QSCarrierGroupControllerTest extends LeakCheckedTest {
private QSCarrierGroupController mQSCarrierGroupController;
- private NetworkController.SignalCallback mSignalCallback;
+ private SignalCallback mSignalCallback;
private CarrierTextManager.CarrierTextCallback mCallback;
@Mock
private QSCarrierGroup mQSCarrierGroup;
@@ -94,7 +96,7 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest {
when(mNetworkController.hasVoiceCallingFeature()).thenReturn(true);
doAnswer(invocation -> mSignalCallback = invocation.getArgument(0))
.when(mNetworkController)
- .addCallback(any(NetworkController.SignalCallback.class));
+ .addCallback(any(SignalCallback.class));
when(mCarrierTextControllerBuilder.setShowAirplaneMode(anyBoolean()))
.thenReturn(mCarrierTextControllerBuilder);
@@ -230,8 +232,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest {
mSlotIndexResolver.overrideInvalid = true;
MobileDataIndicators indicators = new MobileDataIndicators(
- mock(NetworkController.IconState.class),
- mock(NetworkController.IconState.class),
+ mock(IconState.class),
+ mock(IconState.class),
0, 0, true, true, "", "", "", 0, true, true);
mSignalCallback.setMobileDataIndicators(indicators);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index e3045eb2d63f..e3bbfef354bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -27,7 +27,9 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.Looper;
@@ -143,6 +145,16 @@ public class TileServicesTest extends SysuiTestCase {
}
@Test
+ public void testBadComponentName_doesntCrash() {
+ ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mBroadcastDispatcher).registerReceiver(captor.capture(), any(), any(), eq(
+ UserHandle.ALL));
+ Intent intent = new Intent(TileService.ACTION_REQUEST_LISTENING)
+ .putExtra(Intent.EXTRA_COMPONENT_NAME, "abc");
+ captor.getValue().onReceive(mContext, intent);
+ }
+
+ @Test
public void testRecalculateBindAllowance() {
// Add some fake tiles.
for (int i = 0; i < NUM_FAKES; i++) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
index f0bd06571eb9..5a49337fe640 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
@@ -43,8 +43,10 @@ import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.statusbar.connectivity.IconState;
import com.android.systemui.statusbar.connectivity.NetworkController;
-import com.android.systemui.statusbar.connectivity.NetworkController.WifiIndicators;
+import com.android.systemui.statusbar.connectivity.SignalCallback;
+import com.android.systemui.statusbar.connectivity.WifiIndicators;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastController.CastDevice;
import com.android.systemui.statusbar.policy.HotspotController;
@@ -77,7 +79,7 @@ public class CastTileTest extends SysuiTestCase {
@Mock
private QSTileHost mHost;
@Mock
- NetworkController.SignalCallback mSignalCallback;
+ SignalCallback mSignalCallback;
@Mock
private MetricsLogger mMetricsLogger;
@Mock
@@ -122,8 +124,8 @@ public class CastTileTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
mCastTile.handleSetListening(true);
- ArgumentCaptor<NetworkController.SignalCallback> signalCallbackArgumentCaptor =
- ArgumentCaptor.forClass(NetworkController.SignalCallback.class);
+ ArgumentCaptor<SignalCallback> signalCallbackArgumentCaptor =
+ ArgumentCaptor.forClass(SignalCallback.class);
verify(mNetworkController).observe(any(LifecycleOwner.class),
signalCallbackArgumentCaptor.capture());
mSignalCallback = signalCallbackArgumentCaptor.getValue();
@@ -139,10 +141,9 @@ public class CastTileTest extends SysuiTestCase {
// All these tests for enabled/disabled wifi have hotspot not enabled
@Test
public void testStateUnavailable_wifiDisabled() {
- NetworkController.IconState qsIcon =
- new NetworkController.IconState(false, 0, "");
+ IconState qsIcon = new IconState(false, 0, "");
WifiIndicators indicators = new WifiIndicators(
- false, mock(NetworkController.IconState.class),
+ false, mock(IconState.class),
qsIcon, false,false, "",
false, "");
mSignalCallback.setWifiIndicators(indicators);
@@ -153,10 +154,9 @@ public class CastTileTest extends SysuiTestCase {
@Test
public void testStateUnavailable_wifiNotConnected() {
- NetworkController.IconState qsIcon =
- new NetworkController.IconState(false, 0, "");
+ IconState qsIcon = new IconState(false, 0, "");
WifiIndicators indicators = new WifiIndicators(
- true, mock(NetworkController.IconState.class),
+ true, mock(IconState.class),
qsIcon, false,false, "",
false, "");
mSignalCallback.setWifiIndicators(indicators);
@@ -166,10 +166,9 @@ public class CastTileTest extends SysuiTestCase {
}
private void enableWifiAndProcessMessages() {
- NetworkController.IconState qsIcon =
- new NetworkController.IconState(true, 0, "");
+ IconState qsIcon = new IconState(true, 0, "");
WifiIndicators indicators = new WifiIndicators(
- true, mock(NetworkController.IconState.class),
+ true, mock(IconState.class),
qsIcon, false,false, "",
false, "");
mSignalCallback.setWifiIndicators(indicators);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
index 94af10a485fd..98c7274aeba6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
@@ -52,13 +52,11 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.doNothing
-import org.mockito.Mockito.never
import org.mockito.Mockito.nullable
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
@@ -272,28 +270,7 @@ class DeviceControlsTileTest : SysuiTestCase() {
}
@Test
- fun handleClick_availableAndLocked_activityStarted() {
- verify(controlsListingController).observe(
- any(LifecycleOwner::class.java),
- capture(listingCallbackCaptor)
- )
- `when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
- `when`(keyguardStateController.isUnlocked).thenReturn(false)
-
- listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
- testableLooper.processAllMessages()
-
- tile.click(null /* view */)
- testableLooper.processAllMessages()
-
- // The activity should be started right away and not require a keyguard dismiss.
- verifyZeroInteractions(activityStarter)
- verify(spiedContext).startActivity(intentCaptor.capture())
- assertThat(intentCaptor.value.component?.className).isEqualTo(CONTROLS_ACTIVITY_CLASS_NAME)
- }
-
- @Test
- fun handleClick_availableAndUnlocked_activityStarted() {
+ fun handleClick_available_shownOverLockscreenWhenLocked() {
verify(controlsListingController).observe(
any(LifecycleOwner::class.java),
capture(listingCallbackCaptor)
@@ -307,16 +284,16 @@ class DeviceControlsTileTest : SysuiTestCase() {
tile.click(null /* view */)
testableLooper.processAllMessages()
- verify(activityStarter, never()).postStartActivityDismissingKeyguard(any(), anyInt())
verify(activityStarter).startActivity(
intentCaptor.capture(),
eq(true) /* dismissShade */,
- nullable(ActivityLaunchAnimator.Controller::class.java))
+ nullable(ActivityLaunchAnimator.Controller::class.java),
+ eq(true) /* showOverLockscreenWhenLocked */)
assertThat(intentCaptor.value.component?.className).isEqualTo(CONTROLS_ACTIVITY_CLASS_NAME)
}
@Test
- fun handleClick_availableAfterUnlockAndIsLocked_keyguardDismissRequired() {
+ fun handleClick_availableAfterUnlock_notShownOverLockscreenWhenLocked() {
verify(controlsListingController).observe(
any(LifecycleOwner::class.java),
capture(listingCallbackCaptor)
@@ -331,38 +308,11 @@ class DeviceControlsTileTest : SysuiTestCase() {
tile.click(null /* view */)
testableLooper.processAllMessages()
- verify(activityStarter, never()).startActivity(
- any(),
- anyBoolean() /* dismissShade */,
- nullable(ActivityLaunchAnimator.Controller::class.java))
- verify(activityStarter).postStartActivityDismissingKeyguard(
- intentCaptor.capture(),
- anyInt(),
- nullable(ActivityLaunchAnimator.Controller::class.java))
- assertThat(intentCaptor.value.component?.className).isEqualTo(CONTROLS_ACTIVITY_CLASS_NAME)
- }
-
- @Test
- fun handleClick_availableAfterUnlockAndIsUnlocked_activityStarted() {
- verify(controlsListingController).observe(
- any(LifecycleOwner::class.java),
- capture(listingCallbackCaptor)
- )
- `when`(controlsComponent.getVisibility())
- .thenReturn(ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK)
- `when`(keyguardStateController.isUnlocked).thenReturn(true)
-
- listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
- testableLooper.processAllMessages()
-
- tile.click(null /* view */)
- testableLooper.processAllMessages()
-
- verify(activityStarter, never()).postStartActivityDismissingKeyguard(any(), anyInt())
verify(activityStarter).startActivity(
intentCaptor.capture(),
- eq(true) /* dismissShade */,
- nullable(ActivityLaunchAnimator.Controller::class.java))
+ anyBoolean() /* dismissShade */,
+ nullable(ActivityLaunchAnimator.Controller::class.java),
+ eq(false) /* showOverLockscreenWhenLocked */)
assertThat(intentCaptor.value.component?.className).isEqualTo(CONTROLS_ACTIVITY_CLASS_NAME)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
index 964ce01312bf..e4c5299a0cc5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
@@ -17,9 +17,11 @@
package com.android.systemui.qs.tiles;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -34,6 +36,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -41,10 +44,12 @@ import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.screenrecord.RecordingController;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
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;
@@ -67,6 +72,10 @@ public class ScreenRecordTileTest extends SysuiTestCase {
private ActivityStarter mActivityStarter;
@Mock
private QSLogger mQSLogger;
+ @Mock
+ private KeyguardStateController mKeyguardStateController;
+ @Mock
+ private DialogLaunchAnimator mDialogLaunchAnimator;
private TestableLooper mTestableLooper;
private ScreenRecordTile mTile;
@@ -89,7 +98,9 @@ public class ScreenRecordTileTest extends SysuiTestCase {
mActivityStarter,
mQSLogger,
mController,
- mKeyguardDismissUtil
+ mKeyguardDismissUtil,
+ mKeyguardStateController,
+ mDialogLaunchAnimator
);
mTile.initialize();
@@ -112,7 +123,15 @@ public class ScreenRecordTileTest extends SysuiTestCase {
mTile.handleClick(null /* view */);
mTestableLooper.processAllMessages();
- verify(mController, times(1)).getPromptIntent();
+
+ ArgumentCaptor<Runnable> onStartRecordingClicked = ArgumentCaptor.forClass(Runnable.class);
+ verify(mController).createScreenRecordDialog(any(), onStartRecordingClicked.capture());
+
+ // When starting the recording, we collapse the shade and disable the dialog animation.
+ assertNotNull(onStartRecordingClicked.getValue());
+ onStartRecordingClicked.getValue().run();
+ verify(mDialogLaunchAnimator).disableAllCurrentDialogsExitAnimations();
+ verify(mHost).collapsePanels();
}
// Test that the tile is active and labeled correctly when the controller is starting
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
index fe328395b89f..ca8903bfe009 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
@@ -45,12 +45,13 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.settingslib.wifi.WifiUtils;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.statusbar.connectivity.NetworkController;
-import com.android.systemui.statusbar.connectivity.NetworkController.AccessPointController;
+import com.android.systemui.statusbar.connectivity.AccessPointController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.LocationController;
import com.android.systemui.toast.SystemUIToast;
import com.android.systemui.toast.ToastFactory;
import com.android.systemui.util.CarrierConfigTracker;
@@ -102,7 +103,7 @@ public class InternetDialogControllerTest extends SysuiTestCase {
@Mock
private KeyguardStateController mKeyguardStateController;
@Mock
- private NetworkController.AccessPointController mAccessPointController;
+ private AccessPointController mAccessPointController;
@Mock
private WifiEntry mConnectedEntry;
@Mock
@@ -135,6 +136,10 @@ public class InternetDialogControllerTest extends SysuiTestCase {
private Animator mAnimator;
@Mock
private CarrierConfigTracker mCarrierConfigTracker;
+ @Mock
+ private LocationController mLocationController;
+ @Mock
+ private DialogLaunchAnimator mDialogLaunchAnimator;
private TestableResources mTestableResources;
private MockInternetDialogController mInternetDialogController;
@@ -170,7 +175,8 @@ public class InternetDialogControllerTest extends SysuiTestCase {
mSubscriptionManager, mTelephonyManager, mWifiManager,
mock(ConnectivityManager.class), mHandler, mExecutor, mBroadcastDispatcher,
mock(KeyguardUpdateMonitor.class), mGlobalSettings, mKeyguardStateController,
- mWindowManager, mToastFactory, mWorkerHandler, mCarrierConfigTracker);
+ mWindowManager, mToastFactory, mWorkerHandler, mCarrierConfigTracker,
+ mLocationController, mDialogLaunchAnimator);
mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor,
mInternetDialogController.mOnSubscriptionsChangedListener);
mInternetDialogController.onStart(mInternetDialogCallback, true);
@@ -602,6 +608,30 @@ public class InternetDialogControllerTest extends SysuiTestCase {
verify(mMergedCarrierEntry).setEnabled(false);
}
+ @Test
+ public void isWifiScanEnabled_locationOff_returnFalse() {
+ when(mLocationController.isLocationEnabled()).thenReturn(false);
+ when(mWifiManager.isScanAlwaysAvailable()).thenReturn(false);
+
+ assertThat(mInternetDialogController.isWifiScanEnabled()).isFalse();
+
+ when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true);
+
+ assertThat(mInternetDialogController.isWifiScanEnabled()).isFalse();
+ }
+
+ @Test
+ public void isWifiScanEnabled_locationOn_returnIsScanAlwaysAvailable() {
+ when(mLocationController.isLocationEnabled()).thenReturn(true);
+ when(mWifiManager.isScanAlwaysAvailable()).thenReturn(false);
+
+ assertThat(mInternetDialogController.isWifiScanEnabled()).isFalse();
+
+ when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true);
+
+ assertThat(mInternetDialogController.isWifiScanEnabled()).isTrue();
+ }
+
private String getResourcesString(String name) {
return mContext.getResources().getString(getResourcesId(name));
}
@@ -625,12 +655,14 @@ public class InternetDialogControllerTest extends SysuiTestCase {
KeyguardUpdateMonitor keyguardUpdateMonitor, GlobalSettings globalSettings,
KeyguardStateController keyguardStateController, WindowManager windowManager,
ToastFactory toastFactory, Handler workerHandler,
- CarrierConfigTracker carrierConfigTracker) {
+ CarrierConfigTracker carrierConfigTracker,
+ LocationController locationController,
+ DialogLaunchAnimator dialogLaunchAnimator) {
super(context, uiEventLogger, starter, accessPointController, subscriptionManager,
telephonyManager, wifiManager, connectivityManager, handler, mainExecutor,
broadcastDispatcher, keyguardUpdateMonitor, globalSettings,
keyguardStateController, windowManager, toastFactory, workerHandler,
- carrierConfigTracker);
+ carrierConfigTracker, locationController, dialogLaunchAnimator);
mGlobalSettings = globalSettings;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
index 66889607482f..b6e8979db189 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
@@ -99,7 +99,8 @@ public class InternetDialogTest extends SysuiTestCase {
mInternetDialogController, true, true, true, mock(UiEventLogger.class), mHandler,
mBgExecutor);
mInternetDialog.mAdapter = mInternetAdapter;
- mInternetDialog.onAccessPointsChanged(mWifiEntries, mInternetWifiEntry);
+ mInternetDialog.mConnectedWifiEntry = mInternetWifiEntry;
+ mInternetDialog.mWifiEntriesCount = mWifiEntries.size();
mInternetDialog.show();
mDialogView = mInternetDialog.mDialogView;
@@ -209,7 +210,7 @@ public class InternetDialogTest extends SysuiTestCase {
@Test
public void updateDialog_wifiOnAndNoConnectedWifi_hideConnectedWifi() {
// The precondition WiFi ON is already in setUp()
- mInternetDialog.onAccessPointsChanged(mWifiEntries, null /* connectedEntry*/);
+ mInternetDialog.mConnectedWifiEntry = null;
doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
mInternetDialog.updateDialog(false);
@@ -220,7 +221,7 @@ public class InternetDialogTest extends SysuiTestCase {
@Test
public void updateDialog_wifiOnAndNoWifiList_hideWifiListAndSeeAll() {
// The precondition WiFi ON is already in setUp()
- mInternetDialog.onAccessPointsChanged(null /* wifiEntries */, mInternetWifiEntry);
+ mInternetDialog.mWifiEntriesCount = 0;
mInternetDialog.updateDialog(false);
@@ -282,7 +283,7 @@ public class InternetDialogTest extends SysuiTestCase {
@Test
public void updateDialog_wifiOffAndWifiScanOff_hideWifiScanNotify() {
when(mWifiManager.isWifiEnabled()).thenReturn(false);
- when(mWifiManager.isScanAlwaysAvailable()).thenReturn(false);
+ when(mInternetDialogController.isWifiScanEnabled()).thenReturn(false);
mInternetDialog.updateDialog(false);
@@ -292,7 +293,7 @@ public class InternetDialogTest extends SysuiTestCase {
@Test
public void updateDialog_wifiOffAndWifiScanOnAndDeviceLocked_hideWifiScanNotify() {
when(mWifiManager.isWifiEnabled()).thenReturn(false);
- when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true);
+ when(mInternetDialogController.isWifiScanEnabled()).thenReturn(true);
when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
mInternetDialog.updateDialog(false);
@@ -303,7 +304,7 @@ public class InternetDialogTest extends SysuiTestCase {
@Test
public void updateDialog_wifiOffAndWifiScanOnAndDeviceUnlocked_showWifiScanNotify() {
when(mWifiManager.isWifiEnabled()).thenReturn(false);
- when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true);
+ when(mInternetDialogController.isWifiScanEnabled()).thenReturn(true);
when(mInternetDialogController.isDeviceLocked()).thenReturn(false);
mInternetDialog.updateDialog(false);
@@ -366,7 +367,8 @@ public class InternetDialogTest extends SysuiTestCase {
public void showProgressBar_wifiEnabledWithoutWifiEntries_showProgressBarThenHideSearch() {
Mockito.reset(mHandler);
when(mWifiManager.isWifiEnabled()).thenReturn(true);
- mInternetDialog.onAccessPointsChanged(null /* wifiEntries */, null /* connectedEntry*/);
+ mInternetDialog.mConnectedWifiEntry = null;
+ mInternetDialog.mWifiEntriesCount = 0;
mInternetDialog.showProgressBar();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
index b7cc651dc24b..013e58ed99d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
@@ -32,6 +32,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.settings.UserContextProvider;
import org.junit.Before;
import org.junit.Test;
@@ -52,6 +53,8 @@ public class RecordingControllerTest extends SysuiTestCase {
private RecordingController.RecordingStateChangeCallback mCallback;
@Mock
private BroadcastDispatcher mBroadcastDispatcher;
+ @Mock
+ private UserContextProvider mUserContextProvider;
private RecordingController mController;
@@ -60,7 +63,7 @@ public class RecordingControllerTest extends SysuiTestCase {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mController = new RecordingController(mBroadcastDispatcher);
+ mController = new RecordingController(mBroadcastDispatcher, mUserContextProvider);
mController.addCallback(mCallback);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt
index bceb92894609..2b39354d99e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt
@@ -45,7 +45,7 @@ import org.mockito.Mockito.`when` as whenever
@SmallTest
@RunWith(AndroidTestingRunner::class)
-class BrightnessSliderTest : SysuiTestCase() {
+class BrightnessSliderControllerTest : SysuiTestCase() {
@Mock
private lateinit var brightnessSliderView: BrightnessSliderView
@@ -66,7 +66,7 @@ class BrightnessSliderTest : SysuiTestCase() {
private lateinit var seekBar: SeekBar
private var mFalsingManager: FalsingManagerFake = FalsingManagerFake()
- private lateinit var mController: BrightnessSlider
+ private lateinit var mController: BrightnessSliderController
@Before
fun setUp() {
@@ -75,7 +75,7 @@ class BrightnessSliderTest : SysuiTestCase() {
whenever(mirrorController.toggleSlider).thenReturn(mirror)
whenever(motionEvent.copy()).thenReturn(motionEvent)
- mController = BrightnessSlider(brightnessSliderView, mFalsingManager)
+ mController = BrightnessSliderController(brightnessSliderView, mFalsingManager)
mController.init()
mController.setOnChangedListener(listener)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
index 8e52588e5390..e9676c83c39e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
@@ -27,9 +27,12 @@ import org.junit.Before
import org.junit.Test
import org.mockito.Mock
import org.mockito.Mockito.`when`
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyInt
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.eq
import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -40,12 +43,11 @@ class BlurUtilsTest : SysuiTestCase() {
@Mock lateinit var dumpManager: DumpManager
@Mock lateinit var transaction: SurfaceControl.Transaction
@Mock lateinit var crossWindowBlurListeners: CrossWindowBlurListeners
- lateinit var blurUtils: BlurUtils
+ lateinit var blurUtils: TestableBlurUtils
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- `when`(crossWindowBlurListeners.isCrossWindowBlurEnabled).thenReturn(true)
blurUtils = TestableBlurUtils()
}
@@ -76,6 +78,21 @@ class BlurUtilsTest : SysuiTestCase() {
}
@Test
+ fun testApplyBlur_blurDisabled() {
+ val radius = 10
+ val surfaceControl = mock(SurfaceControl::class.java)
+ val viewRootImpl = mock(ViewRootImpl::class.java)
+ `when`(viewRootImpl.surfaceControl).thenReturn(surfaceControl)
+ `when`(surfaceControl.isValid).thenReturn(true)
+
+ blurUtils.blursEnabled = false
+ blurUtils.applyBlur(viewRootImpl, radius, true /* opaque */)
+ verify(transaction).setOpaque(eq(surfaceControl), eq(true))
+ verify(transaction, never()).setBackgroundBlurRadius(any(), anyInt())
+ verify(transaction).apply()
+ }
+
+ @Test
fun testEarlyWakeUp() {
val radius = 10
val surfaceControl = mock(SurfaceControl::class.java)
@@ -89,9 +106,11 @@ class BlurUtilsTest : SysuiTestCase() {
verify(transaction).setEarlyWakeupEnd()
}
- inner class TestableBlurUtils() : BlurUtils(resources, crossWindowBlurListeners, dumpManager) {
+ inner class TestableBlurUtils : BlurUtils(resources, crossWindowBlurListeners, dumpManager) {
+ var blursEnabled = true
+
override fun supportsBlursOnWindows(): Boolean {
- return true
+ return blursEnabled
}
override fun createTransaction(): SurfaceControl.Transaction {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/DisableFlagsLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/DisableFlagsLoggerTest.kt
index 096efad50615..38ad6b85f8aa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/DisableFlagsLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/DisableFlagsLoggerTest.kt
@@ -86,6 +86,23 @@ class DisableFlagsLoggerTest : SysuiTestCase() {
}
@Test
+ fun getDisableFlagsString_nullOld_onlyNewStateLogged() {
+ val result = disableFlagsLogger.getDisableFlagsString(
+ old = null,
+ new = DisableFlagsLogger.DisableState(
+ 0b001, // abC
+ 0b01, // mN
+ ),
+ )
+
+ assertThat(result).doesNotContain("Old")
+ assertThat(result).contains("New: abC.mN")
+ // We have no state to diff on, so we shouldn't see any diff in parentheses
+ assertThat(result).doesNotContain("(")
+ assertThat(result).doesNotContain(")")
+ }
+
+ @Test
fun getDisableFlagsString_nullLocalModification_localModNotLogged() {
val result = disableFlagsLogger.getDisableFlagsString(
DisableFlagsLogger.DisableState(0, 0),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 01f7fae05f76..8afefde86632 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -701,7 +701,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
// GIVEN fingerprint is also running (not udfps)
when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
- when(mKeyguardUpdateMonitor.isUdfpsAvailable()).thenReturn(false);
+ when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(false);
mController.setVisible(true);
@@ -710,8 +710,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED, faceHelpMsg,
BiometricSourceType.FACE);
- // THEN "try fingerprint" message appears (and not the face help message)
- verifyTransientMessage(mKeyguardTryFingerprintMsg);
+ // THEN no help message appears
+ verify(mRotateTextViewController, never()).showTransient(anyString());
// THEN the face help message is still announced for a11y
verify(mIndicationAreaBottom).announceForAccessibility(eq(faceHelpMsg));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index ea21aa906ab1..23cca727335e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -20,10 +20,10 @@ import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.content.Intent.ACTION_USER_SWITCHED;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_ALERTING;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_MEDIA_CONTROLS;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_PEOPLE;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_ALERTING;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_MEDIA_CONTROLS;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PEOPLE;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index 5944e9c1f391..4ed722470334 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -1,3 +1,18 @@
+/*
+ * 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;
@@ -10,26 +25,25 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
-import android.app.RemoteInputHistoryItem;
import android.content.Context;
-import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
-import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.NotificationRemoteInputManager.RemoteInputActiveExtender;
-import com.android.systemui.statusbar.NotificationRemoteInputManager.RemoteInputHistoryExtender;
-import com.android.systemui.statusbar.NotificationRemoteInputManager.SmartReplyHistoryExtender;
+import com.android.systemui.statusbar.NotificationRemoteInputManager.LegacyRemoteInputLifetimeExtender.RemoteInputActiveExtender;
+import com.android.systemui.statusbar.NotificationRemoteInputManager.LegacyRemoteInputLifetimeExtender.RemoteInputHistoryExtender;
+import com.android.systemui.statusbar.NotificationRemoteInputManager.LegacyRemoteInputLifetimeExtender.SmartReplyHistoryExtender;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -76,13 +90,19 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
private RemoteInputHistoryExtender mRemoteInputHistoryExtender;
private SmartReplyHistoryExtender mSmartReplyHistoryExtender;
private RemoteInputActiveExtender mRemoteInputActiveExtender;
+ private TestableNotificationRemoteInputManager.FakeLegacyRemoteInputLifetimeExtender
+ mLegacyRemoteInputLifetimeExtender;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mRemoteInputManager = new TestableNotificationRemoteInputManager(mContext,
- mLockscreenUserManager, mSmartReplyController, mEntryManager,
+ mock(FeatureFlags.class),
+ mLockscreenUserManager,
+ mSmartReplyController,
+ mEntryManager,
+ mock(RemoteInputNotificationRebuilder.class),
() -> Optional.of(mock(StatusBar.class)),
mStateController,
Handler.createAsync(Looper.myLooper()),
@@ -120,6 +140,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
public void testShouldExtendLifetime_remoteInputActive() {
when(mController.isRemoteInputActive(mEntry)).thenReturn(true);
+ assertTrue(mRemoteInputManager.isRemoteInputActive(mEntry));
assertTrue(mRemoteInputActiveExtender.shouldExtendLifetime(mEntry));
}
@@ -128,6 +149,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY = true;
when(mController.isSpinning(mEntry.getKey())).thenReturn(true);
+ assertTrue(mRemoteInputManager.shouldKeepForRemoteInputHistory(mEntry));
assertTrue(mRemoteInputHistoryExtender.shouldExtendLifetime(mEntry));
}
@@ -136,6 +158,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY = true;
mEntry.lastRemoteInputSent = SystemClock.elapsedRealtime();
+ assertTrue(mRemoteInputManager.shouldKeepForRemoteInputHistory(mEntry));
assertTrue(mRemoteInputHistoryExtender.shouldExtendLifetime(mEntry));
}
@@ -144,6 +167,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY = true;
when(mSmartReplyController.isSendingSmartReply(mEntry.getKey())).thenReturn(true);
+ assertTrue(mRemoteInputManager.shouldKeepForSmartReplyHistory(mEntry));
assertTrue(mSmartReplyHistoryExtender.shouldExtendLifetime(mEntry));
}
@@ -151,124 +175,24 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
public void testNotificationWithRemoteInputActiveIsRemovedOnCollapse() {
mRemoteInputActiveExtender.setShouldManageLifetime(mEntry, true /* shouldManage */);
- assertEquals(mRemoteInputManager.getEntriesKeptForRemoteInputActive(),
+ assertEquals(mLegacyRemoteInputLifetimeExtender.getEntriesKeptForRemoteInputActive(),
Sets.newArraySet(mEntry));
mRemoteInputManager.onPanelCollapsed();
- assertTrue(mRemoteInputManager.getEntriesKeptForRemoteInputActive().isEmpty());
+ assertTrue(
+ mLegacyRemoteInputLifetimeExtender.getEntriesKeptForRemoteInputActive().isEmpty());
}
- @Test
- public void testRebuildWithRemoteInput_noExistingInput_image() {
- Uri uri = mock(Uri.class);
- String mimeType = "image/jpeg";
- String text = "image inserted";
- StatusBarNotification newSbn =
- mRemoteInputManager.rebuildNotificationWithRemoteInputInserted(
- mEntry, text, false, mimeType, uri);
- RemoteInputHistoryItem[] messages = (RemoteInputHistoryItem[]) newSbn.getNotification()
- .extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
- assertEquals(1, messages.length);
- assertEquals(text, messages[0].getText());
- assertEquals(mimeType, messages[0].getMimeType());
- assertEquals(uri, messages[0].getUri());
- }
-
- @Test
- public void testRebuildWithRemoteInput_noExistingInputNoSpinner() {
- StatusBarNotification newSbn =
- mRemoteInputManager.rebuildNotificationWithRemoteInputInserted(
- mEntry, "A Reply", false, null, null);
- RemoteInputHistoryItem[] messages = (RemoteInputHistoryItem[]) newSbn.getNotification()
- .extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
- assertEquals(1, messages.length);
- assertEquals("A Reply", messages[0].getText());
- assertFalse(newSbn.getNotification().extras
- .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false));
- assertTrue(newSbn.getNotification().extras
- .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false));
- }
-
- @Test
- public void testRebuildWithRemoteInput_noExistingInputWithSpinner() {
- StatusBarNotification newSbn =
- mRemoteInputManager.rebuildNotificationWithRemoteInputInserted(
- mEntry, "A Reply", true, null, null);
- RemoteInputHistoryItem[] messages = (RemoteInputHistoryItem[]) newSbn.getNotification()
- .extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
- assertEquals(1, messages.length);
- assertEquals("A Reply", messages[0].getText());
- assertTrue(newSbn.getNotification().extras
- .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false));
- assertTrue(newSbn.getNotification().extras
- .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false));
- }
-
- @Test
- public void testRebuildWithRemoteInput_withExistingInput() {
- // Setup a notification entry with 1 remote input.
- StatusBarNotification newSbn =
- mRemoteInputManager.rebuildNotificationWithRemoteInputInserted(
- mEntry, "A Reply", false, null, null);
- NotificationEntry entry = new NotificationEntryBuilder()
- .setSbn(newSbn)
- .build();
-
- // Try rebuilding to add another reply.
- newSbn = mRemoteInputManager.rebuildNotificationWithRemoteInputInserted(
- entry, "Reply 2", true, null, null);
- RemoteInputHistoryItem[] messages = (RemoteInputHistoryItem[]) newSbn.getNotification()
- .extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
- assertEquals(2, messages.length);
- assertEquals("Reply 2", messages[0].getText());
- assertEquals("A Reply", messages[1].getText());
- }
-
- @Test
- public void testRebuildWithRemoteInput_withExistingInput_image() {
- // Setup a notification entry with 1 remote input.
- Uri uri = mock(Uri.class);
- String mimeType = "image/jpeg";
- String text = "image inserted";
- StatusBarNotification newSbn =
- mRemoteInputManager.rebuildNotificationWithRemoteInputInserted(
- mEntry, text, false, mimeType, uri);
- NotificationEntry entry = new NotificationEntryBuilder()
- .setSbn(newSbn)
- .build();
-
- // Try rebuilding to add another reply.
- newSbn = mRemoteInputManager.rebuildNotificationWithRemoteInputInserted(
- entry, "Reply 2", true, null, null);
- RemoteInputHistoryItem[] messages = (RemoteInputHistoryItem[]) newSbn.getNotification()
- .extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
- assertEquals(2, messages.length);
- assertEquals("Reply 2", messages[0].getText());
- assertEquals(text, messages[1].getText());
- assertEquals(mimeType, messages[1].getMimeType());
- assertEquals(uri, messages[1].getUri());
- }
-
- @Test
- public void testRebuildNotificationForCanceledSmartReplies() {
- // Try rebuilding to remove spinner and hide buttons.
- StatusBarNotification newSbn =
- mRemoteInputManager.rebuildNotificationForCanceledSmartReplies(mEntry);
- assertFalse(newSbn.getNotification().extras
- .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false));
- assertTrue(newSbn.getNotification().extras
- .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false));
- }
-
-
private class TestableNotificationRemoteInputManager extends NotificationRemoteInputManager {
TestableNotificationRemoteInputManager(
Context context,
+ FeatureFlags featureFlags,
NotificationLockscreenUserManager lockscreenUserManager,
SmartReplyController smartReplyController,
NotificationEntryManager notificationEntryManager,
+ RemoteInputNotificationRebuilder rebuilder,
Lazy<Optional<StatusBar>> statusBarOptionalLazy,
StatusBarStateController statusBarStateController,
Handler mainHandler,
@@ -278,9 +202,11 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
DumpManager dumpManager) {
super(
context,
+ featureFlags,
lockscreenUserManager,
smartReplyController,
notificationEntryManager,
+ rebuilder,
statusBarOptionalLazy,
statusBarStateController,
mainHandler,
@@ -297,14 +223,28 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
mRemoteInputController = controller;
}
+ @NonNull
@Override
- protected void addLifetimeExtenders() {
- mRemoteInputActiveExtender = new RemoteInputActiveExtender();
- mRemoteInputHistoryExtender = new RemoteInputHistoryExtender();
- mSmartReplyHistoryExtender = new SmartReplyHistoryExtender();
- mLifetimeExtenders.add(mRemoteInputHistoryExtender);
- mLifetimeExtenders.add(mSmartReplyHistoryExtender);
- mLifetimeExtenders.add(mRemoteInputActiveExtender);
+ protected LegacyRemoteInputLifetimeExtender createLegacyRemoteInputLifetimeExtender(
+ Handler mainHandler,
+ NotificationEntryManager notificationEntryManager,
+ SmartReplyController smartReplyController) {
+ mLegacyRemoteInputLifetimeExtender = new FakeLegacyRemoteInputLifetimeExtender();
+ return mLegacyRemoteInputLifetimeExtender;
}
+
+ class FakeLegacyRemoteInputLifetimeExtender extends LegacyRemoteInputLifetimeExtender {
+
+ @Override
+ protected void addLifetimeExtenders() {
+ mRemoteInputActiveExtender = new RemoteInputActiveExtender();
+ mRemoteInputHistoryExtender = new RemoteInputHistoryExtender();
+ mSmartReplyHistoryExtender = new SmartReplyHistoryExtender();
+ mLifetimeExtenders.add(mRemoteInputHistoryExtender);
+ mLifetimeExtenders.add(mSmartReplyHistoryExtender);
+ mLifetimeExtenders.add(mRemoteInputActiveExtender);
+ }
+ }
+
}
}
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 dbd5168386de..0bce621c3b02 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -119,15 +119,17 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
@Test
fun onPanelExpansionChanged_apliesBlur_ifShade() {
- notificationShadeDepthController.onPanelExpansionChanged(1f /* expansion */,
- false /* tracking */)
+ notificationShadeDepthController.onPanelExpansionChanged(
+ rawFraction = 1f, expanded = true, tracking = false
+ )
verify(shadeAnimation).animateTo(eq(maxBlur), any())
}
@Test
fun onPanelExpansionChanged_animatesBlurIn_ifShade() {
- notificationShadeDepthController.onPanelExpansionChanged(0.01f /* expansion */,
- false /* tracking */)
+ notificationShadeDepthController.onPanelExpansionChanged(
+ rawFraction = 0.01f, expanded = false, tracking = false
+ )
verify(shadeAnimation).animateTo(eq(maxBlur), any())
}
@@ -135,8 +137,9 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
fun onPanelExpansionChanged_animatesBlurOut_ifShade() {
onPanelExpansionChanged_animatesBlurIn_ifShade()
clearInvocations(shadeAnimation)
- notificationShadeDepthController.onPanelExpansionChanged(0f /* expansion */,
- false /* tracking */)
+ notificationShadeDepthController.onPanelExpansionChanged(
+ rawFraction = 0f, expanded = false, tracking = false
+ )
verify(shadeAnimation).animateTo(eq(0), any())
}
@@ -144,16 +147,19 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
fun onPanelExpansionChanged_animatesBlurOut_ifFlick() {
onPanelExpansionChanged_apliesBlur_ifShade()
clearInvocations(shadeAnimation)
- notificationShadeDepthController.onPanelExpansionChanged(1f /* expansion */,
- true /* tracking */)
+ notificationShadeDepthController.onPanelExpansionChanged(
+ rawFraction = 1f, expanded = true, tracking = true
+ )
verify(shadeAnimation, never()).animateTo(anyInt(), any())
- notificationShadeDepthController.onPanelExpansionChanged(0.9f /* expansion */,
- true /* tracking */)
+ notificationShadeDepthController.onPanelExpansionChanged(
+ rawFraction = 0.9f, expanded = true, tracking = true
+ )
verify(shadeAnimation, never()).animateTo(anyInt(), any())
- notificationShadeDepthController.onPanelExpansionChanged(0.8f /* expansion */,
- false /* tracking */)
+ notificationShadeDepthController.onPanelExpansionChanged(
+ rawFraction = 0.8f, expanded = true, tracking = false
+ )
verify(shadeAnimation).animateTo(eq(0), any())
}
@@ -161,24 +167,28 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
fun onPanelExpansionChanged_animatesBlurIn_ifFlickCancelled() {
onPanelExpansionChanged_animatesBlurOut_ifFlick()
clearInvocations(shadeAnimation)
- notificationShadeDepthController.onPanelExpansionChanged(0.6f /* expansion */,
- true /* tracking */)
+ notificationShadeDepthController.onPanelExpansionChanged(
+ rawFraction = 0.6f, expanded = true, tracking = true
+ )
verify(shadeAnimation).animateTo(eq(maxBlur), any())
}
@Test
fun onPanelExpansionChanged_respectsMinPanelPullDownFraction() {
notificationShadeDepthController.panelPullDownMinFraction = 0.5f
- notificationShadeDepthController.onPanelExpansionChanged(0.5f /* expansion */,
- true /* tracking */)
+ notificationShadeDepthController.onPanelExpansionChanged(
+ rawFraction = 0.5f, expanded = true, tracking = true
+ )
assertThat(notificationShadeDepthController.shadeExpansion).isEqualTo(0f)
- notificationShadeDepthController.onPanelExpansionChanged(0.75f /* expansion */,
- true /* tracking */)
+ notificationShadeDepthController.onPanelExpansionChanged(
+ rawFraction = 0.75f, expanded = true, tracking = true
+ )
assertThat(notificationShadeDepthController.shadeExpansion).isEqualTo(0.5f)
- notificationShadeDepthController.onPanelExpansionChanged(1f /* expansion */,
- true /* tracking */)
+ notificationShadeDepthController.onPanelExpansionChanged(
+ rawFraction = 1f, expanded = true, tracking = true
+ )
assertThat(notificationShadeDepthController.shadeExpansion).isEqualTo(1f)
}
@@ -196,7 +206,9 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
fun setQsPanelExpansion_appliesBlur() {
statusBarState = StatusBarState.KEYGUARD
notificationShadeDepthController.qsPanelExpansion = 1f
- notificationShadeDepthController.onPanelExpansionChanged(1f, tracking = false)
+ notificationShadeDepthController.onPanelExpansionChanged(
+ rawFraction = 1f, expanded = true, tracking = false
+ )
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
}
@@ -205,7 +217,9 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
fun setQsPanelExpansion_easing() {
statusBarState = StatusBarState.KEYGUARD
notificationShadeDepthController.qsPanelExpansion = 0.25f
- notificationShadeDepthController.onPanelExpansionChanged(1f, tracking = false)
+ notificationShadeDepthController.onPanelExpansionChanged(
+ rawFraction = 1f, expanded = true, tracking = false
+ )
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(wallpaperController).setNotificationShadeZoom(
eq(ShadeInterpolation.getNotificationScrimAlpha(0.25f)))
@@ -261,7 +275,9 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
@Test
fun updateBlurCallback_setsBlur_whenExpanded() {
- notificationShadeDepthController.onPanelExpansionChanged(1f, false)
+ notificationShadeDepthController.onPanelExpansionChanged(
+ rawFraction = 1f, expanded = true, tracking = false
+ )
`when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
@@ -269,7 +285,9 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
@Test
fun updateBlurCallback_ignoreShadeBlurUntilHidden_overridesZoom() {
- notificationShadeDepthController.onPanelExpansionChanged(1f, false)
+ notificationShadeDepthController.onPanelExpansionChanged(
+ rawFraction = 1f, expanded = true, tracking = false
+ )
`when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
notificationShadeDepthController.blursDisabledForAppLaunch = true
notificationShadeDepthController.updateBlurCallback.doFrame(0)
@@ -300,7 +318,9 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
// Brightness mirror is fully visible
`when`(brightnessSpring.ratio).thenReturn(1f)
// And shade is blurred
- notificationShadeDepthController.onPanelExpansionChanged(1f, false)
+ notificationShadeDepthController.onPanelExpansionChanged(
+ rawFraction = 1f, expanded = true, tracking = false
+ )
`when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
notificationShadeDepthController.updateBlurCallback.doFrame(0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 7fb7b8667a1b..cf58c63e3d26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -36,6 +36,7 @@ import android.widget.LinearLayout;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
import com.android.systemui.statusbar.notification.DynamicChildBindController;
@@ -75,6 +76,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
@Spy private FakeListContainer mListContainer = new FakeListContainer();
// Dependency mocks:
+ @Mock private FeatureFlags mFeatureFlags;
@Mock private NotificationEntryManager mEntryManager;
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@Mock private NotificationGroupManagerLegacy mGroupManager;
@@ -101,10 +103,14 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
when(mVisualStabilityManager.areGroupChangesAllowed()).thenReturn(true);
when(mVisualStabilityManager.isReorderingAllowed()).thenReturn(true);
+ when(mFeatureFlags.isNewNotifPipelineEnabled()).thenReturn(false);
+ when(mFeatureFlags.checkLegacyPipelineEnabled()).thenReturn(true);
+
mHelper = new NotificationTestHelper(mContext, mDependency, TestableLooper.get(this));
mViewHierarchyManager = new NotificationViewHierarchyManager(mContext,
- mHandler, mLockscreenUserManager, mGroupManager, mVisualStabilityManager,
+ mHandler, mFeatureFlags, mLockscreenUserManager, mGroupManager,
+ mVisualStabilityManager,
mock(StatusBarStateControllerImpl.class), mEntryManager,
mock(KeyguardBypassController.class),
Optional.of(mock(Bubbles.class)),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java
new file mode 100644
index 000000000000..ce11d6a62a8c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java
@@ -0,0 +1,174 @@
+/*
+ * 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;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.mock;
+
+import android.app.Notification;
+import android.app.RemoteInputHistoryItem;
+import android.net.Uri;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class RemoteInputNotificationRebuilderTest extends SysuiTestCase {
+ private static final String TEST_PACKAGE_NAME = "test";
+ private static final int TEST_UID = 0;
+ @Mock
+ private ExpandableNotificationRow mRow;
+
+ private RemoteInputNotificationRebuilder mRebuilder;
+ private NotificationEntry mEntry;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mRebuilder = new RemoteInputNotificationRebuilder(mContext);
+ mEntry = new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_NAME)
+ .setOpPkg(TEST_PACKAGE_NAME)
+ .setUid(TEST_UID)
+ .setNotification(new Notification())
+ .setUser(UserHandle.CURRENT)
+ .build();
+ mEntry.setRow(mRow);
+ }
+
+ @Test
+ public void testRebuildWithRemoteInput_noExistingInput_image() {
+ Uri uri = mock(Uri.class);
+ String mimeType = "image/jpeg";
+ String text = "image inserted";
+ StatusBarNotification newSbn =
+ mRebuilder.rebuildWithRemoteInputInserted(
+ mEntry, text, false, mimeType, uri);
+ RemoteInputHistoryItem[] messages = (RemoteInputHistoryItem[]) newSbn.getNotification()
+ .extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
+ assertEquals(1, messages.length);
+ assertEquals(text, messages[0].getText());
+ assertEquals(mimeType, messages[0].getMimeType());
+ assertEquals(uri, messages[0].getUri());
+ }
+
+ @Test
+ public void testRebuildWithRemoteInput_noExistingInputNoSpinner() {
+ StatusBarNotification newSbn =
+ mRebuilder.rebuildWithRemoteInputInserted(
+ mEntry, "A Reply", false, null, null);
+ RemoteInputHistoryItem[] messages = (RemoteInputHistoryItem[]) newSbn.getNotification()
+ .extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
+ assertEquals(1, messages.length);
+ assertEquals("A Reply", messages[0].getText());
+ assertFalse(newSbn.getNotification().extras
+ .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false));
+ assertTrue(newSbn.getNotification().extras
+ .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false));
+ }
+
+ @Test
+ public void testRebuildWithRemoteInput_noExistingInputWithSpinner() {
+ StatusBarNotification newSbn =
+ mRebuilder.rebuildWithRemoteInputInserted(
+ mEntry, "A Reply", true, null, null);
+ RemoteInputHistoryItem[] messages = (RemoteInputHistoryItem[]) newSbn.getNotification()
+ .extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
+ assertEquals(1, messages.length);
+ assertEquals("A Reply", messages[0].getText());
+ assertTrue(newSbn.getNotification().extras
+ .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false));
+ assertTrue(newSbn.getNotification().extras
+ .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false));
+ }
+
+ @Test
+ public void testRebuildWithRemoteInput_withExistingInput() {
+ // Setup a notification entry with 1 remote input.
+ StatusBarNotification newSbn =
+ mRebuilder.rebuildWithRemoteInputInserted(
+ mEntry, "A Reply", false, null, null);
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setSbn(newSbn)
+ .build();
+
+ // Try rebuilding to add another reply.
+ newSbn = mRebuilder.rebuildWithRemoteInputInserted(
+ entry, "Reply 2", true, null, null);
+ RemoteInputHistoryItem[] messages = (RemoteInputHistoryItem[]) newSbn.getNotification()
+ .extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
+ assertEquals(2, messages.length);
+ assertEquals("Reply 2", messages[0].getText());
+ assertEquals("A Reply", messages[1].getText());
+ }
+
+ @Test
+ public void testRebuildWithRemoteInput_withExistingInput_image() {
+ // Setup a notification entry with 1 remote input.
+ Uri uri = mock(Uri.class);
+ String mimeType = "image/jpeg";
+ String text = "image inserted";
+ StatusBarNotification newSbn =
+ mRebuilder.rebuildWithRemoteInputInserted(
+ mEntry, text, false, mimeType, uri);
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setSbn(newSbn)
+ .build();
+
+ // Try rebuilding to add another reply.
+ newSbn = mRebuilder.rebuildWithRemoteInputInserted(
+ entry, "Reply 2", true, null, null);
+ RemoteInputHistoryItem[] messages = (RemoteInputHistoryItem[]) newSbn.getNotification()
+ .extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
+ assertEquals(2, messages.length);
+ assertEquals("Reply 2", messages[0].getText());
+ assertEquals(text, messages[1].getText());
+ assertEquals(mimeType, messages[1].getMimeType());
+ assertEquals(uri, messages[1].getUri());
+ }
+
+ @Test
+ public void testRebuildNotificationForCanceledSmartReplies() {
+ // Try rebuilding to remove spinner and hide buttons.
+ StatusBarNotification newSbn =
+ mRebuilder.rebuildForCanceledSmartReplies(mEntry);
+ assertFalse(newSbn.getNotification().extras
+ .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false));
+ assertTrue(newSbn.getNotification().extras
+ .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index 837d71f8d74f..99c965a9e57f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -39,6 +39,7 @@ import com.android.internal.statusbar.IStatusBarService;
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.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -86,14 +87,20 @@ public class SmartReplyControllerTest extends SysuiTestCase {
mDependency.injectTestDependency(NotificationEntryManager.class,
mNotificationEntryManager);
- mSmartReplyController = new SmartReplyController(mNotificationEntryManager,
- mIStatusBarService, mClickNotifier);
+ mSmartReplyController = new SmartReplyController(
+ mock(DumpManager.class),
+ mNotificationEntryManager,
+ mIStatusBarService,
+ mClickNotifier);
mDependency.injectTestDependency(SmartReplyController.class,
mSmartReplyController);
mRemoteInputManager = new NotificationRemoteInputManager(mContext,
+ mock(FeatureFlags.class),
mock(NotificationLockscreenUserManager.class), mSmartReplyController,
- mNotificationEntryManager, () -> Optional.of(mock(StatusBar.class)),
+ mNotificationEntryManager,
+ new RemoteInputNotificationRebuilder(mContext),
+ () -> Optional.of(mock(StatusBar.class)),
mStatusBarStateController,
Handler.createAsync(Looper.myLooper()),
mRemoteInputUriController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
index 7896a26badbe..c57b64db2c5c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
@@ -56,9 +56,9 @@ class AccessPointControllerImplTest : SysuiTestCase() {
@Mock
private lateinit var wifiPickerTracker: WifiPickerTracker
@Mock
- private lateinit var callback: NetworkController.AccessPointController.AccessPointCallback
+ private lateinit var callback: AccessPointController.AccessPointCallback
@Mock
- private lateinit var otherCallback: NetworkController.AccessPointController.AccessPointCallback
+ private lateinit var otherCallback: AccessPointController.AccessPointCallback
@Mock
private lateinit var wifiEntryConnected: WifiEntry
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/CallbackHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/CallbackHandlerTest.java
index 11a53c55c024..2d29c80a15ac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/CallbackHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/CallbackHandlerTest.java
@@ -29,10 +29,6 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.connectivity.NetworkController.EmergencyListener;
-import com.android.systemui.statusbar.connectivity.NetworkController.IconState;
-import com.android.systemui.statusbar.connectivity.NetworkController.MobileDataIndicators;
-import com.android.systemui.statusbar.connectivity.NetworkController.SignalCallback;
-import com.android.systemui.statusbar.connectivity.NetworkController.WifiIndicators;
import com.android.systemui.tests.R;
import org.junit.Before;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/MobileStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/MobileStateTest.java
index 92a32bce1799..7ddfde370afa 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/MobileStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/MobileStateTest.java
@@ -14,22 +14,26 @@
* limitations under the License.
*/
-package com.android.settingslib;
+package com.android.systemui.statusbar.connectivity;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+
import com.android.settingslib.mobile.TelephonyIcons;
+import com.android.systemui.SysuiTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-@RunWith(RobolectricTestRunner.class)
-public class MobileStateTest {
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class MobileStateTest extends SysuiTestCase {
- private SignalIcon.MobileState mState = new SignalIcon.MobileState();
+ private final MobileState mState = new MobileState();
@Before
public void setUp() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
index b23d07a314b4..47a11fcdcee4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
@@ -72,9 +72,6 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.statusbar.connectivity.NetworkController.IconState;
-import com.android.systemui.statusbar.connectivity.NetworkController.MobileDataIndicators;
-import com.android.systemui.statusbar.connectivity.NetworkController.SignalCallback;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.telephony.TelephonyListenerManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerEthernetTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerEthernetTest.java
index 675d755ad3e3..f6f939ad2e12 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerEthernetTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerEthernetTest.java
@@ -23,8 +23,6 @@ import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
-import com.android.systemui.statusbar.connectivity.NetworkController.IconState;
-
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
index ffeaf207942b..a39971d27303 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
@@ -36,7 +36,6 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import com.android.settingslib.mobile.TelephonyIcons;
-import com.android.systemui.statusbar.connectivity.NetworkController.WifiIndicators;
import org.junit.Before;
import org.junit.Test;
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 39d794dc0bd9..f08a74ab1316 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
@@ -35,6 +35,7 @@ import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
@@ -50,6 +51,7 @@ import static java.util.Objects.requireNonNull;
import android.annotation.Nullable;
import android.app.Notification;
+import android.os.Handler;
import android.os.RemoteException;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationListenerService.RankingMap;
@@ -60,6 +62,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Pair;
+import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;
import com.android.internal.statusbar.IStatusBarService;
@@ -76,6 +79,7 @@ import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoa
import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer.BatchableNotificationHandler;
import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
+import com.android.systemui.statusbar.notification.collection.notifcollection.InternalNotifUpdater;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionLogger;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
@@ -106,6 +110,7 @@ public class NotifCollectionTest extends SysuiTestCase {
@Mock private FeatureFlags mFeatureFlags;
@Mock private NotifCollectionLogger mLogger;
@Mock private LogBufferEulogizer mEulogizer;
+ @Mock private Handler mMainHandler;
@Mock private GroupCoalescer mGroupCoalescer;
@Spy private RecordingCollectionListener mCollectionListener;
@@ -151,6 +156,7 @@ public class NotifCollectionTest extends SysuiTestCase {
mClock,
mFeatureFlags,
mLogger,
+ mMainHandler,
mEulogizer,
mock(DumpManager.class));
mCollection.attach(mGroupCoalescer);
@@ -1321,6 +1327,78 @@ public class NotifCollectionTest extends SysuiTestCase {
verify(mCollectionListener, never()).onEntryRemoved(any(NotificationEntry.class), anyInt());
}
+ private Runnable getInternalNotifUpdateRunnable(StatusBarNotification sbn) {
+ InternalNotifUpdater updater = mCollection.getInternalNotifUpdater("Test");
+ updater.onInternalNotificationUpdate(sbn, "reason");
+ ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+ verify(mMainHandler).post(runnableCaptor.capture());
+ return runnableCaptor.getValue();
+ }
+
+ @Test
+ public void testGetInternalNotifUpdaterPostsToMainHandler() {
+ InternalNotifUpdater updater = mCollection.getInternalNotifUpdater("Test");
+ updater.onInternalNotificationUpdate(mock(StatusBarNotification.class), "reason");
+ verify(mMainHandler).post(any());
+ }
+
+ @Test
+ public void testSecondPostCallsUpdateWithTrue() {
+ // GIVEN a pipeline with one notification
+ NotifEvent notifEvent = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
+ NotificationEntry entry = mCollectionListener.getEntry(notifEvent.key);
+
+ // KNOWING that it already called listener methods once
+ verify(mCollectionListener).onEntryAdded(eq(entry));
+ verify(mCollectionListener).onRankingApplied();
+
+ // WHEN we update the notification via the system
+ mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
+
+ // THEN entry updated gets called, added does not, and ranking is called again
+ verify(mCollectionListener).onEntryUpdated(eq(entry));
+ verify(mCollectionListener).onEntryUpdated(eq(entry), eq(true));
+ verify(mCollectionListener).onEntryAdded((entry));
+ verify(mCollectionListener, times(2)).onRankingApplied();
+ }
+
+ @Test
+ public void testInternalNotifUpdaterCallsUpdate() {
+ // GIVEN a pipeline with one notification
+ NotifEvent notifEvent = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
+ NotificationEntry entry = mCollectionListener.getEntry(notifEvent.key);
+
+ // KNOWING that it will call listener methods once
+ verify(mCollectionListener).onEntryAdded(eq(entry));
+ verify(mCollectionListener).onRankingApplied();
+
+ // WHEN we update that notification internally
+ StatusBarNotification sbn = notifEvent.sbn;
+ getInternalNotifUpdateRunnable(sbn).run();
+
+ // THEN only entry updated gets called a second time
+ verify(mCollectionListener).onEntryAdded(eq(entry));
+ verify(mCollectionListener).onRankingApplied();
+ verify(mCollectionListener).onEntryUpdated(eq(entry));
+ verify(mCollectionListener).onEntryUpdated(eq(entry), eq(false));
+ }
+
+ @Test
+ public void testInternalNotifUpdaterIgnoresNew() {
+ // GIVEN a pipeline without any notifications
+ StatusBarNotification sbn = buildNotif(TEST_PACKAGE, 47, "myTag").build().getSbn();
+
+ // WHEN we internally update an unknown notification
+ getInternalNotifUpdateRunnable(sbn).run();
+
+ // THEN only entry updated gets called a second time
+ verify(mCollectionListener, never()).onEntryAdded(any());
+ verify(mCollectionListener, never()).onRankingUpdate(any());
+ verify(mCollectionListener, never()).onRankingApplied();
+ verify(mCollectionListener, never()).onEntryUpdated(any());
+ verify(mCollectionListener, never()).onEntryUpdated(any(), anyBoolean());
+ }
+
private static NotificationEntryBuilder buildNotif(String pkg, int id, String tag) {
return new NotificationEntryBuilder()
.setPkg(pkg)
@@ -1371,6 +1449,11 @@ public class NotifCollectionTest extends SysuiTestCase {
}
@Override
+ public void onEntryUpdated(NotificationEntry entry, boolean fromSystem) {
+ onEntryUpdated(entry);
+ }
+
+ @Override
public void onEntryRemoved(NotificationEntry entry, int reason) {
}
@@ -1405,25 +1488,26 @@ public class NotifCollectionTest extends SysuiTestCase {
mName = name;
}
+ @NonNull
@Override
public String getName() {
return mName;
}
@Override
- public void setCallback(OnEndLifetimeExtensionCallback callback) {
+ public void setCallback(@NonNull OnEndLifetimeExtensionCallback callback) {
this.callback = callback;
}
@Override
public boolean shouldExtendLifetime(
- NotificationEntry entry,
+ @NonNull NotificationEntry entry,
@CancellationReason int reason) {
return shouldExtendLifetime;
}
@Override
- public void cancelLifetimeExtension(NotificationEntry entry) {
+ public void cancelLifetimeExtension(@NonNull NotificationEntry entry) {
if (onCancelLifetimeExtension != null) {
onCancelLifetimeExtension.run();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index 3378003b0d44..190c3521e83c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -33,6 +33,7 @@ import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static java.util.Collections.singletonList;
@@ -42,6 +43,7 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.ArrayMap;
+import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -54,6 +56,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.OnBefo
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.ShadeListBuilderLogger;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
@@ -78,6 +81,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
@SmallTest
@@ -608,6 +612,30 @@ public class ShadeListBuilderTest extends SysuiTestCase {
}
@Test
+ public void testNotifSectionsChildrenUpdated() {
+ AtomicBoolean validChildren = new AtomicBoolean(false);
+ final NotifSectioner pkg1Sectioner = spy(new PackageSectioner(PACKAGE_1) {
+ @Nullable
+ @Override
+ public void onEntriesUpdated(List<ListEntry> entries) {
+ super.onEntriesUpdated(entries);
+ validChildren.set(entries.size() == 2);
+ }
+ });
+ mListBuilder.setSectioners(Arrays.asList(pkg1Sectioner));
+
+ addNotif(0, PACKAGE_4);
+ addNotif(1, PACKAGE_1);
+ addNotif(2, PACKAGE_1);
+ addNotif(3, PACKAGE_3);
+
+ dispatchBuild();
+
+ verify(pkg1Sectioner, times(1)).onEntriesUpdated(any());
+ assertTrue(validChildren.get());
+ }
+
+ @Test
public void testNotifSections() {
// GIVEN a filter that removes all PACKAGE_4 notifs and sections that divide
// notifs based on package name
@@ -820,11 +848,13 @@ public class ShadeListBuilderTest extends SysuiTestCase {
NotifPromoter idPromoter = new IdPromoter(4);
NotifSectioner section = new PackageSectioner(PACKAGE_1);
NotifComparator hypeComparator = new HypeComparator(PACKAGE_2);
+ Invalidator preRenderInvalidator = new Invalidator("PreRenderInvalidator") {};
mListBuilder.addPreGroupFilter(packageFilter);
mListBuilder.addPromoter(idPromoter);
mListBuilder.setSectioners(singletonList(section));
mListBuilder.setComparators(singletonList(hypeComparator));
+ mListBuilder.addPreRenderInvalidator(preRenderInvalidator);
// GIVEN a set of random notifs
addNotif(0, PACKAGE_1);
@@ -849,6 +879,10 @@ public class ShadeListBuilderTest extends SysuiTestCase {
clearInvocations(mOnRenderListListener);
hypeComparator.invalidateList();
verify(mOnRenderListListener).onRenderList(anyList());
+
+ clearInvocations(mOnRenderListListener);
+ preRenderInvalidator.invalidateList();
+ verify(mOnRenderListListener).onRenderList(anyList());
}
@Test
@@ -1633,7 +1667,7 @@ public class ShadeListBuilderTest extends SysuiTestCase {
private final String mPackage;
PackageSectioner(String pkg) {
- super("PackageSection_" + pkg);
+ super("PackageSection_" + pkg, 0);
mPackage = pkg;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
new file mode 100644
index 000000000000..0cba07033c63
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
@@ -0,0 +1,117 @@
+/*
+ * 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.collection.coordinator
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender.OnEndLifetimeExtensionCallback
+import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewListener
+import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager
+import com.android.systemui.statusbar.notification.row.NotificationGuts
+import com.android.systemui.util.mockito.argumentCaptor
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations.initMocks
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+class GutsCoordinatorTest : SysuiTestCase() {
+ private lateinit var coordinator: GutsCoordinator
+ private lateinit var notifLifetimeExtender: NotifLifetimeExtender
+ private lateinit var notifGutsViewListener: NotifGutsViewListener
+
+ private lateinit var entry1: NotificationEntry
+ private lateinit var entry2: NotificationEntry
+
+ @Mock private lateinit var notifGutsViewManager: NotifGutsViewManager
+ @Mock private lateinit var pipeline: NotifPipeline
+ @Mock private lateinit var dumpManager: DumpManager
+ @Mock private lateinit var logger: GutsCoordinatorLogger
+ @Mock private lateinit var lifetimeExtenderCallback: OnEndLifetimeExtensionCallback
+
+ @Before
+ fun setUp() {
+ initMocks(this)
+ coordinator = GutsCoordinator(notifGutsViewManager, logger, dumpManager)
+ coordinator.attach(pipeline)
+ notifLifetimeExtender = argumentCaptor<NotifLifetimeExtender>().let {
+ verify(pipeline).addNotificationLifetimeExtender(it.capture())
+ it.value!!
+ }
+ notifGutsViewListener = argumentCaptor<NotifGutsViewListener>().let {
+ verify(notifGutsViewManager).setGutsListener(it.capture())
+ it.value!!
+ }
+ notifLifetimeExtender.setCallback(lifetimeExtenderCallback)
+ entry1 = NotificationEntryBuilder().setId(1).build()
+ entry2 = NotificationEntryBuilder().setId(2).build()
+ }
+
+ @Test
+ fun testSimpleLifetimeExtension() {
+ assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
+ notifGutsViewListener.onGutsOpen(entry1, mock(NotificationGuts::class.java))
+ assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isTrue()
+ notifGutsViewListener.onGutsClose(entry1)
+ verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry1)
+ assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
+ }
+
+ @Test
+ fun testDoubleOpenLifetimeExtension() {
+ assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
+ notifGutsViewListener.onGutsOpen(entry1, mock(NotificationGuts::class.java))
+ assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isTrue()
+ notifGutsViewListener.onGutsOpen(entry1, mock(NotificationGuts::class.java))
+ assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isTrue()
+ notifGutsViewListener.onGutsClose(entry1)
+ verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry1)
+ assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
+ }
+
+ @Test
+ fun testTwoEntryLifetimeExtension() {
+ assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
+ assertThat(notifLifetimeExtender.shouldExtendLifetime(entry2, 0)).isFalse()
+ notifGutsViewListener.onGutsOpen(entry1, mock(NotificationGuts::class.java))
+ assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(notifLifetimeExtender.shouldExtendLifetime(entry2, 0)).isFalse()
+ notifGutsViewListener.onGutsOpen(entry2, mock(NotificationGuts::class.java))
+ assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(notifLifetimeExtender.shouldExtendLifetime(entry2, 0)).isTrue()
+ notifGutsViewListener.onGutsClose(entry1)
+ verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry1)
+ assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
+ assertThat(notifLifetimeExtender.shouldExtendLifetime(entry2, 0)).isTrue()
+ notifGutsViewListener.onGutsClose(entry2)
+ verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry2)
+ assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
+ assertThat(notifLifetimeExtender.shouldExtendLifetime(entry2, 0)).isFalse()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
index 1031d6befc36..8f241a37c5ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
@@ -21,17 +21,22 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICAT
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.Notification;
+import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
+import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.RankingBuilder;
+import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -39,6 +44,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.collection.render.NodeController;
+import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
import org.junit.Before;
import org.junit.Test;
@@ -46,8 +52,11 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.Arrays;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class RankingCoordinatorTest extends SysuiTestCase {
@@ -56,7 +65,8 @@ public class RankingCoordinatorTest extends SysuiTestCase {
@Mock private HighPriorityProvider mHighPriorityProvider;
@Mock private NotifPipeline mNotifPipeline;
@Mock private NodeController mAlertingHeaderController;
- @Mock private NodeController mSilentHeaderController;
+ @Mock private NodeController mSilentNodeController;
+ @Mock private SectionHeaderController mSilentHeaderController;
@Captor private ArgumentCaptor<NotifFilter> mNotifFilterCaptor;
@@ -72,7 +82,7 @@ public class RankingCoordinatorTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
RankingCoordinator rankingCoordinator = new RankingCoordinator(
mStatusBarStateController, mHighPriorityProvider, mAlertingHeaderController,
- mSilentHeaderController);
+ mSilentHeaderController, mSilentNodeController);
mEntry = new NotificationEntryBuilder().build();
rankingCoordinator.attach(mNotifPipeline);
@@ -85,6 +95,28 @@ public class RankingCoordinatorTest extends SysuiTestCase {
}
@Test
+ public void testSilentHeaderClearableChildrenUpdate() {
+ StatusBarNotification sbn = Mockito.mock(StatusBarNotification.class);
+ Mockito.doReturn("key").when(sbn).getKey();
+ Mockito.doReturn(Mockito.mock(Notification.class)).when(sbn).getNotification();
+ NotificationEntry entry = new NotificationEntryBuilder().setSbn(sbn).build();
+ ListEntry listEntry = new ListEntry("key", 0L) {
+ @Nullable
+ @Override
+ public NotificationEntry getRepresentativeEntry() {
+ return entry;
+ }
+ };
+ Mockito.doReturn(true).when(sbn).isClearable();
+ mSilentSectioner.onEntriesUpdated(Arrays.asList(listEntry));
+ verify(mSilentHeaderController).setClearSectionEnabled(eq(true));
+
+ Mockito.doReturn(false).when(sbn).isClearable();
+ mSilentSectioner.onEntriesUpdated(Arrays.asList(listEntry));
+ verify(mSilentHeaderController).setClearSectionEnabled(eq(false));
+ }
+
+ @Test
public void testUnfilteredState() {
// GIVEN no suppressed visual effects + app not suspended
mEntry.setRanking(getRankingForUnfilteredNotif().build());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt
new file mode 100644
index 000000000000..0ce6ada51f23
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt
@@ -0,0 +1,145 @@
+/*
+ * 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.collection.coordinator
+
+import android.os.Handler
+import android.service.notification.StatusBarNotification
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.NotificationRemoteInputManager
+import com.android.systemui.statusbar.NotificationRemoteInputManager.RemoteInputListener
+import com.android.systemui.statusbar.RemoteInputNotificationRebuilder
+import com.android.systemui.statusbar.SmartReplyController
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.notifcollection.InternalNotifUpdater
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender.OnEndLifetimeExtensionCallback
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations.initMocks
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+class RemoteInputCoordinatorTest : SysuiTestCase() {
+ private lateinit var coordinator: RemoteInputCoordinator
+ private lateinit var listener: RemoteInputListener
+ private lateinit var collectionListener: NotifCollectionListener
+
+ private lateinit var entry1: NotificationEntry
+ private lateinit var entry2: NotificationEntry
+
+ @Mock private lateinit var lifetimeExtensionCallback: OnEndLifetimeExtensionCallback
+ @Mock private lateinit var rebuilder: RemoteInputNotificationRebuilder
+ @Mock private lateinit var remoteInputManager: NotificationRemoteInputManager
+ @Mock private lateinit var mainHandler: Handler
+ @Mock private lateinit var smartReplyController: SmartReplyController
+ @Mock private lateinit var pipeline: NotifPipeline
+ @Mock private lateinit var notifUpdater: InternalNotifUpdater
+ @Mock private lateinit var dumpManager: DumpManager
+ @Mock private lateinit var sbn: StatusBarNotification
+
+ @Before
+ fun setUp() {
+ initMocks(this)
+ coordinator = RemoteInputCoordinator(
+ dumpManager,
+ rebuilder,
+ remoteInputManager,
+ mainHandler,
+ smartReplyController
+ )
+ `when`(pipeline.addNotificationLifetimeExtender(any())).thenAnswer {
+ (it.arguments[0] as NotifLifetimeExtender).setCallback(lifetimeExtensionCallback)
+ }
+ `when`(pipeline.getInternalNotifUpdater(any())).thenReturn(notifUpdater)
+ coordinator.attach(pipeline)
+ listener = withArgCaptor {
+ verify(remoteInputManager).setRemoteInputListener(capture())
+ }
+ collectionListener = withArgCaptor {
+ verify(pipeline).addCollectionListener(capture())
+ }
+ entry1 = NotificationEntryBuilder().setId(1).build()
+ entry2 = NotificationEntryBuilder().setId(2).build()
+ `when`(rebuilder.rebuildForCanceledSmartReplies(any())).thenReturn(sbn)
+ `when`(rebuilder.rebuildForRemoteInputReply(any())).thenReturn(sbn)
+ `when`(rebuilder.rebuildForSendingSmartReply(any(), any())).thenReturn(sbn)
+ }
+
+ val remoteInputActiveExtender get() = coordinator.mRemoteInputActiveExtender
+ val remoteInputHistoryExtender get() = coordinator.mRemoteInputHistoryExtender
+ val smartReplyHistoryExtender get() = coordinator.mSmartReplyHistoryExtender
+
+ @Test
+ fun testRemoteInputActive() {
+ `when`(remoteInputManager.isRemoteInputActive(entry1)).thenReturn(true)
+ assertThat(remoteInputActiveExtender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(remoteInputHistoryExtender.shouldExtendLifetime(entry1, 0)).isFalse()
+ assertThat(smartReplyHistoryExtender.shouldExtendLifetime(entry1, 0)).isFalse()
+ assertThat(listener.isNotificationKeptForRemoteInputHistory(entry1.key)).isFalse()
+ }
+
+ @Test
+ fun testRemoteInputHistory() {
+ `when`(remoteInputManager.shouldKeepForRemoteInputHistory(entry1)).thenReturn(true)
+ assertThat(remoteInputActiveExtender.shouldExtendLifetime(entry1, 0)).isFalse()
+ assertThat(remoteInputHistoryExtender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(smartReplyHistoryExtender.shouldExtendLifetime(entry1, 0)).isFalse()
+ assertThat(listener.isNotificationKeptForRemoteInputHistory(entry1.key)).isTrue()
+ }
+
+ @Test
+ fun testSmartReplyHistory() {
+ `when`(remoteInputManager.shouldKeepForSmartReplyHistory(entry1)).thenReturn(true)
+ assertThat(remoteInputActiveExtender.shouldExtendLifetime(entry1, 0)).isFalse()
+ assertThat(remoteInputHistoryExtender.shouldExtendLifetime(entry1, 0)).isFalse()
+ assertThat(smartReplyHistoryExtender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(listener.isNotificationKeptForRemoteInputHistory(entry1.key)).isTrue()
+ }
+
+ @Test
+ fun testNotificationWithRemoteInputActiveIsRemovedOnCollapse() {
+ `when`(remoteInputManager.isRemoteInputActive(entry1)).thenReturn(true)
+ assertThat(remoteInputActiveExtender.isExtending(entry1.key)).isFalse()
+
+ // Nothing should happen on panel collapse before we start extending the lifetime
+ listener.onPanelCollapsed()
+ assertThat(remoteInputActiveExtender.isExtending(entry1.key)).isFalse()
+ verify(lifetimeExtensionCallback, never()).onEndLifetimeExtension(any(), any())
+
+ // Start extending lifetime & validate that the extension is ended
+ assertThat(remoteInputActiveExtender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(remoteInputActiveExtender.isExtending(entry1.key)).isTrue()
+ listener.onPanelCollapsed()
+ verify(lifetimeExtensionCallback).onEndLifetimeExtension(remoteInputActiveExtender, entry1)
+ assertThat(remoteInputActiveExtender.isExtending(entry1.key)).isFalse()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
new file mode 100644
index 000000000000..5fd4174af164
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
@@ -0,0 +1,209 @@
+/*
+ * 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.collection.coordinator
+
+import android.os.UserHandle
+import android.service.notification.StatusBarNotification
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.statusbar.notification.DynamicPrivacyController
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable
+import com.android.systemui.util.mockito.withArgCaptor
+import com.android.systemui.util.mockito.mock
+import org.junit.Test
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+class SensitiveContentCoordinatorTest : SysuiTestCase() {
+
+ val dynamicPrivacyController: DynamicPrivacyController = mock()
+ val lockscreenUserManager: NotificationLockscreenUserManager = mock()
+ val pipeline: NotifPipeline = mock()
+
+ val coordinator: SensitiveContentCoordinator = SensitiveContentCoordinatorModule
+ .provideCoordinator(dynamicPrivacyController, lockscreenUserManager)
+
+ @Test
+ fun onDynamicPrivacyChanged_invokeInvalidationListener() {
+ coordinator.attach(pipeline)
+ val invalidator = withArgCaptor<Invalidator> {
+ verify(pipeline).addPreRenderInvalidator(capture())
+ }
+ val dynamicPrivacyListener = withArgCaptor<DynamicPrivacyController.Listener> {
+ verify(dynamicPrivacyController).addListener(capture())
+ }
+
+ val invalidationListener = mock<Pluggable.PluggableListener<Invalidator>>()
+ invalidator.setInvalidationListener(invalidationListener)
+
+ dynamicPrivacyListener.onDynamicPrivacyChanged()
+
+ verify(invalidationListener).onPluggableInvalidated(invalidator)
+ }
+
+ @Test
+ fun onBeforeRenderList_deviceUnlocked_notifDoesNotNeedRedaction() {
+ coordinator.attach(pipeline)
+ val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
+ verify(pipeline).addOnBeforeRenderListListener(capture())
+ }
+
+ whenever(lockscreenUserManager.currentUserId).thenReturn(1)
+ whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false)
+ whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true)
+ whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false)
+ val entry = fakeNotification(1, false)
+
+ onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
+
+ verify(entry.representativeEntry!!).setSensitive(false, false)
+ }
+
+ @Test
+ fun onBeforeRenderList_deviceUnlocked_notifWouldNeedRedaction() {
+ coordinator.attach(pipeline)
+ val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
+ verify(pipeline).addOnBeforeRenderListListener(capture())
+ }
+
+ whenever(lockscreenUserManager.currentUserId).thenReturn(1)
+ whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false)
+ whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true)
+ whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false)
+ val entry = fakeNotification(1, true)
+
+ onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
+
+ verify(entry.representativeEntry!!).setSensitive(false, false)
+ }
+
+ @Test
+ fun onBeforeRenderList_deviceLocked_userAllowsPublicNotifs() {
+ coordinator.attach(pipeline)
+ val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
+ verify(pipeline).addOnBeforeRenderListListener(capture())
+ }
+
+ whenever(lockscreenUserManager.currentUserId).thenReturn(1)
+ whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
+ whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true)
+ whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false)
+ val entry = fakeNotification(1, false)
+
+ onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
+
+ verify(entry.representativeEntry!!).setSensitive(false, false)
+ }
+
+ @Test
+ fun onBeforeRenderList_deviceLocked_userDisallowsPublicNotifs_notifDoesNotNeedRedaction() {
+ coordinator.attach(pipeline)
+ val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
+ verify(pipeline).addOnBeforeRenderListListener(capture())
+ }
+
+ whenever(lockscreenUserManager.currentUserId).thenReturn(1)
+ whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
+ whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false)
+ whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false)
+ val entry = fakeNotification(1, false)
+
+ onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
+
+ verify(entry.representativeEntry!!).setSensitive(false, true)
+ }
+
+ @Test
+ fun onBeforeRenderList_deviceLocked_notifNeedsRedaction() {
+ coordinator.attach(pipeline)
+ val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
+ verify(pipeline).addOnBeforeRenderListListener(capture())
+ }
+
+ whenever(lockscreenUserManager.currentUserId).thenReturn(1)
+ whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
+ whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false)
+ whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false)
+ val entry = fakeNotification(1, true)
+
+ onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
+
+ verify(entry.representativeEntry!!).setSensitive(true, true)
+ }
+
+ @Test
+ fun onBeforeRenderList_deviceDynamicallyUnlocked_notifNeedsRedaction() {
+ coordinator.attach(pipeline)
+ val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
+ verify(pipeline).addOnBeforeRenderListListener(capture())
+ }
+
+ whenever(lockscreenUserManager.currentUserId).thenReturn(1)
+ whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
+ whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false)
+ whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true)
+ val entry = fakeNotification(1, true)
+
+ onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
+
+ verify(entry.representativeEntry!!).setSensitive(false, true)
+ }
+
+ @Test
+ fun onBeforeRenderList_deviceDynamicallyUnlocked_notifUserNeedsWorkChallenge() {
+ coordinator.attach(pipeline)
+ val onBeforeRenderListListener = withArgCaptor<OnBeforeRenderListListener> {
+ verify(pipeline).addOnBeforeRenderListListener(capture())
+ }
+
+ whenever(lockscreenUserManager.currentUserId).thenReturn(1)
+ whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true)
+ whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false)
+ whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true)
+ whenever(lockscreenUserManager.needsSeparateWorkChallenge(2)).thenReturn(true)
+
+ val entry = fakeNotification(2, true)
+
+ onBeforeRenderListListener.onBeforeRenderList(listOf(entry))
+
+ verify(entry.representativeEntry!!).setSensitive(true, true)
+ }
+
+ private fun fakeNotification(notifUserId: Int, needsRedaction: Boolean): ListEntry {
+ val mockUserHandle = mock<UserHandle>().apply {
+ whenever(identifier).thenReturn(notifUserId)
+ }
+ val mockSbn: StatusBarNotification = mock<StatusBarNotification>().apply {
+ whenever(user).thenReturn(mockUserHandle)
+ }
+ val mockEntry = mock<NotificationEntry>().apply {
+ whenever(sbn).thenReturn(mockSbn)
+ }
+ whenever(lockscreenUserManager.needsRedaction(mockEntry)).thenReturn(needsRedaction)
+ whenever(mockEntry.rowExists()).thenReturn(true)
+ return object : ListEntry("key", 0) {
+ override fun getRepresentativeEntry(): NotificationEntry = mockEntry
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt
new file mode 100644
index 000000000000..5915cd7823f0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt
@@ -0,0 +1,106 @@
+/*
+ * 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.collection.coordinator
+
+import android.service.notification.NotificationListenerService.REASON_APP_CANCEL
+import android.service.notification.NotificationListenerService.REASON_CANCEL
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
+import com.android.systemui.util.mockito.argumentCaptor
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations.initMocks
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+class ShadeEventCoordinatorTest : SysuiTestCase() {
+ private lateinit var coordinator: ShadeEventCoordinator
+ private lateinit var notifCollectionListener: NotifCollectionListener
+ private lateinit var onBeforeRenderListListener: OnBeforeRenderListListener
+
+ private lateinit var entry1: NotificationEntry
+ private lateinit var entry2: NotificationEntry
+
+ @Mock private lateinit var pipeline: NotifPipeline
+ @Mock private lateinit var logger: ShadeEventCoordinatorLogger
+ @Mock private lateinit var notifRemovedByUserCallback: Runnable
+ @Mock private lateinit var shadeEmptiedCallback: Runnable
+
+ @Before
+ fun setUp() {
+ initMocks(this)
+ coordinator = ShadeEventCoordinator(logger)
+ coordinator.attach(pipeline)
+ notifCollectionListener = argumentCaptor<NotifCollectionListener>().let {
+ verify(pipeline).addCollectionListener(it.capture())
+ it.value!!
+ }
+ onBeforeRenderListListener = argumentCaptor<OnBeforeRenderListListener>().let {
+ verify(pipeline).addOnBeforeRenderListListener(it.capture())
+ it.value!!
+ }
+ coordinator.setNotifRemovedByUserCallback(notifRemovedByUserCallback)
+ coordinator.setShadeEmptiedCallback(shadeEmptiedCallback)
+ entry1 = NotificationEntryBuilder().setId(1).build()
+ entry2 = NotificationEntryBuilder().setId(2).build()
+ }
+
+ @Test
+ fun testUserCancelLastNotification() {
+ notifCollectionListener.onEntryRemoved(entry1, REASON_CANCEL)
+ verify(shadeEmptiedCallback, never()).run()
+ verify(notifRemovedByUserCallback, never()).run()
+ onBeforeRenderListListener.onBeforeRenderList(listOf())
+ verify(shadeEmptiedCallback).run()
+ verify(notifRemovedByUserCallback).run()
+ }
+
+ @Test
+ fun testAppCancelLastNotification() {
+ notifCollectionListener.onEntryRemoved(entry1, REASON_APP_CANCEL)
+ onBeforeRenderListListener.onBeforeRenderList(listOf())
+ verify(shadeEmptiedCallback).run()
+ verify(notifRemovedByUserCallback, never()).run()
+ }
+
+ @Test
+ fun testUserCancelOneOfTwoNotifications() {
+ notifCollectionListener.onEntryRemoved(entry1, REASON_CANCEL)
+ onBeforeRenderListListener.onBeforeRenderList(listOf(entry2))
+ verify(shadeEmptiedCallback, never()).run()
+ verify(notifRemovedByUserCallback).run()
+ }
+
+ @Test
+ fun testAppCancelOneOfTwoNotifications() {
+ notifCollectionListener.onEntryRemoved(entry1, REASON_APP_CANCEL)
+ onBeforeRenderListListener.onBeforeRenderList(listOf(entry2))
+ verify(shadeEmptiedCallback, never()).run()
+ verify(notifRemovedByUserCallback, never()).run()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt
new file mode 100644
index 000000000000..37ad8357aa95
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt
@@ -0,0 +1,230 @@
+/*
+ * 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.collection.notifcollection
+
+import android.os.Handler
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender.OnEndLifetimeExtensionCallback
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyLong
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations.initMocks
+import java.util.function.Consumer
+import java.util.function.Predicate
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+class SelfTrackingLifetimeExtenderTest : SysuiTestCase() {
+ private lateinit var extender: TestableSelfTrackingLifetimeExtender
+
+ private lateinit var entry1: NotificationEntry
+ private lateinit var entry2: NotificationEntry
+
+ @Mock
+ private lateinit var callback: OnEndLifetimeExtensionCallback
+ @Mock
+ private lateinit var mainHandler: Handler
+ @Mock
+ private lateinit var shouldExtend: Predicate<NotificationEntry>
+ @Mock
+ private lateinit var onStarted: Consumer<NotificationEntry>
+ @Mock
+ private lateinit var onCanceled: Consumer<NotificationEntry>
+
+ @Before
+ fun setUp() {
+ initMocks(this)
+ extender = TestableSelfTrackingLifetimeExtender()
+ extender.setCallback(callback)
+ entry1 = NotificationEntryBuilder().setId(1).build()
+ entry2 = NotificationEntryBuilder().setId(2).build()
+ }
+
+ @Test
+ fun testName() {
+ assertThat(extender.name).isEqualTo("Testable")
+ }
+
+ @Test
+ fun testNoExtend() {
+ `when`(shouldExtend.test(entry1)).thenReturn(false)
+ assertThat(extender.shouldExtendLifetime(entry1, 0)).isFalse()
+ assertThat(extender.isExtending(entry1.key)).isFalse()
+ verify(onStarted, never()).accept(entry1)
+ verify(onCanceled, never()).accept(entry1)
+ }
+
+ @Test
+ fun testExtendThenCancelForRepost() {
+ `when`(shouldExtend.test(entry1)).thenReturn(true)
+ assertThat(extender.shouldExtendLifetime(entry1, 0)).isTrue()
+ verify(onStarted).accept(entry1)
+ verify(onCanceled, never()).accept(entry1)
+ assertThat(extender.isExtending(entry1.key)).isTrue()
+ extender.cancelLifetimeExtension(entry1)
+ verify(onCanceled).accept(entry1)
+ }
+
+ @Test
+ fun testExtendThenCancel_thenEndDoesNothing() {
+ testExtendThenCancelForRepost()
+ assertThat(extender.isExtending(entry1.key)).isFalse()
+
+ extender.endLifetimeExtension(entry1.key)
+ extender.endLifetimeExtensionAfterDelay(entry1.key, 1000)
+ verify(callback, never()).onEndLifetimeExtension(any(), any())
+ verify(mainHandler, never()).postDelayed(any(), anyLong())
+ }
+
+ @Test
+ fun testExtendThenEnd() {
+ `when`(shouldExtend.test(entry1)).thenReturn(true)
+ assertThat(extender.shouldExtendLifetime(entry1, 0)).isTrue()
+ verify(onStarted).accept(entry1)
+ assertThat(extender.isExtending(entry1.key)).isTrue()
+ extender.endLifetimeExtension(entry1.key)
+ verify(callback).onEndLifetimeExtension(extender, entry1)
+ verify(onCanceled, never()).accept(entry1)
+ }
+
+ @Test
+ fun testExtendThenEndAfterDelay() {
+ `when`(shouldExtend.test(entry1)).thenReturn(true)
+ assertThat(extender.shouldExtendLifetime(entry1, 0)).isTrue()
+ verify(onStarted).accept(entry1)
+ assertThat(extender.isExtending(entry1.key)).isTrue()
+
+ // Call the method and capture the posted runnable
+ extender.endLifetimeExtensionAfterDelay(entry1.key, 1234)
+ val runnable = withArgCaptor<Runnable> {
+ verify(mainHandler).postDelayed(capture(), eq(1234.toLong()))
+ }
+ assertThat(extender.isExtending(entry1.key)).isTrue()
+ verify(callback, never()).onEndLifetimeExtension(any(), any())
+
+ // now run the posted runnable and ensure it works as expected
+ runnable.run()
+ verify(callback).onEndLifetimeExtension(extender, entry1)
+ assertThat(extender.isExtending(entry1.key)).isFalse()
+ verify(onCanceled, never()).accept(entry1)
+ }
+
+ @Test
+ fun testExtendThenEndAll() {
+ `when`(shouldExtend.test(entry1)).thenReturn(true)
+ `when`(shouldExtend.test(entry2)).thenReturn(true)
+ assertThat(extender.shouldExtendLifetime(entry1, 0)).isTrue()
+ verify(onStarted).accept(entry1)
+ assertThat(extender.isExtending(entry1.key)).isTrue()
+ assertThat(extender.isExtending(entry2.key)).isFalse()
+ assertThat(extender.shouldExtendLifetime(entry2, 0)).isTrue()
+ verify(onStarted).accept(entry2)
+ assertThat(extender.isExtending(entry1.key)).isTrue()
+ assertThat(extender.isExtending(entry2.key)).isTrue()
+ extender.endAllLifetimeExtensions()
+ verify(callback).onEndLifetimeExtension(extender, entry1)
+ verify(callback).onEndLifetimeExtension(extender, entry2)
+ verify(onCanceled, never()).accept(entry1)
+ verify(onCanceled, never()).accept(entry2)
+ }
+
+ @Test
+ fun testExtendWithinEndCanReExtend() {
+ `when`(shouldExtend.test(entry1)).thenReturn(true)
+ assertThat(extender.shouldExtendLifetime(entry1, 0)).isTrue()
+ verify(onStarted, times(1)).accept(entry1)
+
+ `when`(callback.onEndLifetimeExtension(extender, entry1)).thenAnswer {
+ assertThat(extender.shouldExtendLifetime(entry1, 0)).isTrue()
+ }
+ extender.endLifetimeExtension(entry1.key)
+ verify(onStarted, times(2)).accept(entry1)
+ assertThat(extender.isExtending(entry1.key)).isTrue()
+ }
+
+ @Test
+ fun testExtendWithinEndCanNotReExtend() {
+ `when`(shouldExtend.test(entry1)).thenReturn(true, false)
+ assertThat(extender.shouldExtendLifetime(entry1, 0)).isTrue()
+ verify(onStarted, times(1)).accept(entry1)
+
+ `when`(callback.onEndLifetimeExtension(extender, entry1)).thenAnswer {
+ assertThat(extender.shouldExtendLifetime(entry1, 0)).isFalse()
+ }
+ extender.endLifetimeExtension(entry1.key)
+ verify(onStarted, times(1)).accept(entry1)
+ assertThat(extender.isExtending(entry1.key)).isFalse()
+ }
+
+ @Test
+ fun testExtendWithinEndAllCanReExtend() {
+ `when`(shouldExtend.test(entry1)).thenReturn(true)
+ assertThat(extender.shouldExtendLifetime(entry1, 0)).isTrue()
+ verify(onStarted, times(1)).accept(entry1)
+
+ `when`(callback.onEndLifetimeExtension(extender, entry1)).thenAnswer {
+ assertThat(extender.shouldExtendLifetime(entry1, 0)).isTrue()
+ }
+ extender.endAllLifetimeExtensions()
+ verify(onStarted, times(2)).accept(entry1)
+ assertThat(extender.isExtending(entry1.key)).isTrue()
+ }
+
+ @Test
+ fun testExtendWithinEndAllCanNotReExtend() {
+ `when`(shouldExtend.test(entry1)).thenReturn(true, false)
+ assertThat(extender.shouldExtendLifetime(entry1, 0)).isTrue()
+ verify(onStarted, times(1)).accept(entry1)
+
+ `when`(callback.onEndLifetimeExtension(extender, entry1)).thenAnswer {
+ assertThat(extender.shouldExtendLifetime(entry1, 0)).isFalse()
+ }
+ extender.endAllLifetimeExtensions()
+ verify(onStarted, times(1)).accept(entry1)
+ assertThat(extender.isExtending(entry1.key)).isFalse()
+ }
+
+ inner class TestableSelfTrackingLifetimeExtender(debug: Boolean = false) :
+ SelfTrackingLifetimeExtender("Test", "Testable", debug, mainHandler) {
+
+ override fun queryShouldExtendLifetime(entry: NotificationEntry) =
+ shouldExtend.test(entry)
+
+ override fun onStartedLifetimeExtension(entry: NotificationEntry) {
+ onStarted.accept(entry)
+ }
+
+ override fun onCanceledLifetimeExtension(entry: NotificationEntry) {
+ onCanceled.accept(entry)
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
index 2e676bbe6541..ed48452eccc7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
@@ -26,6 +26,10 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntryB
import com.android.systemui.statusbar.notification.collection.getAttachState
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
+import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING
+import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE
+import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
+import com.android.systemui.statusbar.notification.stack.PriorityBucket
import com.android.systemui.util.mockito.any
import org.junit.Before
import org.junit.Test
@@ -45,11 +49,15 @@ class NodeSpecBuilderTest : SysuiTestCase() {
private var headerController1: NodeController = buildFakeController("header1")
private var headerController2: NodeController = buildFakeController("header2")
- private val section0 = buildSection(0, headerController0)
- private val section0NoHeader = buildSection(0, null)
- private val section1 = buildSection(1, headerController1)
- private val section1NoHeader = buildSection(1, null)
- private val section2 = buildSection(2, headerController2)
+ private val section0Bucket = BUCKET_PEOPLE
+ private val section1Bucket = BUCKET_ALERTING
+ private val section2Bucket = BUCKET_SILENT
+
+ private val section0 = buildSection(0, section0Bucket, headerController0)
+ private val section0NoHeader = buildSection(0, section0Bucket, null)
+ private val section1 = buildSection(1, section1Bucket, headerController1)
+ private val section1NoHeader = buildSection(1, section1Bucket, null)
+ private val section2 = buildSection(2, section2Bucket, headerController2)
private val fakeViewBarn = FakeViewBarn()
@@ -297,8 +305,12 @@ private fun buildFakeController(name: String): NodeController {
return controller
}
-private fun buildSection(index: Int, nodeController: NodeController?): NotifSection {
- return NotifSection(object : NotifSectioner("Section $index") {
+private fun buildSection(
+ index: Int,
+ @PriorityBucket bucket: Int,
+ nodeController: NodeController?
+): NotifSection {
+ return NotifSection(object : NotifSectioner("Section $index (bucket=$bucket)", bucket) {
override fun isInSection(entry: ListEntry?): Boolean {
throw NotImplementedError("This should never be called")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 42aecfdc11bd..c5d1e3acb2b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -255,6 +255,22 @@ public class NotificationTestHelper {
}
/**
+ * Returns an {@link ExpandableNotificationRow} that should be shown as a bubble.
+ */
+ public ExpandableNotificationRow createShortcutBubble(String shortcutId)
+ throws Exception {
+ Notification n = createNotification(false /* isGroupSummary */,
+ null /* groupKey */, makeShortcutBubbleMetadata(shortcutId));
+ n.flags |= FLAG_BUBBLE;
+ ExpandableNotificationRow row = generateRow(n, PKG, UID, USER_HANDLE,
+ 0 /* extraInflationFlags */, IMPORTANCE_HIGH);
+ modifyRanking(row.getEntry())
+ .setCanBubble(true)
+ .build();
+ return row;
+ }
+
+ /**
* Returns an {@link ExpandableNotificationRow} that should be shown as a bubble and is part
* of a group of notifications.
*/
@@ -506,6 +522,12 @@ public class NotificationTestHelper {
.build();
}
+ private BubbleMetadata makeShortcutBubbleMetadata(String shortcutId) {
+ return new BubbleMetadata.Builder(shortcutId)
+ .setDesiredHeight(314)
+ .build();
+ }
+
private static class MockSmartReplyInflater implements SmartReplyStateInflater {
@Override
public InflatedSmartReplyState inflateSmartReplyState(NotificationEntry entry) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index c1d2ea88a1b1..f11f8c476433 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -18,11 +18,11 @@ package com.android.systemui.statusbar.notification.stack;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_ALERTING;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_FOREGROUND_SERVICE;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_HEADS_UP;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_PEOPLE;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_ALERTING;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_FOREGROUND_SERVICE;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_HEADS_UP;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PEOPLE;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
import static com.google.common.truth.Truth.assertThat;
@@ -64,7 +64,6 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -608,7 +607,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
}
}
- private View mockNotification(int bucket, boolean isGone) {
+ private View mockNotification(@PriorityBucket int bucket, boolean isGone) {
ExpandableNotificationRow notifRow =
mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
when(notifRow.getVisibility()).thenReturn(View.VISIBLE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentLoggerTest.kt
index f3136c7be967..bf8cc37697b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentLoggerTest.kt
@@ -40,7 +40,7 @@ class CollapsedStatusBarFragmentLoggerTest : SysuiTestCase() {
private val logger = CollapsedStatusBarFragmentLogger(buffer, disableFlagsLogger)
@Test
- fun logToBuffer_bufferHasStates() {
+ fun logDisableFlagChange_bufferHasStates() {
val state = DisableFlagsLogger.DisableState(0, 1)
logger.logDisableFlagChange(state, state)
@@ -48,7 +48,9 @@ class CollapsedStatusBarFragmentLoggerTest : SysuiTestCase() {
val stringWriter = StringWriter()
buffer.dump(PrintWriter(stringWriter), tailLength = 0)
val actualString = stringWriter.toString()
- val expectedLogString = disableFlagsLogger.getDisableFlagsString(state, state)
+ val expectedLogString = disableFlagsLogger.getDisableFlagsString(
+ old = null, new = state, newAfterLocalModification = state
+ )
assertThat(actualString).contains(expectedLogString)
}
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 f23f14801484..c300021ac53a 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
@@ -38,6 +38,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiBaseFragmentTest;
+import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.LogcatEchoTracker;
@@ -48,7 +49,10 @@ import com.android.systemui.statusbar.OperatorNameViewController;
import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Ignore;
@@ -259,9 +263,12 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
mAnimationScheduler,
mLocationPublisher,
mMockNotificationAreaController,
+ new PanelExpansionStateManager(),
mock(FeatureFlags.class),
() -> Optional.of(mStatusBar),
mStatusBarIconController,
+ new StatusBarHideIconsForBouncerManager(
+ mCommandQueue, new FakeExecutor(new FakeSystemClock()), new DumpManager()),
mKeyguardStateController,
mNetworkController,
mStatusBarStateController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
index 1ce336e5f37d..34c43ef52a00 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
@@ -28,6 +28,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import org.junit.Before;
import org.junit.Test;
@@ -44,12 +45,15 @@ public class DozeScrimControllerTest extends SysuiTestCase {
private DozeParameters mDozeParameters;
@Mock
private DozeLog mDozeLog;
+ @Mock
+ private StatusBarStateController mStatusBarStateController;
private DozeScrimController mDozeScrimController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mDozeScrimController = new DozeScrimController(mDozeParameters, mDozeLog);
+ mDozeScrimController = new DozeScrimController(mDozeParameters, mDozeLog,
+ mStatusBarStateController);
mDozeScrimController.setDozing(true);
}
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 d098e1a0b8a5..11826954baee 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
@@ -58,7 +58,6 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
private KeyguardClockPositionAlgorithm.Result mClockPosition;
private MockitoSession mStaticMockSession;
- private int mNotificationStackHeight;
private float mPanelExpansion;
private int mKeyguardStatusBarHeaderHeight;
@@ -264,6 +263,58 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
}
@Test
+ public void clockPositionedDependingOnMarginInSplitShade() {
+ when(mResources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin))
+ .thenReturn(400);
+ mClockPositionAlgorithm.loadDimens(mResources);
+ givenLockScreen();
+ mIsSplitShade = true;
+ // WHEN the position algorithm is run
+ positionClock();
+
+ assertThat(mClockPosition.clockY).isEqualTo(400);
+ }
+
+ @Test
+ public void notifPaddingMakesUpToFullMarginInSplitShade() {
+ when(mResources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin))
+ .thenReturn(100);
+ when(mResources.getDimensionPixelSize(R.dimen.split_shade_header_height))
+ .thenReturn(70);
+ mClockPositionAlgorithm.loadDimens(mResources);
+ givenLockScreen();
+ mIsSplitShade = true;
+ // WHEN the position algorithm is run
+ positionClock();
+ // THEN the notif padding makes up lacking margin (margin - header height = 30).
+ assertThat(mClockPosition.stackScrollerPadding).isEqualTo(30);
+ }
+
+ @Test
+ public void notifPaddingExpandedAlignedWithClockInSplitShadeMode() {
+ givenLockScreen();
+ mIsSplitShade = true;
+ mKeyguardStatusHeight = 200;
+ // WHEN the position algorithm is run
+ positionClock();
+ // THEN the padding DOESN'T adjust for keyguard status height.
+ assertThat(mClockPosition.stackScrollerPaddingExpanded)
+ .isEqualTo(mClockPosition.clockY);
+ }
+
+ @Test
+ public void notifMinPaddingAlignedWithClockInSplitShadeMode() {
+ givenLockScreen();
+ mIsSplitShade = true;
+ mKeyguardStatusHeight = 200;
+ // WHEN the position algorithm is run
+ positionClock();
+ // THEN the padding DOESN'T adjust for keyguard status height.
+ assertThat(mClockPositionAlgorithm.getMinStackScrollerPadding())
+ .isEqualTo(mKeyguardStatusBarHeaderHeight);
+ }
+
+ @Test
public void notifPositionWithLargeClockOnLockScreen() {
// GIVEN on lock screen and clock has a nonzero height
givenLockScreen();
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 faf968b4ff44..8d05e6693e33 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
@@ -85,6 +85,8 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
private BiometricUnlockController mBiometricUnlockController;
@Mock
private SysuiStatusBarStateController mStatusBarStateController;
+ @Mock
+ private StatusBarContentInsetsProvider mStatusBarContentInsetsProvider;
private TestNotificationPanelViewStateProvider mNotificationPanelViewStateProvider;
private KeyguardStatusBarView mKeyguardStatusBarView;
@@ -118,7 +120,8 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
mKeyguardBypassController,
mKeyguardUpdateMonitor,
mBiometricUnlockController,
- mStatusBarStateController
+ mStatusBarStateController,
+ mStatusBarContentInsetsProvider
);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
index 25aa93aa37c2..bd4efdb32573 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
@@ -33,6 +33,7 @@ import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.wm.shell.bubbles.Bubbles;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
index ead32910f943..01f5654f24ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
@@ -90,6 +90,7 @@ import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.controls.dagger.ControlsComponent;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.media.KeyguardMediaController;
@@ -121,8 +122,10 @@ import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.unfold.SysUIUnfoldComponent;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.time.FakeSystemClock;
@@ -138,6 +141,7 @@ import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
import java.util.List;
+import java.util.Optional;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -172,8 +176,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
@Mock
private HeadsUpTouchHelper.Callback mHeadsUpCallback;
@Mock
- private PanelBar mPanelBar;
- @Mock
private KeyguardUpdateMonitor mUpdateMonitor;
@Mock
private KeyguardBypassController mKeyguardBypassController;
@@ -302,7 +304,9 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
private DumpManager mDumpManager;
@Mock
private NotificationsQSContainerController mNotificationsQSContainerController;
-
+ @Mock
+ private FeatureFlags mFeatureFlags;
+ private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
private SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController;
private View.AccessibilityDelegate mAccessibiltyDelegate;
@@ -444,14 +448,16 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mSplitShadeHeaderController,
mUnlockedScreenOffAnimationController,
mLockscreenGestureLogger,
+ new PanelExpansionStateManager(),
mNotificationRemoteInputManager,
- mControlsComponent);
+ mSysUIUnfoldComponent,
+ mControlsComponent,
+ mFeatureFlags);
mNotificationPanelViewController.initDependencies(
mStatusBar,
() -> {},
mNotificationShelfController);
mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
- mNotificationPanelViewController.setBar(mPanelBar);
mNotificationPanelViewController.setKeyguardIndicationController(
mKeyguardIndicationController);
ArgumentCaptor<View.OnAttachStateChangeListener> onAttachStateChangeListenerArgumentCaptor =
@@ -517,46 +523,50 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
}
@Test
- public void onTouchForwardedFromStatusBar_panelsNotEnabled_returnsFalseAndNoViewEvent() {
+ public void handleTouchEventFromStatusBar_panelsNotEnabled_returnsFalseAndNoViewEvent() {
when(mCommandQueue.panelsEnabled()).thenReturn(false);
- boolean returnVal = mTouchHandler.onTouchForwardedFromStatusBar(
- MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0));
+ boolean returnVal = mNotificationPanelViewController
+ .getStatusBarTouchEventHandler()
+ .handleTouchEvent(
+ MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0));
assertThat(returnVal).isFalse();
verify(mView, never()).dispatchTouchEvent(any());
}
@Test
- public void onTouchForwardedFromStatusBar_viewNotEnabled_returnsTrueAndNoViewEvent() {
+ public void handleTouchEventFromStatusBar_viewNotEnabled_returnsTrueAndNoViewEvent() {
when(mCommandQueue.panelsEnabled()).thenReturn(true);
when(mView.isEnabled()).thenReturn(false);
- boolean returnVal = mTouchHandler.onTouchForwardedFromStatusBar(
- MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0));
+ boolean returnVal = mNotificationPanelViewController
+ .getStatusBarTouchEventHandler()
+ .handleTouchEvent(
+ MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0));
assertThat(returnVal).isTrue();
verify(mView, never()).dispatchTouchEvent(any());
}
@Test
- public void onTouchForwardedFromStatusBar_viewNotEnabledButIsMoveEvent_viewReceivesEvent() {
+ public void handleTouchEventFromStatusBar_viewNotEnabledButIsMoveEvent_viewReceivesEvent() {
when(mCommandQueue.panelsEnabled()).thenReturn(true);
when(mView.isEnabled()).thenReturn(false);
MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0);
- mTouchHandler.onTouchForwardedFromStatusBar(event);
+ mNotificationPanelViewController.getStatusBarTouchEventHandler().handleTouchEvent(event);
verify(mView).dispatchTouchEvent(event);
}
@Test
- public void onTouchForwardedFromStatusBar_panelAndViewEnabled_viewReceivesEvent() {
+ public void handleTouchEventFromStatusBar_panelAndViewEnabled_viewReceivesEvent() {
when(mCommandQueue.panelsEnabled()).thenReturn(true);
when(mView.isEnabled()).thenReturn(true);
MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0);
- mTouchHandler.onTouchForwardedFromStatusBar(event);
+ mNotificationPanelViewController.getStatusBarTouchEventHandler().handleTouchEvent(event);
verify(mView).dispatchTouchEvent(event);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
index 6e9bb2d30ed3..1adba6e64c6d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
@@ -52,7 +52,9 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.systemui.tuner.TunerService;
import org.junit.Before;
@@ -90,7 +92,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
@Mock private NotificationPanelViewController mNotificationPanelViewController;
@Mock private NotificationStackScrollLayout mNotificationStackScrollLayout;
@Mock private NotificationShadeDepthController mNotificationShadeDepthController;
- @Mock private StatusBarWindowView mStatusBarWindowView;
+ @Mock private StatusBarWindowController mStatusBarWindowController;
@Mock private NotificationShadeWindowController mNotificationShadeWindowController;
@Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -135,7 +137,8 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
mNotificationShadeDepthController,
mView,
mNotificationPanelViewController,
- mStatusBarWindowView,
+ new PanelExpansionStateManager(),
+ mStatusBarWindowController,
mNotificationStackScrollLayoutController,
mStatusBarKeyguardViewManager,
mLockIconViewController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index 310a8baadb78..dc320076a668 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -26,6 +26,7 @@ import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.unfold.SysUIUnfoldComponent
import com.android.systemui.unfold.config.UnfoldTransitionConfig
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
import com.android.systemui.util.mockito.any
@@ -39,6 +40,7 @@ import org.mockito.Mockito.mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import java.util.Optional
@SmallTest
class PhoneStatusBarViewControllerTest : SysuiTestCase() {
@@ -50,11 +52,10 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
@Mock
private lateinit var panelView: ViewGroup
@Mock
- private lateinit var scrimController: ScrimController
-
- @Mock
private lateinit var moveFromCenterAnimation: StatusBarMoveFromCenterAnimationController
@Mock
+ private lateinit var sysuiUnfoldComponent: SysUIUnfoldComponent
+ @Mock
private lateinit var progressProvider: ScopedUnfoldTransitionProgressProvider
private lateinit var view: PhoneStatusBarView
@@ -66,14 +67,13 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
fun setUp() {
MockitoAnnotations.initMocks(this)
`when`(panelViewController.view).thenReturn(panelView)
-
+ `when`(sysuiUnfoldComponent.getStatusBarMoveFromCenterAnimationController())
+ .thenReturn(moveFromCenterAnimation)
// create the view on main thread as it requires main looper
InstrumentationRegistry.getInstrumentation().runOnMainSync {
val parent = FrameLayout(mContext) // add parent to keep layout params
view = LayoutInflater.from(mContext)
.inflate(R.layout.status_bar, parent, false) as PhoneStatusBarView
- view.setScrimController(scrimController)
- view.setBar(mock(StatusBar::class.java))
}
controller = createController(view)
@@ -81,10 +81,13 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
@Test
fun constructor_setsTouchHandlerOnView() {
+ val interceptEvent = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 10f, 10f, 0)
val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
+ view.onInterceptTouchEvent(interceptEvent)
view.onTouchEvent(event)
+ assertThat(touchEventHandler.lastInterceptEvent).isEqualTo(interceptEvent)
assertThat(touchEventHandler.lastEvent).isEqualTo(event)
}
@@ -112,9 +115,8 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
private fun createController(view: PhoneStatusBarView): PhoneStatusBarViewController {
return PhoneStatusBarViewController.Factory(
- { progressProvider },
- { moveFromCenterAnimation },
- unfoldConfig
+ Optional.of(sysuiUnfoldComponent),
+ Optional.of(progressProvider)
).create(view, touchEventHandler)
}
@@ -125,6 +127,11 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
private class TestTouchEventHandler : PhoneStatusBarView.TouchEventHandler {
var lastEvent: MotionEvent? = null
+ var lastInterceptEvent: MotionEvent? = null
+
+ override fun onInterceptTouchEvent(event: MotionEvent?) {
+ lastInterceptEvent = event
+ }
override fun handleTouchEvent(event: MotionEvent?): Boolean {
lastEvent = event
return false
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
index fe3490399e81..8d686ae94e79 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
@@ -34,10 +34,6 @@ class PhoneStatusBarViewTest : SysuiTestCase() {
private lateinit var panelViewController: PanelViewController
@Mock
private lateinit var panelView: ViewGroup
- @Mock
- private lateinit var scrimController: ScrimController
- @Mock
- private lateinit var statusBar: StatusBar
private lateinit var view: PhoneStatusBarView
@@ -49,72 +45,28 @@ class PhoneStatusBarViewTest : SysuiTestCase() {
`when`(panelViewController.view).thenReturn(panelView)
view = PhoneStatusBarView(mContext, null)
- view.setScrimController(scrimController)
- view.setBar(statusBar)
- }
-
- @Test
- fun panelExpansionChanged_expansionChangeListenerNotified() {
- val listener = TestExpansionChangedListener()
- view.setExpansionChangedListeners(listOf(listener))
- val fraction = 0.4f
- val isExpanded = true
-
- view.panelExpansionChanged(fraction, isExpanded)
-
- assertThat(listener.fraction).isEqualTo(fraction)
- assertThat(listener.isExpanded).isEqualTo(isExpanded)
- }
-
- @Test
- fun panelExpansionChanged_noListeners_noCrash() {
- view.panelExpansionChanged(1f, false)
- // No assert needed, just testing no crash
- }
-
- @Test
- fun panelStateChanged_toStateOpening_listenerNotified() {
- val listener = TestStateChangedListener()
- view.setPanelStateChangeListener(listener)
-
- view.panelExpansionChanged(0.5f, true)
-
- assertThat(listener.state).isEqualTo(PanelBar.STATE_OPENING)
}
@Test
- fun panelStateChanged_toStateOpen_listenerNotified() {
- val listener = TestStateChangedListener()
- view.setPanelStateChangeListener(listener)
-
- view.panelExpansionChanged(1f, true)
-
- assertThat(listener.state).isEqualTo(PanelBar.STATE_OPEN)
- }
-
- @Test
- fun panelStateChanged_toStateClosed_listenerNotified() {
- val listener = TestStateChangedListener()
- view.setPanelStateChangeListener(listener)
-
- // First, open the panel
- view.panelExpansionChanged(1f, true)
+ fun onTouchEvent_listenerNotified() {
+ val handler = TestTouchEventHandler()
+ view.setTouchEventHandler(handler)
- // Then, close it again
- view.panelExpansionChanged(0f, false)
+ val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
+ view.onTouchEvent(event)
- assertThat(listener.state).isEqualTo(PanelBar.STATE_CLOSED)
+ assertThat(handler.lastEvent).isEqualTo(event)
}
@Test
- fun onTouchEvent_listenerNotified() {
+ fun onInterceptTouchEvent_listenerNotified() {
val handler = TestTouchEventHandler()
view.setTouchEventHandler(handler)
val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
- view.onTouchEvent(event)
+ view.onInterceptTouchEvent(event)
- assertThat(handler.lastEvent).isEqualTo(event)
+ assertThat(handler.lastInterceptEvent).isEqualTo(event)
}
@Test
@@ -123,7 +75,7 @@ class PhoneStatusBarViewTest : SysuiTestCase() {
view.setTouchEventHandler(handler)
val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
- handler.returnValue = true
+ handler.handleTouchReturnValue = true
assertThat(view.onTouchEvent(event)).isTrue()
}
@@ -134,7 +86,7 @@ class PhoneStatusBarViewTest : SysuiTestCase() {
view.setTouchEventHandler(handler)
val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
- handler.returnValue = false
+ handler.handleTouchReturnValue = false
assertThat(view.onTouchEvent(event)).isFalse()
}
@@ -145,30 +97,18 @@ class PhoneStatusBarViewTest : SysuiTestCase() {
// No assert needed, just testing no crash
}
- private class TestExpansionChangedListener
- : StatusBar.ExpansionChangedListener {
- var fraction: Float = 0f
- var isExpanded: Boolean = false
-
- override fun onExpansionChanged(expansion: Float, expanded: Boolean) {
- this.fraction = expansion
- this.isExpanded = expanded
- }
- }
+ private class TestTouchEventHandler : PhoneStatusBarView.TouchEventHandler {
+ var lastInterceptEvent: MotionEvent? = null
+ var lastEvent: MotionEvent? = null
+ var handleTouchReturnValue: Boolean = false
- private class TestStateChangedListener : PanelBar.PanelStateChangeListener {
- var state: Int = 0
- override fun onStateChanged(state: Int) {
- this.state = state
+ override fun onInterceptTouchEvent(event: MotionEvent?) {
+ lastInterceptEvent = event
}
- }
- private class TestTouchEventHandler : PhoneStatusBarView.TouchEventHandler {
- var lastEvent: MotionEvent? = null
- var returnValue: Boolean = false
override fun handleTouchEvent(event: MotionEvent?): Boolean {
lastEvent = event
- return returnValue
+ return handleTouchReturnValue
}
}
}
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 6849dab1a19a..42f22063110e 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
@@ -55,6 +55,7 @@ import com.android.systemui.DejankUtils;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dock.DockManager;
import com.android.systemui.scrim.ScrimView;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -112,6 +113,10 @@ public class ScrimControllerTest extends SysuiTestCase {
private ConfigurationController mConfigurationController;
@Mock
private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+ // TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The
+ // event-dispatch-on-registration pattern caused some of these unit tests to fail.)
+ @Mock
+ private PanelExpansionStateManager mPanelExpansionStateManager;
private static class AnimatorListener implements Animator.AnimatorListener {
@@ -224,7 +229,8 @@ public class ScrimControllerTest extends SysuiTestCase {
mDozeParameters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder,
new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor,
mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()),
- mUnlockedScreenOffAnimationController);
+ mUnlockedScreenOffAnimationController,
+ mPanelExpansionStateManager);
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
mScrimController.setAnimatorListener(mAnimatorListener);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SplitShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SplitShadeHeaderControllerTest.kt
new file mode 100644
index 000000000000..0cf0bd300419
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SplitShadeHeaderControllerTest.kt
@@ -0,0 +1,88 @@
+package com.android.systemui.statusbar.phone
+
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import android.view.View
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.ShadeInterpolation
+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.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class SplitShadeHeaderControllerTest : SysuiTestCase() {
+
+ @Mock private lateinit var view: View
+ @Mock private lateinit var statusIcons: StatusIconContainer
+ @Mock private lateinit var statusBarIconController: StatusBarIconController
+ @Mock private lateinit var qsCarrierGroupController: QSCarrierGroupController
+ @Mock private lateinit var qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder
+ @Mock private lateinit var featureFlags: FeatureFlags
+ @Mock private lateinit var batteryMeterView: BatteryMeterView
+ @Mock private lateinit var batteryMeterViewController: BatteryMeterViewController
+
+ @JvmField @Rule val mockitoRule = MockitoJUnit.rule()
+ var viewVisibility = View.GONE
+
+ private lateinit var splitShadeHeaderController: SplitShadeHeaderController
+
+ @Before
+ fun setup() {
+ whenever<BatteryMeterView>(view.findViewById(R.id.batteryRemainingIcon))
+ .thenReturn(batteryMeterView)
+ whenever<StatusIconContainer>(view.findViewById(R.id.statusIcons)).thenReturn(statusIcons)
+ whenever(view.context).thenReturn(context)
+ whenever(statusIcons.context).thenReturn(context)
+ whenever(qsCarrierGroupControllerBuilder.setQSCarrierGroup(any()))
+ .thenReturn(qsCarrierGroupControllerBuilder)
+ whenever(qsCarrierGroupControllerBuilder.build()).thenReturn(qsCarrierGroupController)
+ whenever(view.setVisibility(anyInt())).then {
+ viewVisibility = it.arguments[0] as Int
+ null
+ }
+ whenever(view.visibility).thenAnswer { _ -> viewVisibility }
+ whenever(featureFlags.useCombinedQSHeaders()).thenReturn(false)
+ splitShadeHeaderController = SplitShadeHeaderController(view, statusBarIconController,
+ qsCarrierGroupControllerBuilder, featureFlags, batteryMeterViewController)
+ }
+
+ @Test
+ fun setVisible_onlyInSplitShade() {
+ splitShadeHeaderController.splitShadeMode = true
+ splitShadeHeaderController.shadeExpanded = true
+ assertThat(viewVisibility).isEqualTo(View.VISIBLE)
+
+ splitShadeHeaderController.splitShadeMode = false
+ assertThat(viewVisibility).isEqualTo(View.GONE)
+ }
+
+ @Test
+ fun updateListeners_registersWhenVisible() {
+ splitShadeHeaderController.splitShadeMode = true
+ splitShadeHeaderController.shadeExpanded = true
+ verify(qsCarrierGroupController).setListening(true)
+ verify(statusBarIconController).addIconGroup(any())
+ }
+
+ @Test
+ fun shadeExpandedFraction_updatesAlpha() {
+ splitShadeHeaderController.splitShadeMode = true
+ splitShadeHeaderController.shadeExpanded = true
+ splitShadeHeaderController.shadeExpandedFraction = 0.5f
+ verify(view).setAlpha(ShadeInterpolation.getContentAlpha(0.5f))
+ }
+} \ No newline at end of file
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
index 8555306bae04..0131293656e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java
@@ -36,6 +36,7 @@ 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.dump.DumpManager;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DisableFlagsLogger;
@@ -45,6 +46,8 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import org.junit.Before;
@@ -109,6 +112,8 @@ public class StatusBarCommandQueueCallbacksTest extends SysuiTestCase {
mStatusBarStateController,
mNotificationShadeWindowView,
mNotificationStackScrollLayoutController,
+ new StatusBarHideIconsForBouncerManager(
+ mCommandQueue, new FakeExecutor(new FakeSystemClock()), new DumpManager()),
mPowerManager,
mVibratorHelper,
Optional.of(mVibrator),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
index 1503af82545c..e86676b81f8e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
@@ -86,7 +86,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
screenBounds,
sbHeightPortrait,
minLeftPadding,
- minRightPadding)
+ minRightPadding,
+ isRtl,
+ dotWidth)
var chipBounds = getPrivacyChipBoundingRectForInsets(bounds, dotWidth, chipWidth, isRtl)
/* 1080 - 20 (rounded corner) - 30 (chip),
@@ -115,7 +117,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
screenBounds,
sbHeightLandscape,
minLeftPadding,
- minRightPadding)
+ minRightPadding,
+ isRtl,
+ dotWidth)
chipBounds = getPrivacyChipBoundingRectForInsets(bounds, dotWidth, chipWidth, isRtl)
/* 2160 - 20 (rounded corner) - 30 (chip),
@@ -146,6 +150,8 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
val sbHeightPortrait = 100
val sbHeightLandscape = 60
val currentRotation = ROTATION_NONE
+ val isRtl = false
+ val dotWidth = 10
`when`(dc.boundingRects).thenReturn(listOf(dcBounds))
@@ -164,7 +170,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
screenBounds,
sbHeightPortrait,
minLeftPadding,
- minRightPadding)
+ minRightPadding,
+ isRtl,
+ dotWidth)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -181,7 +189,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
screenBounds,
sbHeightLandscape,
minLeftPadding,
- minRightPadding)
+ minRightPadding,
+ isRtl,
+ dotWidth)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -200,7 +210,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
screenBounds,
sbHeightPortrait,
minLeftPadding,
- minRightPadding)
+ minRightPadding,
+ isRtl,
+ dotWidth)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -208,7 +220,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
targetRotation = ROTATION_SEASCAPE
expectedBounds = Rect(minLeftPadding,
0,
- screenBounds.height() - dcBounds.height(),
+ screenBounds.height() - dcBounds.height() - dotWidth,
sbHeightLandscape)
bounds = calculateInsetsForRotationWithRotatedResources(
@@ -218,7 +230,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
screenBounds,
sbHeightLandscape,
minLeftPadding,
- minRightPadding)
+ minRightPadding,
+ isRtl,
+ dotWidth)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
}
@@ -237,6 +251,8 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
val sbHeightPortrait = 100
val sbHeightLandscape = 60
val currentRotation = ROTATION_NONE
+ val isRtl = false
+ val dotWidth = 10
`when`(dc.boundingRects).thenReturn(listOf(dcBounds))
@@ -255,7 +271,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
screenBounds,
sbHeightPortrait,
minLeftPadding,
- minRightPadding)
+ minRightPadding,
+ isRtl,
+ dotWidth)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -272,7 +290,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
screenBounds,
sbHeightLandscape,
minLeftPadding,
- minRightPadding)
+ minRightPadding,
+ isRtl,
+ dotWidth)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
@@ -289,14 +309,16 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
screenBounds,
sbHeightPortrait,
minLeftPadding,
- minRightPadding)
+ minRightPadding,
+ isRtl,
+ dotWidth)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
targetRotation = ROTATION_SEASCAPE
expectedBounds = Rect(minLeftPadding,
0,
- screenBounds.height() - dcBounds.height(),
+ screenBounds.height() - dcBounds.height() - dotWidth,
sbHeightLandscape)
bounds = calculateInsetsForRotationWithRotatedResources(
@@ -306,7 +328,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
screenBounds,
sbHeightLandscape,
minLeftPadding,
- minRightPadding)
+ minRightPadding,
+ isRtl,
+ dotWidth)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
}
@@ -320,6 +344,8 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
val minRightPadding = 20
val sbHeightPortrait = 100
val sbHeightLandscape = 60
+ val isRtl = false
+ val dotWidth = 10
// THEN content insets should only use rounded corner padding
var targetRotation = ROTATION_NONE
@@ -335,7 +361,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
screenBounds,
sbHeightPortrait,
minLeftPadding,
- minRightPadding)
+ minRightPadding,
+ isRtl,
+ dotWidth)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
targetRotation = ROTATION_LANDSCAPE
@@ -351,7 +379,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
screenBounds,
sbHeightLandscape,
minLeftPadding,
- minRightPadding)
+ minRightPadding,
+ isRtl,
+ dotWidth)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
targetRotation = ROTATION_UPSIDE_DOWN
@@ -367,7 +397,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
screenBounds,
sbHeightPortrait,
minLeftPadding,
- minRightPadding)
+ minRightPadding,
+ isRtl,
+ dotWidth)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
targetRotation = ROTATION_LANDSCAPE
@@ -383,7 +415,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
screenBounds,
sbHeightLandscape,
minLeftPadding,
- minRightPadding)
+ minRightPadding,
+ isRtl,
+ dotWidth)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
}
@@ -397,6 +431,8 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
val sbHeightPortrait = 100
val sbHeightLandscape = 60
val currentRotation = ROTATION_NONE
+ val isRtl = false
+ val dotWidth = 10
`when`(dc.boundingRects).thenReturn(listOf(dcBounds))
@@ -414,7 +450,9 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
screenBounds,
sbHeightPortrait,
minLeftPadding,
- minRightPadding)
+ minRightPadding,
+ isRtl,
+ dotWidth)
assertRects(expectedBounds, bounds, currentRotation, targetRotation)
}
@@ -429,7 +467,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
screenBounds = Rect(0, 0, 1080, 2160),
displayUniqueId = "1"
)
- val firstDisplayInsets = provider.getStatusBarContentInsetsForRotation(ROTATION_NONE)
+ val firstDisplayInsets = provider.getStatusBarContentAreaForRotation(ROTATION_NONE)
givenDisplay(
screenBounds = Rect(0, 0, 800, 600),
displayUniqueId = "2"
@@ -437,7 +475,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
configurationController.onConfigurationChanged(configuration)
// WHEN: get insets on the second display
- val secondDisplayInsets = provider.getStatusBarContentInsetsForRotation(ROTATION_NONE)
+ val secondDisplayInsets = provider.getStatusBarContentAreaForRotation(ROTATION_NONE)
// THEN: insets are updated
assertThat(firstDisplayInsets).isNotEqualTo(secondDisplayInsets)
@@ -454,13 +492,13 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
displayUniqueId = "1"
)
val firstDisplayInsetsFirstCall = provider
- .getStatusBarContentInsetsForRotation(ROTATION_NONE)
+ .getStatusBarContentAreaForRotation(ROTATION_NONE)
givenDisplay(
screenBounds = Rect(0, 0, 800, 600),
displayUniqueId = "2"
)
configurationController.onConfigurationChanged(configuration)
- provider.getStatusBarContentInsetsForRotation(ROTATION_NONE)
+ provider.getStatusBarContentAreaForRotation(ROTATION_NONE)
givenDisplay(
screenBounds = Rect(0, 0, 1080, 2160),
displayUniqueId = "1"
@@ -469,7 +507,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
// WHEN: get insets on the first display again
val firstDisplayInsetsSecondCall = provider
- .getStatusBarContentInsetsForRotation(ROTATION_NONE)
+ .getStatusBarContentAreaForRotation(ROTATION_NONE)
// THEN: insets for the first and second calls for the first display are the same
assertThat(firstDisplayInsetsFirstCall).isEqualTo(firstDisplayInsetsSecondCall)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 3fcd0712079f..6f174cbe0021 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
@@ -44,13 +45,13 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
-import com.android.systemui.keyguard.FaceAuthScreenBrightnessController;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -60,10 +61,6 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.Optional;
-
-import dagger.Lazy;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -88,12 +85,12 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
@Mock
private SysuiStatusBarStateController mStatusBarStateController;
@Mock
+ private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock
private View mNotificationContainer;
@Mock
private KeyguardBypassController mBypassController;
@Mock
- private FaceAuthScreenBrightnessController mFaceAuthScreenBrightnessController;
- @Mock
private KeyguardBouncer.Factory mKeyguardBouncerFactory;
@Mock
private KeyguardMessageAreaController.Factory mKeyguardMessageAreaFactory;
@@ -102,9 +99,11 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
@Mock
private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@Mock
+ private StatusBarKeyguardViewManager.AlternateAuthInterceptor mAlternateAuthInterceptor;
+ @Mock
private KeyguardMessageArea mKeyguardMessageArea;
@Mock
- private Lazy<ShadeController> mShadeController;
+ private ShadeController mShadeController;
private WakefulnessLifecycle mWakefulnessLifecycle;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -128,21 +127,24 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
mLockPatternUtils,
mStatusBarStateController,
mock(ConfigurationController.class),
- mock(KeyguardUpdateMonitor.class),
+ mKeyguardUpdateMonitor,
mock(NavigationModeController.class),
mock(DockManager.class),
mock(NotificationShadeWindowController.class),
mKeyguardStateController,
- Optional.of(mFaceAuthScreenBrightnessController),
mock(NotificationMediaManager.class),
mKeyguardBouncerFactory,
mWakefulnessLifecycle,
mUnlockedScreenOffAnimationController,
mKeyguardMessageAreaFactory,
- mShadeController);
- mStatusBarKeyguardViewManager.registerStatusBar(mStatusBar,
- mNotificationPanelView, mBiometrucUnlockController,
- mNotificationContainer, mBypassController);
+ () -> mShadeController);
+ mStatusBarKeyguardViewManager.registerStatusBar(
+ mStatusBar,
+ mNotificationPanelView,
+ new PanelExpansionStateManager(),
+ mBiometrucUnlockController,
+ mNotificationContainer,
+ mBypassController);
mStatusBarKeyguardViewManager.show(null);
}
@@ -182,8 +184,10 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
public void onPanelExpansionChanged_neverHidesFullscreenBouncer() {
// TODO: StatusBar should not be here, mBouncer.isFullscreenBouncer() should do the same.
when(mStatusBar.isFullScreenUserSwitcherState()).thenReturn(true);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(0.5f /* expansion */,
- true /* tracking */);
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(
+ /* fraction= */ 0.5f,
+ /* expanded= */ false,
+ /* tracking= */ true);
verify(mBouncer).setExpansion(eq(KeyguardBouncer.EXPANSION_VISIBLE));
}
@@ -191,51 +195,67 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
public void onPanelExpansionChanged_neverHidesScrimmedBouncer() {
when(mBouncer.isShowing()).thenReturn(true);
when(mBouncer.isScrimmed()).thenReturn(true);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(0.5f /* expansion */,
- true /* tracking */);
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(
+ /* fraction= */ 0.5f,
+ /* expanded= */ false,
+ /* tracking= */ true);
verify(mBouncer).setExpansion(eq(KeyguardBouncer.EXPANSION_VISIBLE));
}
@Test
public void onPanelExpansionChanged_neverShowsDuringHintAnimation() {
when(mNotificationPanelView.isUnlockHintRunning()).thenReturn(true);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(0.5f /* expansion */,
- true /* tracking */);
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(
+ /* fraction= */ 0.5f,
+ /* expanded= */ false,
+ /* tracking= */ true);
verify(mBouncer).setExpansion(eq(KeyguardBouncer.EXPANSION_HIDDEN));
}
@Test
public void onPanelExpansionChanged_propagatesToBouncer() {
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(0.5f /* expansion */,
- true /* tracking */);
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(
+ /* fraction= */ 0.5f,
+ /* expanded= */ false,
+ /* tracking= */ true);
verify(mBouncer).setExpansion(eq(0.5f));
}
@Test
public void onPanelExpansionChanged_showsBouncerWhenSwiping() {
when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(0.5f /* expansion */,
- true /* tracking */);
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(
+ /* fraction= */ 0.5f,
+ /* expanded= */ false,
+ /* tracking= */ true);
verify(mBouncer).show(eq(false), eq(false));
// But not when it's already visible
reset(mBouncer);
when(mBouncer.isShowing()).thenReturn(true);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(0.5f /* expansion */, true /* tracking */);
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(
+ /* fraction= */ 0.5f,
+ /* expanded= */ false,
+ /* tracking= */ true);
verify(mBouncer, never()).show(eq(false), eq(false));
// Or animating away
reset(mBouncer);
when(mBouncer.isAnimatingAway()).thenReturn(true);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(0.5f /* expansion */, true /* tracking */);
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(
+ /* fraction= */ 0.5f,
+ /* expanded= */ false,
+ /* tracking= */ true);
verify(mBouncer, never()).show(eq(false), eq(false));
}
@Test
public void onPanelExpansionChanged_neverTranslatesBouncerWhenOccluded() {
mStatusBarKeyguardViewManager.setOccluded(true /* occluded */, false /* animate */);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(0.5f /* expansion */,
- true /* tracking */);
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(
+ /* fraction= */ 0.5f,
+ /* expanded= */ false,
+ /* tracking= */ true);
verify(mBouncer, never()).setExpansion(eq(0.5f));
}
@@ -243,16 +263,20 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
public void onPanelExpansionChanged_neverTranslatesBouncerWhenWakeAndUnlock() {
when(mBiometrucUnlockController.getMode())
.thenReturn(BiometricUnlockController.MODE_WAKE_AND_UNLOCK);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(KeyguardBouncer.EXPANSION_VISIBLE,
- false /* tracking */);
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(
+ /* fraction= */ KeyguardBouncer.EXPANSION_VISIBLE,
+ /* expanded= */ true,
+ /* tracking= */ false);
verify(mBouncer, never()).setExpansion(anyFloat());
}
@Test
public void onPanelExpansionChanged_neverTranslatesBouncerWhenLaunchingApp() {
when(mStatusBar.isInLaunchTransition()).thenReturn(true);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(KeyguardBouncer.EXPANSION_VISIBLE,
- false /* tracking */);
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(
+ /* fraction= */ KeyguardBouncer.EXPANSION_VISIBLE,
+ /* expanded= */ true,
+ /* tracking= */ false);
verify(mBouncer, never()).setExpansion(anyFloat());
}
@@ -268,6 +292,45 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
}
@Test
+ public void setOccluded_onKeyguardOccludedChangedCalledCorrectly() {
+ mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, false /* animated */);
+ verify(mKeyguardUpdateMonitor).onKeyguardOccludedChanged(false);
+
+ clearInvocations(mKeyguardUpdateMonitor);
+
+ mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, false /* animated */);
+ verify(mKeyguardUpdateMonitor, never()).onKeyguardOccludedChanged(anyBoolean());
+
+ clearInvocations(mKeyguardUpdateMonitor);
+
+ mStatusBarKeyguardViewManager.setOccluded(true /* occluded */, false /* animated */);
+ verify(mKeyguardUpdateMonitor).onKeyguardOccludedChanged(true);
+
+ clearInvocations(mKeyguardUpdateMonitor);
+
+ mStatusBarKeyguardViewManager.setOccluded(true /* occluded */, false /* animated */);
+ verify(mKeyguardUpdateMonitor, never()).onKeyguardOccludedChanged(anyBoolean());
+ }
+
+ @Test
+ public void setOccluded_isInLaunchTransition_onKeyguardOccludedChangedCalled() {
+ when(mStatusBar.isInLaunchTransition()).thenReturn(true);
+ mStatusBarKeyguardViewManager.show(null);
+
+ mStatusBarKeyguardViewManager.setOccluded(true /* occluded */, false /* animated */);
+ verify(mKeyguardUpdateMonitor).onKeyguardOccludedChanged(true);
+ }
+
+ @Test
+ public void setOccluded_isLaunchingActivityOverLockscreen_onKeyguardOccludedChangedCalled() {
+ when(mStatusBar.isLaunchingActivityOverLockscreen()).thenReturn(true);
+ mStatusBarKeyguardViewManager.show(null);
+
+ mStatusBarKeyguardViewManager.setOccluded(true /* occluded */, false /* animated */);
+ verify(mKeyguardUpdateMonitor).onKeyguardOccludedChanged(true);
+ }
+
+ @Test
public void testHiding_cancelsGoneRunnable() {
OnDismissAction action = mock(OnDismissAction.class);
Runnable cancelAction = mock(Runnable.class);
@@ -293,6 +356,24 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
}
@Test
+ public void testShowing_whenAlternateAuthShowing() {
+ mStatusBarKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor);
+ when(mBouncer.isShowing()).thenReturn(false);
+ when(mAlternateAuthInterceptor.isShowingAlternateAuthBouncer()).thenReturn(true);
+ assertTrue("Is showing not accurate when alternative auth showing",
+ mStatusBarKeyguardViewManager.isShowing());
+ }
+
+ @Test
+ public void testWillBeShowing_whenAlternateAuthShowing() {
+ mStatusBarKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor);
+ when(mBouncer.isShowing()).thenReturn(false);
+ when(mAlternateAuthInterceptor.isShowingAlternateAuthBouncer()).thenReturn(true);
+ assertTrue("Is or will be showing not accurate when alternative auth showing",
+ mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing());
+ }
+
+ @Test
public void testUpdateResources_delegatesToBouncer() {
mStatusBarKeyguardViewManager.updateResources();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index c80c07249cc5..4e6b0a26609b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -37,6 +37,7 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.ForegroundServiceNotificationListener;
import com.android.systemui.InitController;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -51,6 +52,7 @@ import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -109,12 +111,15 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase {
mock(DozeScrimController.class), mock(ScrimController.class),
mock(NotificationShadeWindowController.class), mock(DynamicPrivacyController.class),
mock(KeyguardStateController.class),
- mock(KeyguardIndicationController.class), mStatusBar,
+ mock(KeyguardIndicationController.class),
+ mock(FeatureFlags.class),
+ mStatusBar,
mock(ShadeControllerImpl.class), mock(LockscreenShadeTransitionController.class),
mCommandQueue,
mock(NotificationViewHierarchyManager.class),
mock(NotificationLockscreenUserManager.class),
mock(SysuiStatusBarStateController.class),
+ mock(NotifShadeEventSource.class),
mock(NotificationEntryManager.class),
mock(NotificationMediaManager.class),
mock(NotificationGutsManager.class),
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 943d3c79984d..bd87a5021f8b 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
@@ -78,7 +78,6 @@ import com.android.systemui.InitController;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.ActivityLaunchAnimator;
-import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollectorFake;
@@ -96,7 +95,7 @@ import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
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.settings.brightness.BrightnessSliderController;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -121,6 +120,7 @@ import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
@@ -132,6 +132,7 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -140,11 +141,8 @@ import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.systemui.tuner.TunerService;
-import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
-import com.android.systemui.unfold.UnfoldTransitionWallpaperController;
-import com.android.systemui.unfold.config.UnfoldTransitionConfig;
-import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider;
import com.android.systemui.util.WallpaperController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.concurrency.MessageRouterImpl;
@@ -210,6 +208,7 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private NotificationShadeWindowView mNotificationShadeWindowView;
@Mock private BroadcastDispatcher mBroadcastDispatcher;
@Mock private AssistManager mAssistManager;
+ @Mock private NotifShadeEventSource mNotifShadeEventSource;
@Mock private NotificationEntryManager mNotificationEntryManager;
@Mock private NotificationGutsManager mNotificationGutsManager;
@Mock private NotificationMediaManager mNotificationMediaManager;
@@ -222,6 +221,7 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private KeyguardBypassController mKeyguardBypassController;
@Mock private DynamicPrivacyController mDynamicPrivacyController;
@Mock private AutoHideController mAutoHideController;
+ @Mock private StatusBarWindowController mStatusBarWindowController;
@Mock private NotificationViewHierarchyManager mNotificationViewHierarchyManager;
@Mock private UserSwitcherController mUserSwitcherController;
@Mock private NetworkController mNetworkController;
@@ -243,7 +243,6 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private StatusBarComponent mStatusBarComponent;
@Mock private PluginManager mPluginManager;
@Mock private LegacySplitScreen mLegacySplitScreen;
- @Mock private StatusBarWindowView mStatusBarWindowView;
@Mock private LightsOutNotifController mLightsOutNotifController;
@Mock private ViewMediatorCallback mViewMediatorCallback;
@Mock private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
@@ -257,11 +256,7 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private PhoneStatusBarPolicy mPhoneStatusBarPolicy;
@Mock private DemoModeController mDemoModeController;
@Mock private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
- @Mock private BrightnessSlider.Factory mBrightnessSliderFactory;
- @Mock private UnfoldTransitionConfig mUnfoldTransitionConfig;
- @Mock private Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealOverlayAnimationLazy;
- @Mock private Lazy<NaturalRotationUnfoldProgressProvider> mNaturalRotationProgressProvider;
- @Mock private Lazy<UnfoldTransitionWallpaperController> mUnfoldWallpaperController;
+ @Mock private BrightnessSliderController.Factory mBrightnessSliderFactory;
@Mock private WallpaperController mWallpaperController;
@Mock private OngoingCallController mOngoingCallController;
@Mock private SystemStatusAnimationScheduler mAnimationScheduler;
@@ -279,12 +274,12 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
@Mock private PhoneStatusBarViewController.Factory mPhoneStatusBarViewControllerFactory;
@Mock private ActivityLaunchAnimator mActivityLaunchAnimator;
- @Mock private DialogLaunchAnimator mDialogLaunchAnimator;
private ShadeController mShadeController;
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
private FakeExecutor mUiBgExecutor = new FakeExecutor(mFakeSystemClock);
private InitController mInitController = new InitController();
+ private final DumpManager mDumpManager = new DumpManager();
@Before
public void setup() throws Exception {
@@ -338,7 +333,7 @@ public class StatusBarTest extends SysuiTestCase {
}).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());
WakefulnessLifecycle wakefulnessLifecycle =
- new WakefulnessLifecycle(mContext, mIWallpaperManager, mock(DumpManager.class));
+ new WakefulnessLifecycle(mContext, mIWallpaperManager, mDumpManager);
wakefulnessLifecycle.dispatchStartedWakingUp(PowerManager.WAKE_REASON_UNKNOWN);
wakefulnessLifecycle.dispatchFinishedWakingUp();
@@ -366,6 +361,7 @@ public class StatusBarTest extends SysuiTestCase {
mNotificationsController,
mLightBarController,
mAutoHideController,
+ mStatusBarWindowController,
mKeyguardUpdateMonitor,
mPulseExpansionHandler,
mNotificationWakeUpCoordinator,
@@ -377,11 +373,13 @@ public class StatusBarTest extends SysuiTestCase {
new FalsingManagerFake(),
new FalsingCollectorFake(),
mBroadcastDispatcher,
+ mNotifShadeEventSource,
mNotificationEntryManager,
mNotificationGutsManager,
notificationLogger,
mNotificationInterruptStateProvider,
mNotificationViewHierarchyManager,
+ new PanelExpansionStateManager(),
mKeyguardViewMediator,
new DisplayMetrics(),
mMetricsLogger,
@@ -393,7 +391,7 @@ public class StatusBarTest extends SysuiTestCase {
mNetworkController,
mBatteryController,
mColorExtractor,
- new ScreenLifecycle(mock(DumpManager.class)),
+ new ScreenLifecycle(mDumpManager),
wakefulnessLifecycle,
mStatusBarStateController,
Optional.of(mBubblesManager),
@@ -421,7 +419,6 @@ public class StatusBarTest extends SysuiTestCase {
mLightsOutNotifController,
mStatusBarNotificationActivityStarterBuilder,
mShadeController,
- mStatusBarWindowView,
mStatusBarKeyguardViewManager,
mViewMediatorCallback,
mInitController,
@@ -439,15 +436,12 @@ public class StatusBarTest extends SysuiTestCase {
mStatusBarTouchableRegionManager,
mNotificationIconAreaController,
mBrightnessSliderFactory,
- mUnfoldTransitionConfig,
- mUnfoldLightRevealOverlayAnimationLazy,
- mUnfoldWallpaperController,
- mNaturalRotationProgressProvider,
mWallpaperController,
mOngoingCallController,
mAnimationScheduler,
mLocationPublisher,
mIconController,
+ new StatusBarHideIconsForBouncerManager(mCommandQueue, mMainExecutor, mDumpManager),
mLockscreenTransitionController,
mFeatureFlags,
mKeyguardUnlockAnimationController,
@@ -458,12 +452,15 @@ public class StatusBarTest extends SysuiTestCase {
mUnlockedScreenOffAnimationController,
Optional.of(mStartingSurface),
mTunerService,
- mock(DumpManager.class),
- mActivityLaunchAnimator,
- mDialogLaunchAnimator);
- when(mKeyguardViewMediator.registerStatusBar(any(StatusBar.class),
- any(NotificationPanelViewController.class), any(BiometricUnlockController.class),
- any(ViewGroup.class), any(KeyguardBypassController.class)))
+ mDumpManager,
+ mActivityLaunchAnimator);
+ when(mKeyguardViewMediator.registerStatusBar(
+ any(StatusBar.class),
+ any(NotificationPanelViewController.class),
+ any(PanelExpansionStateManager.class),
+ any(BiometricUnlockController.class),
+ any(ViewGroup.class),
+ any(KeyguardBypassController.class)))
.thenReturn(mStatusBarKeyguardViewManager);
when(mKeyguardViewMediator.getViewMediatorCallback()).thenReturn(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
new file mode 100644
index 000000000000..a8a33dabf1aa
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
@@ -0,0 +1,92 @@
+/*
+ * 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 android.animation.Animator
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.keyguard.KeyguardViewMediator
+import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.statusbar.LightRevealScrim
+import com.android.systemui.statusbar.StatusBarStateControllerImpl
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.settings.GlobalSettings
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.spy
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
+class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() {
+
+ private lateinit var controller: UnlockedScreenOffAnimationController
+ @Mock
+ private lateinit var keyguardViewMediator: KeyguardViewMediator
+ @Mock
+ private lateinit var dozeParameters: DozeParameters
+ @Mock
+ private lateinit var keyguardStateController: KeyguardStateController
+ @Mock
+ private lateinit var globalSettings: GlobalSettings
+ @Mock
+ private lateinit var statusbar: StatusBar
+ @Mock
+ private lateinit var lightRevealScrim: LightRevealScrim
+ @Mock
+ private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
+ @Mock
+ private lateinit var statusBarStateController: StatusBarStateControllerImpl
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ controller = UnlockedScreenOffAnimationController(
+ context,
+ wakefulnessLifecycle,
+ statusBarStateController,
+ dagger.Lazy<KeyguardViewMediator> { keyguardViewMediator },
+ keyguardStateController,
+ dagger.Lazy<DozeParameters> { dozeParameters },
+ globalSettings
+ )
+ controller.initialize(statusbar, lightRevealScrim)
+ }
+
+ @Test
+ fun testAnimClearsEndListener() {
+ val keyguardView = View(context)
+ val animator = spy(keyguardView.animate())
+ val keyguardSpy = spy(keyguardView)
+ Mockito.`when`(keyguardSpy.animate()).thenReturn(animator)
+ val listener = ArgumentCaptor.forClass(Animator.AnimatorListener::class.java)
+ controller.animateInKeyguard(keyguardSpy, Runnable {})
+ Mockito.verify(animator).setListener(listener.capture())
+ // Verify that the listener is cleared when it ends
+ listener.value.onAnimationEnd(null)
+ Mockito.verify(animator).setListener(null)
+ }
+} \ No newline at end of file
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 3d2ff47e3cdd..b385b7d62cff 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
@@ -42,7 +42,7 @@ 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
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
-import com.android.systemui.statusbar.phone.StatusBarWindowController
+import com.android.systemui.statusbar.window.StatusBarWindowController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.time.FakeSystemClock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManagerTest.kt
new file mode 100644
index 000000000000..32bad5c084f5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManagerTest.kt
@@ -0,0 +1,213 @@
+/*
+ * 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.panelstate
+
+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 PanelExpansionStateManagerTest : SysuiTestCase() {
+
+ private lateinit var panelExpansionStateManager: PanelExpansionStateManager
+
+ @Before
+ fun setUp() {
+ panelExpansionStateManager = PanelExpansionStateManager()
+ }
+
+ @Test
+ fun onPanelExpansionChanged_listenerNotified() {
+ val listener = TestPanelExpansionListener()
+ panelExpansionStateManager.addExpansionListener(listener)
+ val fraction = 0.6f
+ val expanded = true
+ val tracking = true
+
+ panelExpansionStateManager.onPanelExpansionChanged(fraction, expanded, tracking)
+
+ assertThat(listener.fraction).isEqualTo(fraction)
+ assertThat(listener.expanded).isEqualTo(expanded)
+ assertThat(listener.tracking).isEqualTo(tracking)
+ }
+
+ @Test
+ fun addExpansionListener_listenerNotifiedOfCurrentValues() {
+ val fraction = 0.6f
+ val expanded = true
+ val tracking = true
+ panelExpansionStateManager.onPanelExpansionChanged(fraction, expanded, tracking)
+ val listener = TestPanelExpansionListener()
+
+ panelExpansionStateManager.addExpansionListener(listener)
+
+ assertThat(listener.fraction).isEqualTo(fraction)
+ assertThat(listener.expanded).isEqualTo(expanded)
+ assertThat(listener.tracking).isEqualTo(tracking)
+ }
+
+ @Test
+ fun updateState_listenerNotified() {
+ val listener = TestPanelStateListener()
+ panelExpansionStateManager.addStateListener(listener)
+
+ panelExpansionStateManager.updateState(STATE_OPEN)
+
+ assertThat(listener.state).isEqualTo(STATE_OPEN)
+ }
+
+ /* ***** [PanelExpansionStateManager.onPanelExpansionChanged] test cases *******/
+
+ /* Fraction < 1 test cases */
+
+ @Test
+ fun onPEC_fractionLessThanOne_expandedTrue_trackingFalse_becomesStateOpening() {
+ val listener = TestPanelStateListener()
+ panelExpansionStateManager.addStateListener(listener)
+
+ panelExpansionStateManager.onPanelExpansionChanged(
+ fraction = 0.5f, expanded = true, tracking = false
+ )
+
+ assertThat(listener.state).isEqualTo(STATE_OPENING)
+ }
+
+ @Test
+ fun onPEC_fractionLessThanOne_expandedTrue_trackingTrue_becomesStateOpening() {
+ val listener = TestPanelStateListener()
+ panelExpansionStateManager.addStateListener(listener)
+
+ panelExpansionStateManager.onPanelExpansionChanged(
+ fraction = 0.5f, expanded = true, tracking = true
+ )
+
+ assertThat(listener.state).isEqualTo(STATE_OPENING)
+ }
+
+ @Test
+ fun onPEC_fractionLessThanOne_expandedFalse_trackingFalse_becomesStateClosed() {
+ val listener = TestPanelStateListener()
+ panelExpansionStateManager.addStateListener(listener)
+ // Start out on a different state
+ panelExpansionStateManager.updateState(STATE_OPEN)
+
+ panelExpansionStateManager.onPanelExpansionChanged(
+ fraction = 0.5f, expanded = false, tracking = false
+ )
+
+ assertThat(listener.state).isEqualTo(STATE_CLOSED)
+ }
+
+ @Test
+ fun onPEC_fractionLessThanOne_expandedFalse_trackingTrue_doesNotBecomeStateClosed() {
+ val listener = TestPanelStateListener()
+ panelExpansionStateManager.addStateListener(listener)
+ // Start out on a different state
+ panelExpansionStateManager.updateState(STATE_OPEN)
+
+ panelExpansionStateManager.onPanelExpansionChanged(
+ fraction = 0.5f, expanded = false, tracking = true
+ )
+
+ assertThat(listener.state).isEqualTo(STATE_OPEN)
+ }
+
+ /* Fraction = 1 test cases */
+
+ @Test
+ fun onPEC_fractionOne_expandedTrue_trackingFalse_becomesStateOpeningThenStateOpen() {
+ val listener = TestPanelStateListener()
+ panelExpansionStateManager.addStateListener(listener)
+
+ panelExpansionStateManager.onPanelExpansionChanged(
+ fraction = 1f, expanded = true, tracking = false
+ )
+
+ assertThat(listener.previousState).isEqualTo(STATE_OPENING)
+ assertThat(listener.state).isEqualTo(STATE_OPEN)
+ }
+
+ @Test
+ fun onPEC_fractionOne_expandedTrue_trackingTrue_becomesStateOpening() {
+ val listener = TestPanelStateListener()
+ panelExpansionStateManager.addStateListener(listener)
+
+ panelExpansionStateManager.onPanelExpansionChanged(
+ fraction = 1f, expanded = true, tracking = true
+ )
+
+ assertThat(listener.state).isEqualTo(STATE_OPENING)
+ }
+
+ @Test
+ fun onPEC_fractionOne_expandedFalse_trackingFalse_becomesStateClosed() {
+ val listener = TestPanelStateListener()
+ panelExpansionStateManager.addStateListener(listener)
+ // Start out on a different state
+ panelExpansionStateManager.updateState(STATE_OPEN)
+
+ panelExpansionStateManager.onPanelExpansionChanged(
+ fraction = 1f, expanded = false, tracking = false
+ )
+
+ assertThat(listener.state).isEqualTo(STATE_CLOSED)
+ }
+
+ @Test
+ fun onPEC_fractionOne_expandedFalse_trackingTrue_doesNotBecomeStateClosed() {
+ val listener = TestPanelStateListener()
+ panelExpansionStateManager.addStateListener(listener)
+ // Start out on a different state
+ panelExpansionStateManager.updateState(STATE_OPEN)
+
+ panelExpansionStateManager.onPanelExpansionChanged(
+ fraction = 1f, expanded = false, tracking = true
+ )
+
+ assertThat(listener.state).isEqualTo(STATE_OPEN)
+ }
+
+ /* ***** end [PanelExpansionStateManager.onPanelExpansionChanged] test cases ******/
+
+ class TestPanelExpansionListener : PanelExpansionListener {
+ var fraction: Float = 0f
+ var expanded: Boolean = false
+ var tracking: Boolean = false
+
+ override fun onPanelExpansionChanged(
+ fraction: Float,
+ expanded: Boolean,
+ tracking: Boolean
+ ) {
+ this.fraction = fraction
+ this.expanded = expanded
+ this.tracking = tracking
+ }
+ }
+
+ class TestPanelStateListener : PanelStateListener {
+ @PanelState var previousState: Int = STATE_CLOSED
+ @PanelState var state: Int = STATE_CLOSED
+
+ override fun onPanelStateChanged(state: Int) {
+ this.previousState = this.state
+ this.state = state
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index dd8354dedafd..97e1edb9ac74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -205,7 +205,7 @@ public class RemoteInputViewTest extends SysuiTestCase {
ExpandableNotificationRow row = helper.createRow();
RemoteInputView view = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
- view.setOnVisibilityChangedListener(null);
+ view.addOnVisibilityChangedListener(null);
view.setVisibility(View.INVISIBLE);
view.setVisibility(View.VISIBLE);
}
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 f89bbe898e35..766471b9a695 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -152,7 +152,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
}
@Test
- public void onWallpaperColorsChanged_setsTheme() {
+ public void onWallpaperColorsChanged_setsTheme_whenForeground() {
// Should ask for a new theme when wallpaper colors change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
@@ -180,13 +180,43 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
// But should change theme after changing wallpapers
clearInvocations(mThemeOverlayApplier);
- mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED));
+ Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
+ intent.putExtra(WallpaperManager.EXTRA_FROM_FOREGROUND_APP, true);
+ mBroadcastReceiver.getValue().onReceive(null, intent);
mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK),
null, null), WallpaperManager.FLAG_SYSTEM);
verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
}
@Test
+ public void onWallpaperColorsChanged_setsTheme_skipWhenBackground() {
+ // Should ask for a new theme when wallpaper colors change
+ WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
+ Color.valueOf(Color.BLUE), null);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ ArgumentCaptor<Map<String, OverlayIdentifier>> themeOverlays =
+ ArgumentCaptor.forClass(Map.class);
+
+ verify(mThemeOverlayApplier)
+ .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any());
+
+ // Assert that we received the colors that we were expecting
+ assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
+ .isEqualTo(new OverlayIdentifier("ffff0000"));
+ assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_ACCENT_COLOR))
+ .isEqualTo(new OverlayIdentifier("ffff0000"));
+
+ // Should not change theme after changing wallpapers, if intent doesn't have
+ // WallpaperManager.EXTRA_FROM_FOREGROUND_APP set to true.
+ clearInvocations(mThemeOverlayApplier);
+ mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED));
+ mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK),
+ null, null), WallpaperManager.FLAG_SYSTEM);
+ verify(mThemeOverlayApplier, never())
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ }
+
+ @Test
public void onWallpaperColorsChanged_preservesWallpaperPickerTheme() {
// Should ask for a new theme when wallpaper colors change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
@@ -455,7 +485,9 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
// Regression test: null events should not reset the internal state and allow colors to be
// applied again.
clearInvocations(mThemeOverlayApplier);
- mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED));
+ Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
+ intent.putExtra(WallpaperManager.EXTRA_FROM_FOREGROUND_APP, true);
+ mBroadcastReceiver.getValue().onReceive(null, intent);
mColorsListener.getValue().onColorsChanged(null, WallpaperManager.FLAG_SYSTEM);
verify(mThemeOverlayApplier, never()).applyCurrentUserOverlays(any(), any(), anyInt(),
any());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/ListenerSetTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/ListenerSetTest.kt
new file mode 100644
index 000000000000..2662da201460
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/ListenerSetTest.kt
@@ -0,0 +1,135 @@
+/*
+ * 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
+
+import android.test.suitebuilder.annotation.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ListenerSetTest : SysuiTestCase() {
+
+ var runnableSet: ListenerSet<Runnable> = ListenerSet()
+
+ @Before
+ fun setup() {
+ runnableSet = ListenerSet()
+ }
+
+ @Test
+ fun addIfAbsent_doesNotDoubleAdd() {
+ // setup & preconditions
+ val runnable1 = Runnable { }
+ val runnable2 = Runnable { }
+ assertThat(runnableSet.toList()).isEmpty()
+
+ // Test that an element can be added
+ assertThat(runnableSet.addIfAbsent(runnable1)).isTrue()
+ assertThat(runnableSet.toList()).containsExactly(runnable1)
+
+ // Test that a second element can be added
+ assertThat(runnableSet.addIfAbsent(runnable2)).isTrue()
+ assertThat(runnableSet.toList()).containsExactly(runnable1, runnable2)
+
+ // Test that re-adding the first element does nothing and returns false
+ assertThat(runnableSet.addIfAbsent(runnable1)).isFalse()
+ assertThat(runnableSet.toList()).containsExactly(runnable1, runnable2)
+ }
+
+ @Test
+ fun remove_removesListener() {
+ // setup and preconditions
+ val runnable1 = Runnable { }
+ val runnable2 = Runnable { }
+ assertThat(runnableSet.toList()).isEmpty()
+ runnableSet.addIfAbsent(runnable1)
+ runnableSet.addIfAbsent(runnable2)
+ assertThat(runnableSet.toList()).containsExactly(runnable1, runnable2)
+
+ // Test that removing the first runnable only removes that one runnable
+ assertThat(runnableSet.remove(runnable1)).isTrue()
+ assertThat(runnableSet.toList()).containsExactly(runnable2)
+
+ // Test that removing a non-present runnable does not error
+ assertThat(runnableSet.remove(runnable1)).isFalse()
+ assertThat(runnableSet.toList()).containsExactly(runnable2)
+
+ // Test that removing the other runnable succeeds
+ assertThat(runnableSet.remove(runnable2)).isTrue()
+ assertThat(runnableSet.toList()).isEmpty()
+ }
+
+ @Test
+ fun remove_isReentrantSafe() {
+ // Setup and preconditions
+ val runnablesCalled = mutableListOf<Int>()
+ // runnable1 is configured to remove itself
+ val runnable1 = object : Runnable {
+ override fun run() {
+ runnableSet.remove(this)
+ runnablesCalled.add(1)
+ }
+ }
+ val runnable2 = Runnable {
+ runnablesCalled.add(2)
+ }
+ assertThat(runnableSet.toList()).isEmpty()
+ runnableSet.addIfAbsent(runnable1)
+ runnableSet.addIfAbsent(runnable2)
+ assertThat(runnableSet.toList()).containsExactly(runnable1, runnable2)
+
+ // Test that both runnables are called and 1 was removed
+ for (runnable in runnableSet) {
+ runnable.run()
+ }
+ assertThat(runnablesCalled).containsExactly(1, 2)
+ assertThat(runnableSet.toList()).containsExactly(runnable2)
+ }
+
+ @Test
+ fun addIfAbsent_isReentrantSafe() {
+ // Setup and preconditions
+ val runnablesCalled = mutableListOf<Int>()
+ val runnable99 = Runnable {
+ runnablesCalled.add(99)
+ }
+ // runnable1 is configured to add runnable99
+ val runnable1 = Runnable {
+ runnableSet.addIfAbsent(runnable99)
+ runnablesCalled.add(1)
+ }
+ val runnable2 = Runnable {
+ runnablesCalled.add(2)
+ }
+ assertThat(runnableSet.toList()).isEmpty()
+ runnableSet.addIfAbsent(runnable1)
+ runnableSet.addIfAbsent(runnable2)
+ assertThat(runnableSet.toList()).containsExactly(runnable1, runnable2)
+
+ // Test that both original runnables are called and 99 was added but not called
+ for (runnable in runnableSet) {
+ runnable.run()
+ }
+ assertThat(runnablesCalled).containsExactly(1, 2)
+ assertThat(runnableSet.toList()).containsExactly(runnable1, runnable2, runnable99)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt b/packages/SystemUI/tests/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
index bff99bf340d6..483dc9fc42b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
@@ -58,3 +58,24 @@ fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
*/
inline fun <reified T : Any> argumentCaptor(): ArgumentCaptor<T> =
ArgumentCaptor.forClass(T::class.java)
+
+/**
+ * Helper function for creating new mocks, without the need to pass in a [Class] instance.
+ *
+ * Generic T is nullable because implicitly bounded by Any?.
+ */
+inline fun <reified T : Any> mock(): T = Mockito.mock(T::class.java)
+
+/**
+ * Helper function for creating and using a single-use ArgumentCaptor in kotlin.
+ *
+ * val captor = argumentCaptor<Foo>()
+ * verify(...).someMethod(captor.capture())
+ * val captured = captor.value
+ *
+ * becomes:
+ *
+ * val captured = withArgCaptor<Foo> { verify(...).someMethod(capture()) }
+ */
+inline fun <reified T : Any> withArgCaptor(block: ArgumentCaptor<T>.() -> Unit): T =
+ argumentCaptor<T>().apply { block() }.value \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
index 8ea9da6f4d0e..33ef9cf7a9c5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
@@ -18,8 +18,9 @@ import android.os.Bundle;
import android.testing.LeakCheck;
import com.android.settingslib.net.DataUsageController;
+import com.android.systemui.statusbar.connectivity.AccessPointController;
import com.android.systemui.statusbar.connectivity.NetworkController;
-import com.android.systemui.statusbar.connectivity.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.connectivity.SignalCallback;
import com.android.systemui.statusbar.policy.DataSaverController;
public class FakeNetworkController extends BaseLeakChecker<SignalCallback>
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
index 5c0efd36fcd1..c9462d651bc0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
@@ -101,6 +101,11 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase {
// Initial non-set value
when(mRingerModeLiveData.getValue()).thenReturn(-1);
when(mRingerModeInternalLiveData.getValue()).thenReturn(-1);
+ // Enable group volume adjustments
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions,
+ true);
+
mCallback = mock(VolumeDialogControllerImpl.C.class);
mThreadFactory.setLooper(TestableLooper.get(this).getLooper());
mVolumeController = new TestableVolumeDialogControllerImpl(mContext,
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 1159e0912926..15a92dcf26b7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -185,6 +185,8 @@ public class BubblesTest extends SysuiTestCase {
private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
@Captor
private ArgumentCaptor<NotificationRemoveInterceptor> mRemoveInterceptorCaptor;
+ @Captor
+ private ArgumentCaptor<List<Bubble>> mBubbleListCaptor;
private BubblesManager mBubblesManager;
// TODO(178618782): Move tests on the controller directly to the shell
@@ -1165,6 +1167,22 @@ public class BubblesTest extends SysuiTestCase {
verify(mDataRepository, times(1)).loadBubbles(anyInt(), any());
}
+ /**
+ * Verifies that shortcut deletions triggers that bubble being removed from XML.
+ */
+ @Test
+ public void testDeleteShortcutsDeletesXml() throws Exception {
+ ExpandableNotificationRow row = mNotificationTestHelper.createShortcutBubble("shortcutId");
+ BubbleEntry shortcutBubbleEntry = BubblesManager.notifToBubbleEntry(row.getEntry());
+ mBubbleController.updateBubble(shortcutBubbleEntry);
+
+ mBubbleData.dismissBubbleWithKey(shortcutBubbleEntry.getKey(),
+ Bubbles.DISMISS_SHORTCUT_REMOVED);
+
+ verify(mDataRepository, atLeastOnce()).removeBubbles(anyInt(), mBubbleListCaptor.capture());
+ assertThat(mBubbleListCaptor.getValue().get(0).getKey()).isEqualTo(
+ shortcutBubbleEntry.getKey());
+ }
/**
* Verifies that the package manager for the user is used when loading info for the bubble.
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 05c4822f288e..43b181ed3ab9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -93,6 +93,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.bubbles.Bubble;
import com.android.wm.shell.bubbles.BubbleData;
import com.android.wm.shell.bubbles.BubbleDataRepository;
import com.android.wm.shell.bubbles.BubbleEntry;
@@ -167,6 +168,9 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
@Captor
private ArgumentCaptor<NotifCollectionListener> mNotifListenerCaptor;
+ @Captor
+ private ArgumentCaptor<List<Bubble>> mBubbleListCaptor;
+
private BubblesManager mBubblesManager;
private TestableBubbleController mBubbleController;
private NotificationShadeWindowControllerImpl mNotificationShadeWindowController;
@@ -1013,6 +1017,23 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
verify(mDataRepository, times(1)).loadBubbles(anyInt(), any());
}
+ /**
+ * Verifies that shortcut deletions triggers that bubble being removed from XML.
+ */
+ @Test
+ public void testDeleteShortcutsDeletesXml() throws Exception {
+ ExpandableNotificationRow row = mNotificationTestHelper.createShortcutBubble("shortcutId");
+ BubbleEntry shortcutBubbleEntry = BubblesManager.notifToBubbleEntry(row.getEntry());
+ mBubbleController.updateBubble(shortcutBubbleEntry);
+
+ mBubbleData.dismissBubbleWithKey(shortcutBubbleEntry.getKey(),
+ Bubbles.DISMISS_SHORTCUT_REMOVED);
+
+ verify(mDataRepository, atLeastOnce()).removeBubbles(anyInt(), mBubbleListCaptor.capture());
+ assertThat(mBubbleListCaptor.getValue().get(0).getKey()).isEqualTo(
+ shortcutBubbleEntry.getKey());
+ }
+
@Test
public void testShowManageMenuChangesSysuiState() {
mBubbleController.updateBubble(mBubbleEntry);
diff --git a/packages/services/CameraExtensionsProxy/AndroidManifest.xml b/packages/services/CameraExtensionsProxy/AndroidManifest.xml
index ef1d581d717e..79c9d13cd925 100644
--- a/packages/services/CameraExtensionsProxy/AndroidManifest.xml
+++ b/packages/services/CameraExtensionsProxy/AndroidManifest.xml
@@ -2,6 +2,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cameraextensions">
+ <queries>
+ <intent>
+ <action android:name="androidx.camera.extensions.action.VENDOR_ACTION" />
+ </intent>
+ </queries>
+
<application
android:label="@string/app_name"
android:defaultToDeviceProtectedStorage="true"
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
index 4946ad442b0a..1af8ad344190 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -187,7 +187,7 @@ public class AppPredictionPerUserService extends
@NonNull IPredictionCallback callback) {
final AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
if (sessionInfo == null) return;
- final boolean serviceExists = resolveService(sessionId, false,
+ final boolean serviceExists = resolveService(sessionId, true,
sessionInfo.mUsesPeopleService,
s -> s.registerPredictionUpdates(sessionId, callback));
if (serviceExists) {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 4748a86b79c6..7c1e2da4d6a3 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -457,6 +457,9 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
}, FgThread.getExecutor()).whenComplete(uncheckExceptions((association, err) -> {
if (err == null) {
addAssociation(association, userId);
+ mServiceConnectors.forUser(userId).post(service -> {
+ service.onAssociationCreated();
+ });
} else {
Slog.e(LOG_TAG, "Failed to discover device(s)", err);
callback.onFailure("No devices found: " + err.getMessage());
@@ -1448,8 +1451,12 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
}
void restartBleScan() {
- mBluetoothAdapter.getBluetoothLeScanner().stopScan(mBleScanCallback);
- startBleScan();
+ if (mBluetoothAdapter.getBluetoothLeScanner() != null) {
+ mBluetoothAdapter.getBluetoothLeScanner().stopScan(mBleScanCallback);
+ startBleScan();
+ } else {
+ Slog.w(LOG_TAG, "BluetoothLeScanner is null (likely BLE isn't ON yet).");
+ }
}
private List<ScanFilter> getBleScanFilters() {
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 8a42ddfdc19d..61d784ecb5f3 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -223,7 +223,7 @@ public final class ContentCaptureManagerService extends
@Override // from AbstractMasterSystemService
protected ContentCapturePerUserService newServiceLocked(@UserIdInt int resolvedUserId,
boolean disabled) {
- return new ContentCapturePerUserService(this, mLock, disabled, resolvedUserId);
+ return new ContentCapturePerUserService(this, mLock, disabled, resolvedUserId, mHandler);
}
@Override // from SystemService
@@ -1072,26 +1072,18 @@ public final class ContentCaptureManagerService extends
ParcelFileDescriptor sourceOut = servicePipe.second;
ParcelFileDescriptor sinkOut = servicePipe.first;
- mParentService.mPackagesWithShareRequests.add(mDataShareRequest.getPackageName());
-
- try {
- mClientAdapter.write(sourceIn);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to call write() the client operation", e);
- sendErrorSignal(mClientAdapter, serviceAdapter,
- ContentCaptureManager.DATA_SHARE_ERROR_UNKNOWN);
- logServiceEvent(
- CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_CLIENT_PIPE_FAIL);
- return;
+ synchronized (mParentService.mLock) {
+ mParentService.mPackagesWithShareRequests.add(mDataShareRequest.getPackageName());
}
- try {
- serviceAdapter.start(sinkOut);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to call start() the service operation", e);
+
+ if (!setUpSharingPipeline(mClientAdapter, serviceAdapter, sourceIn, sinkOut)) {
sendErrorSignal(mClientAdapter, serviceAdapter,
ContentCaptureManager.DATA_SHARE_ERROR_UNKNOWN);
- logServiceEvent(
- CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_SERVICE_PIPE_FAIL);
+ bestEffortCloseFileDescriptors(sourceIn, sinkIn, sourceOut, sinkOut);
+ synchronized (mParentService.mLock) {
+ mParentService.mPackagesWithShareRequests
+ .remove(mDataShareRequest.getPackageName());
+ }
return;
}
@@ -1184,6 +1176,32 @@ public final class ContentCaptureManagerService extends
}
}
+ private boolean setUpSharingPipeline(
+ IDataShareWriteAdapter clientAdapter,
+ IDataShareReadAdapter serviceAdapter,
+ ParcelFileDescriptor sourceIn,
+ ParcelFileDescriptor sinkOut) {
+ try {
+ clientAdapter.write(sourceIn);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to call write() the client operation", e);
+ logServiceEvent(
+ CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_CLIENT_PIPE_FAIL);
+ return false;
+ }
+
+ try {
+ serviceAdapter.start(sinkOut);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to call start() the service operation", e);
+ logServiceEvent(
+ CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_SERVICE_PIPE_FAIL);
+ return false;
+ }
+
+ return true;
+ }
+
private void enforceDataSharingTtl(ParcelFileDescriptor sourceIn,
ParcelFileDescriptor sinkIn,
ParcelFileDescriptor sourceOut,
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index 6bd1fa6c335d..822a42bf50cf 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -46,6 +46,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
import android.os.Binder;
import android.os.Bundle;
+import android.os.Handler;
import android.os.IBinder;
import android.os.UserHandle;
import android.provider.Settings;
@@ -75,6 +76,7 @@ import com.android.server.contentcapture.RemoteContentCaptureService.ContentCapt
import com.android.server.infra.AbstractPerUserSystemService;
import java.io.PrintWriter;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
@@ -88,6 +90,10 @@ final class ContentCapturePerUserService
private static final String TAG = ContentCapturePerUserService.class.getSimpleName();
+ private static final int MAX_REBIND_COUNTS = 5;
+ // 5 minutes
+ private static final long REBIND_DURATION_MS = 5 * 60 * 1_000;
+
@GuardedBy("mLock")
private final SparseArray<ContentCaptureServerSession> mSessions = new SparseArray<>();
@@ -121,11 +127,18 @@ final class ContentCapturePerUserService
@GuardedBy("mLock")
private ContentCaptureServiceInfo mInfo;
+ private Instant mLastRebindTime;
+ private int mRebindCount;
+ private final Handler mHandler;
+
+ private final Runnable mReBindServiceRunnable = new RebindServiceRunnable();
+
// TODO(b/111276913): add mechanism to prune stale sessions, similar to Autofill's
ContentCapturePerUserService(@NonNull ContentCaptureManagerService master,
- @NonNull Object lock, boolean disabled, @UserIdInt int userId) {
+ @NonNull Object lock, boolean disabled, @UserIdInt int userId, Handler handler) {
super(master, lock, userId);
+ mHandler = handler;
updateRemoteServiceLocked(disabled);
}
@@ -190,9 +203,43 @@ final class ContentCapturePerUserService
Slog.w(TAG, "remote service died: " + service);
synchronized (mLock) {
mZombie = true;
- writeServiceEvent(
- FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_REMOTE_SERVICE_DIED,
- getServiceComponentName());
+ // Reset rebindCount if over 12 hours mLastRebindTime
+ if (mLastRebindTime != null && Instant.now().isAfter(
+ mLastRebindTime.plusMillis(12 * 60 * 60 * 1000))) {
+ if (mMaster.debug) {
+ Slog.i(TAG, "The current rebind count " + mRebindCount + " is reset.");
+ }
+ mRebindCount = 0;
+ }
+ if (mRebindCount >= MAX_REBIND_COUNTS) {
+ writeServiceEvent(
+ FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_REMOTE_SERVICE_DIED,
+ getServiceComponentName());
+ }
+ if (mRebindCount < MAX_REBIND_COUNTS) {
+ mHandler.removeCallbacks(mReBindServiceRunnable);
+ mHandler.postDelayed(mReBindServiceRunnable, REBIND_DURATION_MS);
+ }
+ }
+ }
+
+ private void updateRemoteServiceAndResurrectSessionsLocked() {
+ boolean disabled = !isEnabledLocked();
+ updateRemoteServiceLocked(disabled);
+ resurrectSessionsLocked();
+ }
+
+ private final class RebindServiceRunnable implements Runnable{
+
+ @Override
+ public void run() {
+ synchronized (mLock) {
+ if (mZombie) {
+ mLastRebindTime = Instant.now();
+ mRebindCount++;
+ updateRemoteServiceAndResurrectSessionsLocked();
+ }
+ }
}
}
@@ -240,8 +287,8 @@ final class ContentCapturePerUserService
}
void onPackageUpdatedLocked() {
- updateRemoteServiceLocked(!isEnabledLocked());
- resurrectSessionsLocked();
+ mRebindCount = 0;
+ updateRemoteServiceAndResurrectSessionsLocked();
}
@GuardedBy("mLock")
@@ -555,6 +602,8 @@ final class ContentCapturePerUserService
mInfo.dump(prefix2, pw);
}
pw.print(prefix); pw.print("Zombie: "); pw.println(mZombie);
+ pw.print(prefix); pw.print("Rebind count: "); pw.println(mRebindCount);
+ pw.print(prefix); pw.print("Last rebind: "); pw.println(mLastRebindTime);
if (mRemoteService != null) {
pw.print(prefix); pw.println("remote service:");
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 63301ac49573..ab220b5e42e4 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -47,6 +47,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.telecom.TelecomManager;
+import android.telephony.AccessNetworkConstants;
import android.telephony.Annotation;
import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SrvccState;
@@ -1999,42 +2000,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
ApnSetting apnSetting = preciseState.getApnSetting();
- int apnTypes = apnSetting.getApnTypeBitmask();
- int state = preciseState.getState();
- int networkType = preciseState.getNetworkType();
-
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
- // We only call the callback when the change is for default APN type.
- if ((ApnSetting.TYPE_DEFAULT & apnTypes) != 0
- && (mDataConnectionState[phoneId] != state
- || mDataConnectionNetworkType[phoneId] != networkType)) {
- String str = "onDataConnectionStateChanged("
- + TelephonyUtils.dataStateToString(state)
- + ", " + getNetworkTypeName(networkType)
- + ") subId=" + subId + ", phoneId=" + phoneId;
- log(str);
- mLocalLog.log(str);
- for (Record r : mRecords) {
- if (r.matchTelephonyCallbackEvent(
- TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED)
- && idMatch(r, subId, phoneId)) {
- try {
- if (DBG) {
- log("Notify data connection state changed on sub: " + subId);
- }
- r.callback.onDataConnectionStateChanged(state, networkType);
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
- }
- }
- }
- handleRemoveListLocked();
-
- mDataConnectionState[phoneId] = state;
- mDataConnectionNetworkType[phoneId] = networkType;
- }
-
Pair<Integer, ApnSetting> key = Pair.create(preciseState.getTransportType(),
preciseState.getApnSetting());
PreciseDataConnectionState oldState = mPreciseDataConnectionStates.get(phoneId)
@@ -2066,6 +2033,73 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (preciseState.getState() != TelephonyManager.DATA_DISCONNECTED) {
mPreciseDataConnectionStates.get(phoneId).put(key, preciseState);
}
+
+ // Note that below is just the workaround for reporting the correct data connection
+ // state. The actual fix should be put in the new data stack in T.
+ // TODO: Remove the code below in T.
+
+ // Collect all possible candidate data connection state for internet. Key is the
+ // data connection state, value is the precise data connection state.
+ Map<Integer, PreciseDataConnectionState> internetConnections = new ArrayMap<>();
+ if (preciseState.getState() == TelephonyManager.DATA_DISCONNECTED
+ && preciseState.getApnSetting().getApnTypes()
+ .contains(ApnSetting.TYPE_DEFAULT)) {
+ internetConnections.put(TelephonyManager.DATA_DISCONNECTED, preciseState);
+ }
+ for (Map.Entry<Pair<Integer, ApnSetting>, PreciseDataConnectionState> entry :
+ mPreciseDataConnectionStates.get(phoneId).entrySet()) {
+ if (entry.getKey().first == AccessNetworkConstants.TRANSPORT_TYPE_WWAN
+ && entry.getKey().second.getApnTypes()
+ .contains(ApnSetting.TYPE_DEFAULT)) {
+ internetConnections.put(entry.getValue().getState(), entry.getValue());
+ }
+ }
+
+ // If any internet data is in connected state, then report connected, then check
+ // suspended, connecting, disconnecting, and disconnected. The order is very
+ // important.
+ int[] statesInPriority = new int[]{TelephonyManager.DATA_CONNECTED,
+ TelephonyManager.DATA_SUSPENDED, TelephonyManager.DATA_CONNECTING,
+ TelephonyManager.DATA_DISCONNECTING,
+ TelephonyManager.DATA_DISCONNECTED};
+ int state = TelephonyManager.DATA_DISCONNECTED;
+ int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ for (int s : statesInPriority) {
+ if (internetConnections.containsKey(s)) {
+ state = s;
+ networkType = internetConnections.get(s).getNetworkType();
+ break;
+ }
+ }
+
+ if (mDataConnectionState[phoneId] != state
+ || mDataConnectionNetworkType[phoneId] != networkType) {
+ String str = "onDataConnectionStateChanged("
+ + TelephonyUtils.dataStateToString(state)
+ + ", " + TelephonyManager.getNetworkTypeName(networkType)
+ + ") subId=" + subId + ", phoneId=" + phoneId;
+ log(str);
+ mLocalLog.log(str);
+ for (Record r : mRecords) {
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED)
+ && idMatch(r, subId, phoneId)) {
+ try {
+ if (DBG) {
+ log("Notify data connection state changed on sub: " + subId);
+ }
+ r.callback.onDataConnectionStateChanged(state, networkType);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+
+ mDataConnectionState[phoneId] = state;
+ mDataConnectionNetworkType[phoneId] = networkType;
+
+ handleRemoveListLocked();
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 18ed9586d263..b5f3389c50e0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -31,6 +31,7 @@ import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY;
import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
+import static android.app.ActivityManager.StopUserOnSwitch;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.AppOpsManager.OP_NONE;
@@ -4826,6 +4827,8 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void bootAnimationComplete() {
+ if (DEBUG_ALL) Slog.d(TAG, "bootAnimationComplete: Callers=" + Debug.getCallers(4));
+
final boolean callFinishBooting;
synchronized (this) {
callFinishBooting = mCallFinishBooting;
@@ -7648,7 +7651,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// On Automotive, at this point the system user has already been started and unlocked,
// and some of the tasks we do here have already been done. So skip those in that case.
- // TODO(b/132262830): this workdound shouldn't be necessary once we move the
+ // TODO(b/132262830, b/203885241): this workdound shouldn't be necessary once we move the
// headless-user start logic to UserManager-land
final boolean bootingSystemUser = currentUserId == UserHandle.USER_SYSTEM;
@@ -15096,6 +15099,11 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
+ public void setStopUserOnSwitch(@StopUserOnSwitch int value) {
+ mUserController.setStopUserOnSwitch(value);
+ }
+
+ @Override
public int stopUser(final int userId, boolean force, final IStopUserCallback callback) {
return mUserController.stopUser(userId, force, /* allowDelayedLocking= */ false,
/* callback= */ callback, /* keyEvictedCallback= */ null);
@@ -16392,6 +16400,11 @@ public class ActivityManagerService extends IActivityManager.Stub
@Nullable ActivityManagerInternal.VoiceInteractionManagerProvider provider) {
ActivityManagerService.this.setVoiceInteractionManagerProvider(provider);
}
+
+ @Override
+ public void setStopUserOnSwitch(int value) {
+ ActivityManagerService.this.setStopUserOnSwitch(value);
+ }
}
long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 685d606f8d41..31e48fb0837f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -29,6 +29,8 @@ import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_CRI
import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_LOW;
import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_MODERATE;
import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_NORMAL;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.LowMemDetector.ADJ_MEM_FACTOR_NOTHING;
import android.app.ActivityManager;
@@ -100,6 +102,7 @@ import com.android.internal.util.HexDump;
import com.android.internal.util.MemInfoReader;
import com.android.server.am.LowMemDetector.MemFactor;
import com.android.server.compat.PlatformCompat;
+import com.android.server.utils.Slogf;
import java.io.BufferedReader;
import java.io.IOException;
@@ -128,6 +131,10 @@ import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
final class ActivityManagerShellCommand extends ShellCommand {
+
+ static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerShellCommand" : TAG_AM;
+
+
public static final String NO_CLASS_ERROR_CODE = "Error type 3";
private static final String SHELL_PACKAGE_NAME = "com.android.shell";
@@ -323,6 +330,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
return runServiceRestartBackoff(pw);
case "get-isolated-pids":
return runGetIsolatedProcesses(pw);
+ case "set-stop-user-on-switch":
+ return runSetStopUserOnSwitch(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -3157,6 +3166,29 @@ final class ActivityManagerShellCommand extends ShellCommand {
return 0;
}
+ private int runSetStopUserOnSwitch(PrintWriter pw) throws RemoteException {
+ mInternal.enforceCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "setStopUserOnSwitch()");
+ String arg = getNextArg();
+ if (arg == null) {
+ Slogf.i(TAG, "setStopUserOnSwitch(): resetting to default value");
+ mInternal.setStopUserOnSwitch(ActivityManager.STOP_USER_ON_SWITCH_DEFAULT);
+ pw.println("Reset to default value");
+ return 0;
+ }
+
+ boolean stop = Boolean.parseBoolean(arg);
+ int value = stop
+ ? ActivityManager.STOP_USER_ON_SWITCH_TRUE
+ : ActivityManager.STOP_USER_ON_SWITCH_FALSE;
+
+ Slogf.i(TAG, "runSetStopUserOnSwitch(): setting to %d (%b)", value, stop);
+ mInternal.setStopUserOnSwitch(value);
+ pw.println("Set to " + stop);
+
+ return 0;
+ }
+
private Resources getResources(PrintWriter pw) throws RemoteException {
// system resources does not contain all the device configuration, construct it manually.
Configuration config = mInterface.getConfiguration();
@@ -3489,6 +3521,10 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" Shows the restart backoff policy state for <PACKAGE_NAME>.");
pw.println(" get-isolated-pids <UID>");
pw.println(" Get the PIDs of isolated processes with packages in this <UID>");
+ pw.println(" set-stop-user-on-switch [true|false]");
+ pw.println(" Sets whether the current user (and its profiles) should be stopped"
+ + " when switching to a different user.");
+ pw.println(" Without arguments, it resets to the value defined by platform.");
pw.println();
Intent.printIntentArgsHelp(pw, "");
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index ba3e1fb95e7d..429696fd88a2 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -19,6 +19,9 @@ package com.android.server.am;
import static android.Manifest.permission.INTERACT_ACROSS_PROFILES;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.app.ActivityManager.STOP_USER_ON_SWITCH_DEFAULT;
+import static android.app.ActivityManager.STOP_USER_ON_SWITCH_TRUE;
+import static android.app.ActivityManager.StopUserOnSwitch;
import static android.app.ActivityManager.USER_OP_ERROR_IS_SYSTEM;
import static android.app.ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
import static android.app.ActivityManager.USER_OP_IS_CURRENT;
@@ -368,6 +371,13 @@ class UserController implements Handler.Callback {
@GuardedBy("mLock")
private boolean mInitialized;
+ /**
+ * Defines the behavior of whether the background users should be stopped when the foreground
+ * user is switched.
+ */
+ @GuardedBy("mLock")
+ private @StopUserOnSwitch int mStopUserOnSwitch = STOP_USER_ON_SWITCH_DEFAULT;
+
UserController(ActivityManagerService service) {
this(new Injector(service));
}
@@ -408,8 +418,31 @@ class UserController implements Handler.Callback {
}
}
- private boolean shouldStopBackgroundUsersOnSwitch() {
- int property = SystemProperties.getInt("fw.stop_bg_users_on_switch", -1);
+ void setStopUserOnSwitch(@StopUserOnSwitch int value) {
+ if (mInjector.checkCallingPermission(android.Manifest.permission.MANAGE_USERS)
+ == PackageManager.PERMISSION_DENIED && mInjector.checkCallingPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS)
+ == PackageManager.PERMISSION_DENIED) {
+ throw new SecurityException(
+ "You either need MANAGE_USERS or INTERACT_ACROSS_USERS permission to "
+ + "call setStopUserOnSwitch()");
+ }
+
+ synchronized (mLock) {
+ Slogf.i(TAG, "setStopUserOnSwitch(): %d -> %d", mStopUserOnSwitch, value);
+ mStopUserOnSwitch = value;
+ }
+ }
+
+ private boolean shouldStopUserOnSwitch() {
+ synchronized (mLock) {
+ if (mStopUserOnSwitch != STOP_USER_ON_SWITCH_DEFAULT) {
+ final boolean value = mStopUserOnSwitch == STOP_USER_ON_SWITCH_TRUE;
+ Slogf.i(TAG, "shouldStopUserOnSwitch(): returning overridden value (%b)", value);
+ return value;
+ }
+ }
+ final int property = SystemProperties.getInt("fw.stop_bg_users_on_switch", -1);
return property == -1 ? mDelayUserDataLocking : property == 1;
}
@@ -1799,7 +1832,7 @@ class UserController implements Handler.Callback {
mUserSwitchObservers.finishBroadcast();
}
- private void stopBackgroundUsersOnSwitchIfEnforced(@UserIdInt int oldUserId) {
+ private void stopUserOnSwitchIfEnforced(@UserIdInt int oldUserId) {
// Never stop system user
if (oldUserId == UserHandle.USER_SYSTEM) {
return;
@@ -1807,18 +1840,17 @@ class UserController implements Handler.Callback {
boolean hasRestriction =
hasUserRestriction(UserManager.DISALLOW_RUN_IN_BACKGROUND, oldUserId);
synchronized (mLock) {
- // If running in background is disabled or mStopBackgroundUsersOnSwitch mode,
- // stop the user.
- boolean disallowRunInBg = hasRestriction || shouldStopBackgroundUsersOnSwitch();
+ // If running in background is disabled or mStopUserOnSwitch mode, stop the user.
+ boolean disallowRunInBg = hasRestriction || shouldStopUserOnSwitch();
if (!disallowRunInBg) {
if (DEBUG_MU) {
- Slogf.i(TAG, "stopBackgroundUsersIfEnforced() NOT stopping %d and related "
- + "users", oldUserId);
+ Slogf.i(TAG, "stopUserOnSwitchIfEnforced() NOT stopping %d and related users",
+ oldUserId);
}
return;
}
if (DEBUG_MU) {
- Slogf.i(TAG, "stopBackgroundUsersIfEnforced() stopping %d and related users",
+ Slogf.i(TAG, "stopUserOnSwitchIfEnforced() stopping %d and related users",
oldUserId);
}
stopUsersLU(oldUserId, /* force= */ false, /* allowDelayedLocking= */ true,
@@ -1921,7 +1953,7 @@ class UserController implements Handler.Callback {
mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG, newUserId, 0));
stopGuestOrEphemeralUserIfBackground(oldUserId);
- stopBackgroundUsersOnSwitchIfEnforced(oldUserId);
+ stopUserOnSwitchIfEnforced(oldUserId);
}
private void moveUserToForeground(UserState uss, int oldUserId, int newUserId) {
@@ -2611,8 +2643,8 @@ class UserController implements Handler.Callback {
pw.println(" mTargetUserId:" + mTargetUserId);
pw.println(" mLastActiveUsers:" + mLastActiveUsers);
pw.println(" mDelayUserDataLocking:" + mDelayUserDataLocking);
- pw.println(" shouldStopBackgroundUsersOnSwitch:"
- + shouldStopBackgroundUsersOnSwitch());
+ pw.println(" shouldStopUserOnSwitch():" + shouldStopUserOnSwitch());
+ pw.println(" mStopUserOnSwitch:" + mStopUserOnSwitch);
pw.println(" mMaxRunningUsers:" + mMaxRunningUsers);
pw.println(" mUserSwitchUiEnabled:" + mUserSwitchUiEnabled);
pw.println(" mInitialized:" + mInitialized);
diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java
index 1fe76080fc6f..40fc3066e2bb 100644
--- a/services/core/java/com/android/server/am/UserState.java
+++ b/services/core/java/com/android/server/am/UserState.java
@@ -145,4 +145,11 @@ public final class UserState {
proto.write(UserStateProto.SWITCHING, switching);
proto.end(token);
}
+
+ @Override
+ public String toString() {
+ return "[UserState: id=" + mHandle.getIdentifier() + ", state=" + stateToString(state)
+ + ", lastState=" + stateToString(lastState) + ", switching=" + switching
+ + ", tokenProvided=" + tokenProvided + "]";
+ }
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 655278657b83..d4c9b4865bd5 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -7587,7 +7587,7 @@ public class AudioService extends IAudioService.Stub
break;
case MSG_INIT_HEADTRACKING_SENSORS:
- mSpatializerHelper.onInitSensors(/*init*/ msg.arg1 == 1);
+ mSpatializerHelper.onInitSensors();
break;
case MSG_CHECK_MUSIC_ACTIVE:
@@ -8521,14 +8521,13 @@ public class AudioService extends IAudioService.Stub
/**
* post a message to schedule init/release of head tracking sensors
- * @param init initialization if true, release if false
+ * whether to initialize or release sensors is based on the state of spatializer
*/
- void postInitSpatializerHeadTrackingSensors(boolean init) {
+ void postInitSpatializerHeadTrackingSensors() {
sendMsg(mAudioHandler,
MSG_INIT_HEADTRACKING_SENSORS,
SENDMSG_REPLACE,
- /*arg1*/ init ? 1 : 0,
- 0, TAG, /*delay*/ 0);
+ /*arg1*/ 0, /*arg2*/ 0, TAG, /*delay*/ 0);
}
//==========================================================================================
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 7cd027c7550f..6a26bea6f8f0 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -63,6 +63,14 @@ public class SpatializerHelper {
private @Nullable SensorManager mSensorManager;
//------------------------------------------------------------
+ /** head tracker sensor name */
+ // TODO: replace with generic head tracker sensor name.
+ // the current implementation refers to the "google" namespace but will be replaced
+ // by an android name at the next API level revision, it is not Google-specific.
+ // Also see "TODO-HT" in onInitSensors() method
+ private static final String HEADTRACKER_SENSOR =
+ "com.google.hardware.sensor.hid_dynamic.headtracker";
+
// Spatializer state machine
private static final int STATE_UNINITIALIZED = 0;
private static final int STATE_NOT_SUPPORTED = 1;
@@ -81,7 +89,7 @@ public class SpatializerHelper {
private @Nullable ISpatializer mSpat;
private @Nullable SpatializerCallback mSpatCallback;
private @Nullable SpatializerHeadTrackingCallback mSpatHeadTrackingCallback;
-
+ private @Nullable HelperDynamicSensorCallback mDynSensorCallback;
// default attributes and format that determine basic availability of spatialization
private static final AudioAttributes DEFAULT_ATTRIBUTES = new AudioAttributes.Builder()
@@ -209,11 +217,7 @@ public class SpatializerHelper {
// TODO use reported spat level to change state
// init sensors
- if (level == SpatializationLevel.NONE) {
- initSensors(/*init*/false);
- } else {
- postInitSensors(true);
- }
+ postInitSensors();
}
public void onOutputChanged(int output) {
@@ -229,6 +233,7 @@ public class SpatializerHelper {
}
};
+ //------------------------------------------------------
// spatializer head tracking callback from native
private final class SpatializerHeadTrackingCallback
extends ISpatializerHeadTrackingCallback.Stub {
@@ -269,6 +274,20 @@ public class SpatializerHelper {
};
//------------------------------------------------------
+ // dynamic sensor callback
+ private final class HelperDynamicSensorCallback extends SensorManager.DynamicSensorCallback {
+ @Override
+ public void onDynamicSensorConnected(Sensor sensor) {
+ postInitSensors();
+ }
+
+ @Override
+ public void onDynamicSensorDisconnected(Sensor sensor) {
+ postInitSensors();
+ }
+ }
+
+ //------------------------------------------------------
// compatible devices
/**
* @return a shallow copy of the list of compatible audio devices
@@ -851,28 +870,60 @@ public class SpatializerHelper {
//------------------------------------------------------
// sensors
- private void initSensors(boolean init) {
- if (mSensorManager == null) {
- mSensorManager = (SensorManager)
- mAudioService.mContext.getSystemService(Context.SENSOR_SERVICE);
+ private void postInitSensors() {
+ mAudioService.postInitSpatializerHeadTrackingSensors();
+ }
+
+ synchronized void onInitSensors() {
+ final boolean init = (mSpatLevel != SpatializationLevel.NONE);
+ final String action = init ? "initializing" : "releasing";
+ if (mSpat == null) {
+ Log.e(TAG, "not " + action + " sensors, null spatializer");
+ return;
}
- final int headHandle;
- final int screenHandle;
+ try {
+ if (!mSpat.isHeadTrackingSupported()) {
+ Log.e(TAG, "not " + action + " sensors, spatializer doesn't support headtracking");
+ return;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "not " + action + " sensors, error querying headtracking", e);
+ return;
+ }
+ int headHandle = -1;
+ int screenHandle = -1;
if (init) {
if (mSensorManager == null) {
- Log.e(TAG, "Null SensorManager, can't init sensors");
- return;
+ try {
+ mSensorManager = (SensorManager)
+ mAudioService.mContext.getSystemService(Context.SENSOR_SERVICE);
+ mDynSensorCallback = new HelperDynamicSensorCallback();
+ mSensorManager.registerDynamicSensorCallback(mDynSensorCallback);
+ } catch (Exception e) {
+ Log.e(TAG, "Error with SensorManager, can't initialize sensors", e);
+ mSensorManager = null;
+ mDynSensorCallback = null;
+ return;
+ }
}
- // TODO replace with dynamic association of sensor for headtracker
- Sensor headSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR);
- headHandle = headSensor.getHandle();
- //Sensor screenSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
- //screenHandle = deviceSensor.getHandle();
- screenHandle = -1;
+ // initialize sensor handles
+ // TODO-HT update to non-private sensor once head tracker sensor is defined
+ for (Sensor sensor : mSensorManager.getDynamicSensorList(
+ Sensor.TYPE_DEVICE_PRIVATE_BASE)) {
+ if (sensor.getStringType().equals(HEADTRACKER_SENSOR)) {
+ headHandle = sensor.getHandle();
+ break;
+ }
+ }
+ Sensor screenSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
+ screenHandle = screenSensor.getHandle();
} else {
- // -1 is disable value
- screenHandle = -1;
- headHandle = -1;
+ if (mSensorManager != null && mDynSensorCallback != null) {
+ mSensorManager.unregisterDynamicSensorCallback(mDynSensorCallback);
+ mSensorManager = null;
+ mDynSensorCallback = null;
+ }
+ // -1 is disable value for both screen and head tracker handles
}
try {
Log.i(TAG, "setScreenSensor:" + screenHandle);
@@ -888,28 +939,6 @@ public class SpatializerHelper {
}
}
- private void postInitSensors(boolean init) {
- mAudioService.postInitSpatializerHeadTrackingSensors(init);
- }
-
- synchronized void onInitSensors(boolean init) {
- final String action = init ? "initializing" : "releasing";
- if (mSpat == null) {
- Log.e(TAG, "not " + action + " sensors, null spatializer");
- return;
- }
- try {
- if (!mSpat.isHeadTrackingSupported()) {
- Log.e(TAG, "not " + action + " sensors, spatializer doesn't support headtracking");
- return;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "not " + action + " sensors, error querying headtracking", e);
- return;
- }
- initSensors(init);
- }
-
//------------------------------------------------------
// SDK <-> AIDL converters
private static int headTrackingModeTypeToSpatializerInt(byte mode) {
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index e0775d48b42f..f42870b4b734 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -1381,7 +1381,8 @@ public class BiometricService extends SystemService {
Slog.d(TAG, "handleAuthenticate: modality(" + preAuthStatus.first
+ "), status(" + preAuthStatus.second + "), preAuthInfo: " + preAuthInfo
- + " requestId: " + requestId);
+ + " requestId: " + requestId + " promptInfo.isIgnoreEnrollmentState: "
+ + promptInfo.isIgnoreEnrollmentState());
if (preAuthStatus.second == BiometricConstants.BIOMETRIC_SUCCESS) {
// If BIOMETRIC_WEAK or BIOMETRIC_STRONG are allowed, but not enrolled, but
diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
index cd0ff10168bb..a5a3542f49c7 100644
--- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java
+++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
@@ -83,6 +83,7 @@ class PreAuthInfo {
final List<Pair<BiometricSensor, Integer>> ineligibleSensors;
final boolean credentialAvailable;
final boolean confirmationRequested;
+ final boolean ignoreEnrollmentState;
static PreAuthInfo create(ITrustManager trustManager,
DevicePolicyManager devicePolicyManager,
@@ -114,7 +115,8 @@ class PreAuthInfo {
@AuthenticatorStatus int status = getStatusForBiometricAuthenticator(
devicePolicyManager, settingObserver, sensor, userId, opPackageName,
checkDevicePolicyManager, requestedStrength,
- promptInfo.getAllowedSensorIds());
+ promptInfo.getAllowedSensorIds(),
+ promptInfo.isIgnoreEnrollmentState());
Slog.d(TAG, "Package: " + opPackageName
+ " Sensor ID: " + sensor.id
@@ -130,7 +132,8 @@ class PreAuthInfo {
}
return new PreAuthInfo(biometricRequested, requestedStrength, credentialRequested,
- eligibleSensors, ineligibleSensors, credentialAvailable, confirmationRequested);
+ eligibleSensors, ineligibleSensors, credentialAvailable, confirmationRequested,
+ promptInfo.isIgnoreEnrollmentState());
}
/**
@@ -145,7 +148,8 @@ class PreAuthInfo {
BiometricService.SettingObserver settingObserver,
BiometricSensor sensor, int userId, String opPackageName,
boolean checkDevicePolicyManager, int requestedStrength,
- @NonNull List<Integer> requestedSensorIds) {
+ @NonNull List<Integer> requestedSensorIds,
+ boolean ignoreEnrollmentState) {
if (!requestedSensorIds.isEmpty() && !requestedSensorIds.contains(sensor.id)) {
return BIOMETRIC_NO_HARDWARE;
@@ -167,7 +171,8 @@ class PreAuthInfo {
return BIOMETRIC_HARDWARE_NOT_DETECTED;
}
- if (!sensor.impl.hasEnrolledTemplates(userId, opPackageName)) {
+ if (!sensor.impl.hasEnrolledTemplates(userId, opPackageName)
+ && !ignoreEnrollmentState) {
return BIOMETRIC_NOT_ENROLLED;
}
@@ -238,7 +243,7 @@ class PreAuthInfo {
private PreAuthInfo(boolean biometricRequested, int biometricStrengthRequested,
boolean credentialRequested, List<BiometricSensor> eligibleSensors,
List<Pair<BiometricSensor, Integer>> ineligibleSensors, boolean credentialAvailable,
- boolean confirmationRequested) {
+ boolean confirmationRequested, boolean ignoreEnrollmentState) {
mBiometricRequested = biometricRequested;
mBiometricStrengthRequested = biometricStrengthRequested;
this.credentialRequested = credentialRequested;
@@ -247,6 +252,7 @@ class PreAuthInfo {
this.ineligibleSensors = ineligibleSensors;
this.credentialAvailable = credentialAvailable;
this.confirmationRequested = confirmationRequested;
+ this.ignoreEnrollmentState = ignoreEnrollmentState;
}
private Pair<BiometricSensor, Integer> calculateErrorByPriority() {
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 031f6eeeca5f..61b8ded60db7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -168,6 +168,10 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
return Utils.isKeyguard(getContext(), getOwnerString());
}
+ private boolean isSettings() {
+ return Utils.isSettings(getContext(), getOwnerString());
+ }
+
@Override
protected boolean isCryptoOperation() {
return mOperationId != 0;
@@ -499,6 +503,8 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
protected int getShowOverlayReason() {
if (isKeyguard()) {
return BiometricOverlayConstants.REASON_AUTH_KEYGUARD;
+ } else if (isSettings()) {
+ return BiometricOverlayConstants.REASON_AUTH_SETTINGS;
} else if (isBiometricPrompt()) {
return BiometricOverlayConstants.REASON_AUTH_BP;
} else {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStartUserClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStartUserClient.java
index c364dbb4d615..2b5f49546d69 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStartUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStartUserClient.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.hardware.biometrics.face.IFace;
import android.hardware.biometrics.face.ISession;
import android.hardware.biometrics.face.ISessionCallback;
+import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
@@ -52,6 +53,7 @@ public class FaceStartUserClient extends StartUserClient<IFace, ISession> {
try {
final ISession newSession = getFreshDaemon().createSession(getSensorId(),
getTargetUserId(), mSessionCallback);
+ Binder.allowBlocking(newSession.asBinder());
mUserStartedCallback.onUserStarted(getTargetUserId(), newSession);
getCallback().onClientFinished(this, true /* success */);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index f35bb7ffd26b..c5d33ed7400b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -281,7 +281,7 @@ public class FingerprintService extends SystemService {
@Override // Binder call
public long authenticate(final IBinder token, final long operationId,
final int sensorId, final int userId, final IFingerprintServiceReceiver receiver,
- final String opPackageName) {
+ final String opPackageName, boolean ignoreEnrollmentState) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int callingUserId = UserHandle.getCallingUserId();
@@ -333,7 +333,8 @@ public class FingerprintService extends SystemService {
&& sensorProps != null && sensorProps.isAnyUdfpsType()) {
identity = Binder.clearCallingIdentity();
try {
- return authenticateWithPrompt(operationId, sensorProps, userId, receiver);
+ return authenticateWithPrompt(operationId, sensorProps, userId, receiver,
+ ignoreEnrollmentState);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -347,7 +348,8 @@ public class FingerprintService extends SystemService {
final long operationId,
@NonNull final FingerprintSensorPropertiesInternal props,
final int userId,
- final IFingerprintServiceReceiver receiver) {
+ final IFingerprintServiceReceiver receiver,
+ boolean ignoreEnrollmentState) {
final Context context = getUiContext();
final Executor executor = context.getMainExecutor();
@@ -368,6 +370,7 @@ public class FingerprintService extends SystemService {
})
.setAllowedSensorIds(new ArrayList<>(
Collections.singletonList(props.sensorId)))
+ .setIgnoreEnrollmentState(ignoreEnrollmentState)
.build();
final BiometricPrompt.AuthenticationCallback promptCallback =
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java
index 0050a895034f..be0e6edb2a42 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java
@@ -23,7 +23,6 @@ import static android.hardware.fingerprint.FingerprintStateListener.STATE_IDLE;
import static android.hardware.fingerprint.FingerprintStateListener.STATE_KEYGUARD_AUTH;
import android.annotation.NonNull;
-import android.content.Context;
import android.hardware.fingerprint.FingerprintStateListener;
import android.hardware.fingerprint.IFingerprintStateListener;
import android.os.RemoteException;
@@ -34,8 +33,6 @@ import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.EnrollClient;
import com.android.server.biometrics.sensors.EnrollmentModifier;
-import com.android.server.biometrics.sensors.RemovalConsumer;
-import com.android.server.biometrics.sensors.fingerprint.hidl.FingerprintEnrollClient;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -70,7 +67,7 @@ public class FingerprintStateCallback implements BaseClientMonitor.Callback {
} else {
mFingerprintState = STATE_AUTH_OTHER;
}
- } else if (client instanceof FingerprintEnrollClient) {
+ } else if (client instanceof EnrollClient) {
mFingerprintState = STATE_ENROLLING;
} else {
Slog.w(FingerprintService.TAG,
@@ -143,6 +140,7 @@ public class FingerprintStateCallback implements BaseClientMonitor.Callback {
/**
* Enables clients to register a FingerprintStateListener. Used by FingerprintService to forward
* updates in fingerprint sensor state to the SideFpNsEventHandler
+ *
* @param listener
*/
public void registerFingerprintStateListener(@NonNull IFingerprintStateListener listener) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStartUserClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStartUserClient.java
index 2d40c91cbc75..ee81620fdf77 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStartUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStartUserClient.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.hardware.biometrics.fingerprint.IFingerprint;
import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.biometrics.fingerprint.ISessionCallback;
+import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
@@ -53,6 +54,7 @@ public class FingerprintStartUserClient extends StartUserClient<IFingerprint, IS
try {
final ISession newSession = getFreshDaemon().createSession(getSensorId(),
getTargetUserId(), mSessionCallback);
+ Binder.allowBlocking(newSession.asBinder());
mUserStartedCallback.onUserStarted(getTargetUserId(), newSession);
getCallback().onClientFinished(this, true /* success */);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 9d2cff9901e2..5ce72c2fd080 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -108,8 +108,9 @@ public class CameraServiceProxy extends SystemService
/**
* 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.
+ * camera rotate & crop behavior and always return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE .
+ * The default behavior along with all possible override combinations is discussed in the table
+ * below.
*/
@ChangeId
@Overridable
@@ -121,9 +122,7 @@ public class CameraServiceProxy extends SystemService
* 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.
+ * on the needed compensation considering the current display rotation.
*/
@ChangeId
@Overridable
@@ -132,67 +131,30 @@ public class CameraServiceProxy extends SystemService
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
- * ______________________________________________
+ * |OVERRIDE |OVERRIDE_
+ * |CAMERA_ |CAMERA_
+ * |ROTATE_ |RESIZEABLE_
+ * |AND_CROP_ |AND_SDK_
+ * |DEFAULTS |CHECK
+ * _________________________________________________
+ * Default Behavior | D |D
+ * _________________________________________________
+ * Ignore SDK&Resize | D |E
+ * _________________________________________________
+ * SCALER_ROTATE_AND_CROP_NONE | E |D, 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.
+ * E -> Override enabled
+ * D -> Override disabled
+ * Default behavior -> Rotate&crop will be calculated depending on the required
+ * compensation necessary for the current display rotation.
+ * Additionally the app must either target M (or below)
+ * or is declared as non-resizeable.
+ * Ignore SDK&Resize -> The Rotate&crop value will depend on the required
+ * compensation for the current display rotation.
+ * SCALER_ROTATE_AND_CROP_NONE -> Always return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE
*/
// Flags arguments to NFC adapter to enable/disable NFC
@@ -543,14 +505,8 @@ public class CameraServiceProxy extends SystemService
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!");
+ Slog.v(TAG, "OVERRIDE_CAMERA_ROTATE_AND_CROP_DEFAULTS enabled!");
return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE;
- } else {
- Slog.v(TAG, "OVERRIDE_CAMERA_ROTATE_AND_CROP disabled!");
- return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE;
- }
}
boolean ignoreResizableAndSdkCheck = false;
if ((taskInfo != null) && (CompatChanges.isChangeEnabled(
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index 091e6c4adf4d..a56a8ea993f0 100644
--- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -227,7 +227,7 @@ public class MultipathPolicyTracker {
subscriberId = tele.getSubscriberId();
mNetworkTemplate = new NetworkTemplate(
NetworkTemplate.MATCH_MOBILE, subscriberId, new String[] { subscriberId },
- null, NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
+ null, NetworkStats.METERED_YES, NetworkStats.ROAMING_ALL,
NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL, OEM_MANAGED_ALL,
SUBSCRIBER_ID_MATCH_RULE_EXACT);
mUsageCallback = new UsageCallback() {
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index f16ed41af5ca..fadaf1082e46 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -2062,9 +2062,6 @@ public final class DisplayManagerService extends SystemService {
pw.println();
mLogicalDisplayMapper.dumpLocked(pw);
- pw.println();
- mDisplayModeDirector.dump(pw);
-
final int callbackCount = mCallbacks.size();
pw.println();
pw.println("Callbacks: size=" + callbackCount);
@@ -2087,6 +2084,8 @@ public final class DisplayManagerService extends SystemService {
pw.println();
mPersistentDataStore.dump(pw);
}
+ pw.println();
+ mDisplayModeDirector.dump(pw);
}
private static float[] getFloatArray(TypedArray array) {
@@ -2863,14 +2862,31 @@ public final class DisplayManagerService extends SystemService {
@Override // Binder call
public void setBrightnessConfigurationForUser(
BrightnessConfiguration c, @UserIdInt int userId, String packageName) {
- mLogicalDisplayMapper.forEachLocked(logicalDisplay -> {
- if (logicalDisplay.getDisplayInfoLocked().type != Display.TYPE_INTERNAL) {
- return;
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS,
+ "Permission required to change the display's brightness configuration");
+ if (userId != UserHandle.getCallingUserId()) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS,
+ "Permission required to change the display brightness"
+ + " configuration of another user");
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mSyncRoot) {
+ mLogicalDisplayMapper.forEachLocked(logicalDisplay -> {
+ if (logicalDisplay.getDisplayInfoLocked().type != Display.TYPE_INTERNAL) {
+ return;
+ }
+ final DisplayDevice displayDevice =
+ logicalDisplay.getPrimaryDisplayDeviceLocked();
+ setBrightnessConfigurationForDisplayInternal(c, displayDevice.getUniqueId(),
+ userId, packageName);
+ });
}
- final DisplayDevice displayDevice = logicalDisplay.getPrimaryDisplayDeviceLocked();
- setBrightnessConfigurationForDisplay(c, displayDevice.getUniqueId(), userId,
- packageName);
- });
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
@Override // Binder call
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 768587a6a2b8..2f3342f20fcb 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -378,6 +378,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private float mInitialAutoBrightness;
// The controller for the automatic brightness level.
+ @Nullable
private AutomaticBrightnessController mAutomaticBrightnessController;
private Sensor mLightSensor;
@@ -608,7 +609,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mPendingRbcOnOrChanged = strengthChanged || justActivated;
// Reset model if strength changed OR rbc is turned off
- if (strengthChanged || !justActivated && mAutomaticBrightnessController != null) {
+ if ((strengthChanged || !justActivated) && mAutomaticBrightnessController != null) {
mAutomaticBrightnessController.resetShortTermModel();
}
}
@@ -1567,7 +1568,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
sendUpdatePowerStateLocked();
mHandler.post(mOnBrightnessChangeRunnable);
// TODO(b/192258832): Switch the HBMChangeCallback to a listener pattern.
- mAutomaticBrightnessController.update();
+ if (mAutomaticBrightnessController != null) {
+ mAutomaticBrightnessController.update();
+ }
}, mContext);
}
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 345dc217110b..72ab8c1e2d1a 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -1996,6 +1996,11 @@ public class LocationProviderManager extends
+ TimeUtils.formatDuration(delayMs));
}
+ if (mDelayedRegister != null) {
+ mAlarmHelper.cancel(mDelayedRegister);
+ mDelayedRegister = null;
+ }
+
mDelayedRegister = new OnAlarmListener() {
@Override
public void onAlarm() {
diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java
index 607218e20ea8..b424c2083bd4 100644
--- a/services/core/java/com/android/server/media/MediaSession2Record.java
+++ b/services/core/java/com/android/server/media/MediaSession2Record.java
@@ -146,6 +146,12 @@ public class MediaSession2Record implements MediaSessionRecordImpl {
}
@Override
+ public boolean canHandleVolumeKey() {
+ // TODO: Implement when MediaSession2 starts to get key events.
+ return false;
+ }
+
+ @Override
public int getSessionPolicies() {
synchronized (mLock) {
return mPolicies;
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 1525cd4da669..e4ed0e5d4186 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -26,7 +26,9 @@ import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.MediaMetadata;
+import android.media.MediaRouter2Manager;
import android.media.Rating;
+import android.media.RoutingSessionInfo;
import android.media.VolumeProvider;
import android.media.session.ISession;
import android.media.session.ISessionCallback;
@@ -50,6 +52,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SystemClock;
+import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
@@ -121,6 +124,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
private final SessionCb mSessionCb;
private final MediaSessionService mService;
private final Context mContext;
+ private final boolean mVolumeAdjustmentForRemoteGroupSessions;
private final Object mLock = new Object();
private final CopyOnWriteArrayList<ISessionControllerCallbackHolder>
@@ -180,6 +184,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
mAudioAttrs = DEFAULT_ATTRIBUTES;
mPolicies = policies;
+ mVolumeAdjustmentForRemoteGroupSessions = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions);
// May throw RemoteException if the session app is killed.
mSessionCb.mCb.asBinder().linkToDeath(this, 0);
@@ -449,6 +455,33 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
}
@Override
+ public boolean canHandleVolumeKey() {
+ if (isPlaybackTypeLocal() || mVolumeAdjustmentForRemoteGroupSessions) {
+ return true;
+ }
+ MediaRouter2Manager mRouter2Manager = MediaRouter2Manager.getInstance(mContext);
+ List<RoutingSessionInfo> sessions =
+ mRouter2Manager.getRoutingSessions(mPackageName);
+ boolean foundNonSystemSession = false;
+ boolean isGroup = false;
+ for (RoutingSessionInfo session : sessions) {
+ if (!session.isSystemSession()) {
+ foundNonSystemSession = true;
+ int selectedRouteCount = session.getSelectedRoutes().size();
+ if (selectedRouteCount > 1) {
+ isGroup = true;
+ break;
+ }
+ }
+ }
+ if (!foundNonSystemSession) {
+ Log.d(TAG, "No routing session for " + mPackageName);
+ return false;
+ }
+ return !isGroup;
+ }
+
+ @Override
public int getSessionPolicies() {
synchronized (mLock) {
return mPolicies;
diff --git a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
index 3c50597b8cfc..8f01f02f2ab1 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
@@ -131,6 +131,13 @@ public interface MediaSessionRecordImpl extends AutoCloseable {
KeyEvent ke, int sequenceId, ResultReceiver cb);
/**
+ * Returns whether the media session can handle volume key events.
+ *
+ * @return True if this media session can handle volume key events, false otherwise.
+ */
+ boolean canHandleVolumeKey();
+
+ /**
* Get session policies from custom policy provider set when MediaSessionRecord is instantiated.
* If custom policy does not exist, will return null.
*/
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index b477ea353c25..29a5469367cd 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -2128,6 +2128,23 @@ public class MediaSessionService extends SystemService implements Monitor {
// Enabled notification listener only works within the same user.
return false;
}
+ // Verify whether package name and controller UID.
+ // It will indirectly check whether the caller has obtained the package name and UID
+ // via ControllerInfo or with the valid package name visibility.
+ try {
+ int actualControllerUid = mContext.getPackageManager().getPackageUidAsUser(
+ controllerPackageName,
+ UserHandle.getUserId(controllerUid));
+ if (controllerUid != actualControllerUid) {
+ Log.w(TAG, "Failed to check enabled notification listener. Package name and"
+ + " UID doesn't match");
+ return false;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Failed to check enabled notification listener. Package name doesn't"
+ + " exist");
+ return false;
+ }
if (mNotificationManager.hasEnabledNotificationListener(controllerPackageName,
UserHandle.getUserHandleForUid(controllerUid))) {
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index c4c21df746b3..b75ba75e028b 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -325,8 +325,7 @@ class MediaSessionStack {
int size = records.size();
for (int i = 0; i < size; i++) {
MediaSessionRecord record = records.get(i);
- // Do not send the volume key events to remote sessions.
- if (record.checkPlaybackActiveState(true) && record.isPlaybackTypeLocal()) {
+ if (record.checkPlaybackActiveState(true) && record.canHandleVolumeKey()) {
mCachedVolumeDefault = record;
return record;
}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index ddaaa1eeff4a..7d31287663d5 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -114,9 +114,10 @@ abstract public class ManagedServices {
static final String ATT_VERSION = "version";
static final String ATT_DEFAULTS = "defaults";
static final String ATT_USER_SET = "user_set_services";
+ static final String ATT_USER_SET_OLD = "user_set";
static final String ATT_USER_CHANGED = "user_changed";
- static final int DB_VERSION = 4;
+ static final String DB_VERSION = "4";
static final int APPROVAL_BY_PACKAGE = 0;
static final int APPROVAL_BY_COMPONENT = 1;
@@ -482,7 +483,7 @@ abstract public class ManagedServices {
public void writeXml(TypedXmlSerializer out, boolean forBackup, int userId) throws IOException {
out.startTag(null, getConfig().xmlTag);
- out.attributeInt(null, ATT_VERSION, DB_VERSION);
+ out.attributeInt(null, ATT_VERSION, Integer.parseInt(DB_VERSION));
writeDefaults(out);
@@ -615,6 +616,7 @@ abstract public class ManagedServices {
// read grants
int type;
String version = XmlUtils.readStringAttribute(parser, ATT_VERSION);
+ boolean needUpgradeUserset = false;
readDefaults(parser);
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
String tag = parser.getName();
@@ -633,13 +635,42 @@ abstract public class ManagedServices {
final boolean isPrimary =
parser.getAttributeBoolean(null, ATT_IS_PRIMARY, true);
+ // Load three different userSet attributes from xml
+ // user_changed, not null if version == 4 and is NAS setting
final String isUserChanged = XmlUtils.readStringAttribute(parser,
ATT_USER_CHANGED);
- String userSetComponent = null;
- if (isUserChanged == null) {
- userSetComponent = XmlUtils.readStringAttribute(parser, ATT_USER_SET);
+ // user_set, not null if version <= 3
+ final String isUserChanged_Old = XmlUtils.readStringAttribute(parser,
+ ATT_USER_SET_OLD);
+ // user_set_services, not null if version >= 3 and is non-NAS setting
+ String userSetComponent = XmlUtils.readStringAttribute(parser, ATT_USER_SET);
+
+ // since the same xml version may have different userSet attributes,
+ // we need to check both xml version and userSet values to know how to set
+ // the userSetComponent/mIsUserChanged to the correct value
+ if (DB_VERSION.equals(version)) {
+ // version 4, NAS contains user_changed and
+ // NLS/others contain user_set_services
+ if (isUserChanged == null) { //NLS
+ userSetComponent = TextUtils.emptyIfNull(userSetComponent);
+ } else { //NAS
+ mIsUserChanged.put(resolvedUserId, Boolean.valueOf(isUserChanged));
+ userSetComponent = Boolean.valueOf(isUserChanged) ? approved : "";
+ }
} else {
- mIsUserChanged.put(resolvedUserId, Boolean.valueOf(isUserChanged));
+ // version 3 may contain user_set (R) or user_set_services (S)
+ // version 2 or older contain user_set or nothing
+ needUpgradeUserset = true;
+ if (userSetComponent == null) { //contains user_set
+ if (isUserChanged_Old != null && Boolean.valueOf(isUserChanged_Old)) {
+ //user_set = true
+ userSetComponent = approved;
+ mIsUserChanged.put(resolvedUserId, true);
+ needUpgradeUserset = false;
+ } else {
+ userSetComponent = "";
+ }
+ }
}
readExtraAttributes(tag, parser, resolvedUserId);
if (allowedManagedServicePackages == null || allowedManagedServicePackages.test(
@@ -659,7 +690,6 @@ abstract public class ManagedServices {
|| DB_VERSION_1.equals(version)
|| DB_VERSION_2.equals(version)
|| DB_VERSION_3.equals(version);
- boolean needUpgradeUserset = DB_VERSION_3.equals(version);
if (isOldVersion) {
upgradeDefaultsXmlVersion();
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 2f550c6e9338..47d8022a5acc 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -7699,7 +7699,10 @@ public class NotificationManagerService extends SystemService {
final int waitMs = mAudioManager.getFocusRampTimeMs(
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
record.getAudioAttributes());
- if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
+ if (DBG) {
+ Slog.v(TAG, "Delaying vibration for notification "
+ + record.getKey() + " by " + waitMs + "ms");
+ }
try {
Thread.sleep(waitMs);
} catch (InterruptedException e) { }
@@ -7707,9 +7710,17 @@ public class NotificationManagerService extends SystemService {
// so need to check the notification still valide for vibrate.
synchronized (mNotificationLock) {
if (mNotificationsByKey.get(record.getKey()) != null) {
- vibrate(record, effect, true);
+ if (record.getKey().equals(mVibrateNotificationKey)) {
+ vibrate(record, effect, true);
+ } else {
+ if (DBG) {
+ Slog.v(TAG, "No vibration for notification "
+ + record.getKey() + ": a new notification is "
+ + "vibrating, or effects were cleared while waiting");
+ }
+ }
} else {
- Slog.e(TAG, "No vibration for canceled notification : "
+ Slog.w(TAG, "No vibration for canceled notification "
+ record.getKey());
}
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 27b164830572..ee0b3d52eb3d 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -71,6 +71,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.EventLog;
import android.util.Slog;
import android.util.SparseArray;
@@ -81,7 +82,6 @@ import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
-
import com.android.server.pm.UserManagerService;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -285,6 +285,12 @@ public final class OverlayManagerService extends SystemService {
restoreSettings();
+ // Wipe all shell overlays on boot, to recover from a potentially broken device
+ String shellPkgName = TextUtils.emptyIfNull(
+ getContext().getString(android.R.string.config_systemShell));
+ mSettings.removeIf(overlayInfo -> overlayInfo.isFabricated
+ && shellPkgName.equals(overlayInfo.packageName));
+
initIfNeeded();
onSwitchUser(UserHandle.USER_SYSTEM);
@@ -891,6 +897,16 @@ public final class OverlayManagerService extends SystemService {
throw new IllegalArgumentException(request.typeToString()
+ " unsupported for user " + request.userId);
}
+
+ // Normal apps are blocked from accessing OMS via SELinux, so to block non-root,
+ // non privileged callers, a simple check against the shell UID is sufficient, since
+ // that's the only exception from the other categories. This is enough while OMS
+ // is not a public API, but this will have to be changed if it's ever exposed.
+ if (callingUid == Process.SHELL_UID) {
+ EventLog.writeEvent(0x534e4554, "202768292", -1, "");
+ throw new IllegalArgumentException("Non-root shell cannot fabricate overlays");
+ }
+
realUserId = UserHandle.USER_ALL;
// Enforce that the calling process can only register and unregister fabricated
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index d7b244980cfc..7fdeb27203bd 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -135,6 +135,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
private static final long MAX_ACTIVE_SESSIONS_NO_PERMISSION = 50;
/** Upper bound on number of historical sessions for a UID */
private static final long MAX_HISTORICAL_SESSIONS = 1048576;
+ /** Destroy sessions older than this on storage free request */
+ private static final long MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS = 8 * DateUtils.HOUR_IN_MILLIS;
/**
* Allow verification-skipping if it's a development app installed through ADB with
@@ -334,22 +336,28 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
@GuardedBy("mSessions")
private void reconcileStagesLocked(String volumeUuid) {
- final File stagingDir = getTmpSessionDir(volumeUuid);
- final ArraySet<File> unclaimedStages = newArraySet(
- stagingDir.listFiles(sStageFilter));
-
- // We also need to clean up orphaned staging directory for staged sessions
- final File stagedSessionStagingDir = Environment.getDataStagingDirectory(volumeUuid);
- unclaimedStages.addAll(newArraySet(stagedSessionStagingDir.listFiles()));
-
+ final ArraySet<File> unclaimedStages = getStagingDirsOnVolume(volumeUuid);
// Ignore stages claimed by active sessions
for (int i = 0; i < mSessions.size(); i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
unclaimedStages.remove(session.stageDir);
}
+ removeStagingDirs(unclaimedStages);
+ }
+
+ private ArraySet<File> getStagingDirsOnVolume(String volumeUuid) {
+ final File stagingDir = getTmpSessionDir(volumeUuid);
+ final ArraySet<File> stagingDirs = newArraySet(stagingDir.listFiles(sStageFilter));
+
+ // We also need to clean up orphaned staging directory for staged sessions
+ final File stagedSessionStagingDir = Environment.getDataStagingDirectory(volumeUuid);
+ stagingDirs.addAll(newArraySet(stagedSessionStagingDir.listFiles()));
+ return stagingDirs;
+ }
+ private void removeStagingDirs(ArraySet<File> stagingDirsToRemove) {
// Clean up orphaned staging directories
- for (File stage : unclaimedStages) {
+ for (File stage : stagingDirsToRemove) {
Slog.w(TAG, "Deleting orphan stage " + stage);
synchronized (mPm.mInstallLock) {
mPm.removeCodePathLI(stage);
@@ -363,6 +371,33 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
}
+ /**
+ * Called to free up some storage space from obsolete installation files
+ */
+ public void freeStageDirs(String volumeUuid) {
+ final ArraySet<File> unclaimedStagingDirsOnVolume = getStagingDirsOnVolume(volumeUuid);
+ final long currentTimeMillis = System.currentTimeMillis();
+ synchronized (mSessions) {
+ for (int i = 0; i < mSessions.size(); i++) {
+ final PackageInstallerSession session = mSessions.valueAt(i);
+ if (!unclaimedStagingDirsOnVolume.contains(session.stageDir)) {
+ // Only handles sessions stored on the target volume
+ continue;
+ }
+ final long age = currentTimeMillis - session.createdMillis;
+ if (age >= MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS) {
+ // Aggressively close old sessions because we are running low on storage
+ // Their staging dirs will be removed too
+ session.abandon();
+ } else {
+ // Session is new enough, so it deserves to be kept even on low storage
+ unclaimedStagingDirsOnVolume.remove(session.stageDir);
+ }
+ }
+ }
+ removeStagingDirs(unclaimedStagingDirsOnVolume);
+ }
+
public static boolean isStageName(String name) {
final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp");
final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp");
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 542948491dc8..d0e445749698 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -673,7 +673,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final Runnable r;
synchronized (mLock) {
assertNotChildLocked("StagedSession#abandon");
- assertCallerIsOwnerOrRoot();
+ assertCallerIsOwnerOrRootOrSystem();
if (isInTerminalState()) {
// We keep the session in the database if it's in a finalized state. It will be
// removed by PackageInstallerService when the last update time is old enough.
@@ -3704,7 +3704,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private void abandonNonStaged() {
synchronized (mLock) {
assertNotChildLocked("abandonNonStaged");
- assertCallerIsOwnerOrRoot();
+ assertCallerIsOwnerOrRootOrSystem();
if (mRelinquished) {
if (LOGD) Slog.d(TAG, "Ignoring abandon after commit relinquished control");
return;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 1debaf3ea9b4..821900bf57fe 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -9296,6 +9296,10 @@ public class PackageManagerService extends IPackageManager.Stub
if (freeBytesRequired > 0) {
smInternal.freeCache(volumeUuid, freeBytesRequired);
}
+
+ // 12. Clear temp install session files
+ mInstallerService.freeStageDirs(volumeUuid);
+
if (file.getUsableSpace() >= bytes) return;
} else {
try {
@@ -12818,7 +12822,7 @@ public class PackageManagerService extends IPackageManager.Stub
return;
}
} else {
- if (isInstantApp(packageName, callingUserId)) {
+ if (isInstantAppInternal(packageName, callingUserId, Process.SYSTEM_UID)) {
return;
}
}
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index ba64d25178e7..4f190093e0d0 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -896,7 +896,7 @@ public class DomainVerificationService extends SystemService
oldPkgState.getUserStates();
int oldUserStatesSize = oldUserStates.size();
if (oldUserStatesSize > 0) {
- ArraySet<String> newWebDomains = mCollector.collectValidAutoVerifyDomains(newPkg);
+ ArraySet<String> newWebDomains = mCollector.collectAllWebDomains(newPkg);
for (int oldUserStatesIndex = 0; oldUserStatesIndex < oldUserStatesSize;
oldUserStatesIndex++) {
int userId = oldUserStates.keyAt(oldUserStatesIndex);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index cda7407dc98c..b7d4d22d3966 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4625,6 +4625,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return mKeyguardDelegate.isInputRestricted();
}
+ /** {@inheritDoc} */
+ @Override
+ public boolean isKeyguardUnoccluding() {
+ return keyguardOn() && !mWindowManagerFuncs.isAppTransitionStateIdle();
+ }
+
@Override
public void dismissKeyguardLw(IKeyguardDismissCallback callback, CharSequence message) {
if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 87465a4b2ffe..2f2f94d3b5de 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -370,6 +370,12 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
* as the top display.
*/
void moveDisplayToTop(int displayId);
+
+ /**
+ * Return whether the app transition state is idle.
+ * @return {@code true} if app transition state is idle on the default display.
+ */
+ boolean isAppTransitionStateIdle();
}
/**
@@ -970,6 +976,14 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
public boolean isKeyguardOccluded();
/**
+ * Return whether the keyguard is unoccluding.
+ * @return {@code true} if the keyguard is unoccluding.
+ */
+ default boolean isKeyguardUnoccluding() {
+ return false;
+ }
+
+ /**
* @return true if in keyguard is on.
*/
boolean isKeyguardShowing();
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 106cff17dbef..2be29d4a5ab4 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -29,6 +29,7 @@ import static android.net.NetworkIdentity.OEM_PAID;
import static android.net.NetworkIdentity.OEM_PRIVATE;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.METERED_ALL;
+import static android.net.NetworkStats.METERED_YES;
import static android.net.NetworkStats.ROAMING_ALL;
import static android.net.NetworkTemplate.MATCH_ETHERNET;
import static android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD;
@@ -1348,7 +1349,7 @@ public class StatsPullAtomService extends SystemService {
@Nullable private NetworkStats getUidNetworkStatsSnapshotForTransport(int transport) {
final NetworkTemplate template = (transport == TRANSPORT_CELLULAR)
? NetworkTemplate.buildTemplateMobileWithRatType(
- /*subscriptionId=*/null, NETWORK_TYPE_ALL)
+ /*subscriptionId=*/null, NETWORK_TYPE_ALL, METERED_YES)
: NetworkTemplate.buildTemplateWifiWildcard();
return getUidNetworkStatsSnapshotForTemplate(template, /*includeTags=*/false);
}
@@ -1388,7 +1389,8 @@ public class StatsPullAtomService extends SystemService {
final List<NetworkStatsExt> ret = new ArrayList<>();
for (final int ratType : getAllCollapsedRatTypes()) {
final NetworkTemplate template =
- buildTemplateMobileWithRatType(subInfo.subscriberId, ratType);
+ buildTemplateMobileWithRatType(subInfo.subscriberId, ratType,
+ METERED_YES);
final NetworkStats stats =
getUidNetworkStatsSnapshotForTemplate(template, /*includeTags=*/false);
if (stats != null) {
diff --git a/services/core/java/com/android/server/vibrator/Vibration.java b/services/core/java/com/android/server/vibrator/Vibration.java
index e447a23cf331..245f4538a076 100644
--- a/services/core/java/com/android/server/vibrator/Vibration.java
+++ b/services/core/java/com/android/server/vibrator/Vibration.java
@@ -44,9 +44,11 @@ final class Vibration {
enum Status {
RUNNING,
FINISHED,
+ FINISHED_UNEXPECTED, // Didn't terminate in the usual way.
FORWARDED_TO_INPUT_DEVICES,
CANCELLED,
IGNORED_ERROR_APP_OPS,
+ IGNORED_ERROR_TOKEN,
IGNORED,
IGNORED_APP_OPS,
IGNORED_BACKGROUND,
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index 0f4f58b32c1b..25321c18bb3c 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -47,6 +47,7 @@ import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.NoSuchElementException;
import java.util.PriorityQueue;
import java.util.Queue;
@@ -98,7 +99,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
}
private final Object mLock = new Object();
- private final WorkSource mWorkSource = new WorkSource();
+ private final WorkSource mWorkSource;
private final PowerManager.WakeLock mWakeLock;
private final IBatteryStats mBatteryStatsService;
private final VibrationSettings mVibrationSettings;
@@ -110,6 +111,8 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
private volatile boolean mStop;
private volatile boolean mForceStop;
+ // Variable only set and read in main thread.
+ private boolean mCalledVibrationCompleteCallback = false;
VibrationThread(Vibration vib, VibrationSettings vibrationSettings,
DeviceVibrationEffectAdapter effectAdapter,
@@ -119,9 +122,8 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
mVibrationSettings = vibrationSettings;
mDeviceEffectAdapter = effectAdapter;
mCallbacks = callbacks;
+ mWorkSource = new WorkSource(mVibration.uid);
mWakeLock = wakeLock;
- mWorkSource.set(vib.uid);
- mWakeLock.setWorkSource(mWorkSource);
mBatteryStatsService = batteryStatsService;
CombinedVibration effect = vib.getEffect();
@@ -151,17 +153,53 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
@Override
public void run() {
- Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
+ // Structured to guarantee the vibrators completed and released callbacks at the end of
+ // thread execution. Both of these callbacks are exclusively called from this thread.
+ try {
+ try {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
+ runWithWakeLock();
+ } finally {
+ clientVibrationCompleteIfNotAlready(Vibration.Status.FINISHED_UNEXPECTED);
+ }
+ } finally {
+ mCallbacks.onVibratorsReleased();
+ }
+ }
+
+ /** Runs the VibrationThread ensuring that the wake lock is acquired and released. */
+ private void runWithWakeLock() {
+ mWakeLock.setWorkSource(mWorkSource);
mWakeLock.acquire();
try {
+ runWithWakeLockAndDeathLink();
+ } finally {
+ mWakeLock.release();
+ }
+ }
+
+ /**
+ * Runs the VibrationThread with the binder death link, handling link/unlink failures.
+ * Called from within runWithWakeLock.
+ */
+ private void runWithWakeLockAndDeathLink() {
+ try {
mVibration.token.linkToDeath(this, 0);
- playVibration();
- mCallbacks.onVibratorsReleased();
} catch (RemoteException e) {
Slog.e(TAG, "Error linking vibration to token death", e);
+ clientVibrationCompleteIfNotAlready(Vibration.Status.IGNORED_ERROR_TOKEN);
+ return;
+ }
+ // Ensure that the unlink always occurs now.
+ try {
+ // This is the actual execution of the vibration.
+ playVibration();
} finally {
- mVibration.token.unlinkToDeath(this, 0);
- mWakeLock.release();
+ try {
+ mVibration.token.unlinkToDeath(this, 0);
+ } catch (NoSuchElementException e) {
+ Slog.wtf(TAG, "Failed to unlink token", e);
+ }
}
}
@@ -219,6 +257,16 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
}
}
+ // Indicate that the vibration is complete. This can be called multiple times only for
+ // convenience of handling error conditions - an error after the client is complete won't
+ // affect the status.
+ private void clientVibrationCompleteIfNotAlready(Vibration.Status completedStatus) {
+ if (!mCalledVibrationCompleteCallback) {
+ mCalledVibrationCompleteCallback = true;
+ mCallbacks.onVibrationCompleted(mVibration.id, completedStatus);
+ }
+ }
+
private void playVibration() {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "playVibration");
try {
@@ -226,7 +274,6 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
final int sequentialEffectSize = sequentialEffect.getEffects().size();
mStepQueue.offer(new StartVibrateStep(sequentialEffect));
- Vibration.Status status = null;
while (!mStepQueue.isEmpty()) {
long waitTime;
synchronized (mLock) {
@@ -242,13 +289,12 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
if (waitTime <= 0) {
mStepQueue.consumeNext();
}
- Vibration.Status currentStatus = mStop ? Vibration.Status.CANCELLED
+ Vibration.Status status = mStop ? Vibration.Status.CANCELLED
: mStepQueue.calculateVibrationStatus(sequentialEffectSize);
- if (status == null && currentStatus != Vibration.Status.RUNNING) {
+ if (status != Vibration.Status.RUNNING && !mCalledVibrationCompleteCallback) {
// First time vibration stopped running, start clean-up tasks and notify
// callback immediately.
- status = currentStatus;
- mCallbacks.onVibrationCompleted(mVibration.id, status);
+ clientVibrationCompleteIfNotAlready(status);
if (status == Vibration.Status.CANCELLED) {
mStepQueue.cancel();
}
@@ -256,19 +302,10 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
if (mForceStop) {
// Cancel every step and stop playing them right away, even clean-up steps.
mStepQueue.cancelImmediately();
+ clientVibrationCompleteIfNotAlready(Vibration.Status.CANCELLED);
break;
}
}
-
- if (status == null) {
- status = mStepQueue.calculateVibrationStatus(sequentialEffectSize);
- if (status == Vibration.Status.RUNNING) {
- Slog.w(TAG, "Something went wrong, step queue completed but vibration status"
- + " is still RUNNING for vibration " + mVibration.id);
- status = Vibration.Status.FINISHED;
- }
- mCallbacks.onVibrationCompleted(mVibration.id, status);
- }
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index a51ed09790a4..2f353d19b5df 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.wallpaper;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static android.app.WallpaperManager.COMMAND_REAPPLY;
import static android.app.WallpaperManager.FLAG_LOCK;
import static android.app.WallpaperManager.FLAG_SYSTEM;
@@ -791,6 +792,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
private final Context mContext;
private final WindowManagerInternal mWindowManagerInternal;
private final IPackageManager mIPackageManager;
+ private final ActivityManager mActivityManager;
private final MyPackageMonitor mMonitor;
private final AppOpsManager mAppOpsManager;
@@ -939,6 +941,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
*/
WallpaperColors primaryColors;
+ /**
+ * If the wallpaper was set from a foreground app (instead of from a background service).
+ */
+ public boolean fromForegroundApp;
+
WallpaperConnection connection;
long lastDiedTime;
boolean wallpaperUpdating;
@@ -1688,6 +1695,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mDisplayManager = mContext.getSystemService(DisplayManager.class);
mDisplayManager.registerDisplayListener(mDisplayListener, null /* handler */);
+ mActivityManager = mContext.getSystemService(ActivityManager.class);
mMonitor = new MyPackageMonitor();
mColorsChangedListeners = new SparseArray<>();
@@ -2648,6 +2656,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
}
+ final boolean fromForegroundApp = Binder.withCleanCallingIdentity(() ->
+ mActivityManager.getPackageImportance(callingPackage) == IMPORTANCE_FOREGROUND);
+
synchronized (mLock) {
if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which));
WallpaperData wallpaper;
@@ -2670,6 +2681,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
wallpaper.imageWallpaperPending = true;
wallpaper.whichPending = which;
wallpaper.setComplete = completion;
+ wallpaper.fromForegroundApp = fromForegroundApp;
wallpaper.cropHint.set(cropHint);
wallpaper.allowBackup = allowBackup;
}
@@ -3052,6 +3064,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
wallpaper.callbacks.finishBroadcast();
final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
+ intent.putExtra(WallpaperManager.EXTRA_FROM_FOREGROUND_APP, wallpaper.fromForegroundApp);
mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId));
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index cf9783fb9241..38a48570ba16 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -20,11 +20,11 @@ import static android.accessibilityservice.AccessibilityTrace.FLAGS_MAGNIFICATIO
import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK;
import static android.os.Build.IS_USER;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static com.android.server.accessibility.AccessibilityTraceFileProto.ENTRY;
import static com.android.server.accessibility.AccessibilityTraceFileProto.MAGIC_NUMBER;
@@ -1009,6 +1009,8 @@ final class AccessibilityController {
final int windowType = windowState.mAttrs.type;
if (isExcludedWindowType(windowType)
|| ((windowState.mAttrs.privateFlags
+ & PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION) != 0)
+ || ((windowState.mAttrs.privateFlags
& PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0)) {
continue;
}
@@ -1073,7 +1075,6 @@ final class AccessibilityController {
}
}
}
-
visibleWindows.clear();
mMagnificationRegion.op(mDrawBorderInset, mDrawBorderInset,
@@ -1110,9 +1111,6 @@ final class AccessibilityController {
private boolean isExcludedWindowType(int windowType) {
return windowType == TYPE_MAGNIFICATION_OVERLAY
- // Omit the touch region to avoid the cut out of the magnification
- // bounds because nav bar panel is unmagnifiable.
- || windowType == TYPE_NAVIGATION_BAR_PANEL
// Omit the touch region of window magnification to avoid the cut out of the
// magnification and the magnified center of window magnification could be
// in the bounds
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index c715c39c7359..f87856255b3e 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -190,7 +190,7 @@ class ActivityMetricsLogger {
@VisibleForTesting
boolean allDrawn() {
- return mAssociatedTransitionInfo != null && mAssociatedTransitionInfo.allDrawn();
+ return mAssociatedTransitionInfo != null && mAssociatedTransitionInfo.mIsDrawn;
}
boolean hasActiveTransitionInfo() {
@@ -224,8 +224,8 @@ class ActivityMetricsLogger {
final boolean mProcessRunning;
/** whether the process of the launching activity didn't have any active activity. */
final boolean mProcessSwitch;
- /** The activities that should be drawn. */
- final ArrayList<ActivityRecord> mPendingDrawActivities = new ArrayList<>(2);
+ /** Whether the last launched activity has reported drawn. */
+ boolean mIsDrawn;
/** The latest activity to have been launched. */
@NonNull ActivityRecord mLastLaunchedActivity;
@@ -318,10 +318,7 @@ class ActivityMetricsLogger {
mLastLaunchedActivity.mLaunchRootTask = null;
}
mLastLaunchedActivity = r;
- if (!r.noDisplay && !r.isReportedDrawn()) {
- if (DEBUG_METRICS) Slog.i(TAG, "Add pending draw " + r);
- mPendingDrawActivities.add(r);
- }
+ mIsDrawn = r.isReportedDrawn();
}
/** Returns {@code true} if the incoming activity can belong to this transition. */
@@ -332,29 +329,7 @@ class ActivityMetricsLogger {
/** @return {@code true} if the activity matches a launched activity in this transition. */
boolean contains(ActivityRecord r) {
- return r != null && (r == mLastLaunchedActivity || mPendingDrawActivities.contains(r));
- }
-
- /** Called when the activity is drawn or won't be drawn. */
- void removePendingDrawActivity(ActivityRecord r) {
- if (DEBUG_METRICS) Slog.i(TAG, "Remove pending draw " + r);
- mPendingDrawActivities.remove(r);
- }
-
- boolean allDrawn() {
- return mPendingDrawActivities.isEmpty();
- }
-
- /** Only keep the records which can be drawn. */
- void updatePendingDraw(boolean keepInitializing) {
- for (int i = mPendingDrawActivities.size() - 1; i >= 0; i--) {
- final ActivityRecord r = mPendingDrawActivities.get(i);
- if (!r.mVisibleRequested
- && !(keepInitializing && r.isState(ActivityRecord.State.INITIALIZING))) {
- if (DEBUG_METRICS) Slog.i(TAG, "Discard pending draw " + r);
- mPendingDrawActivities.remove(i);
- }
- }
+ return r == mLastLaunchedActivity;
}
/**
@@ -377,7 +352,7 @@ class ActivityMetricsLogger {
@Override
public String toString() {
return "TransitionInfo{" + Integer.toHexString(System.identityHashCode(this))
- + " a=" + mLastLaunchedActivity + " ua=" + mPendingDrawActivities + "}";
+ + " a=" + mLastLaunchedActivity + " d=" + mIsDrawn + "}";
}
}
@@ -683,8 +658,7 @@ class ActivityMetricsLogger {
// visible such as after the top task is finished.
for (int i = mTransitionInfoList.size() - 2; i >= 0; i--) {
final TransitionInfo prevInfo = mTransitionInfoList.get(i);
- prevInfo.updatePendingDraw(false /* keepInitializing */);
- if (prevInfo.allDrawn()) {
+ if (prevInfo.mIsDrawn || !prevInfo.mLastLaunchedActivity.mVisibleRequested) {
abort(prevInfo, "nothing will be drawn");
}
}
@@ -711,17 +685,16 @@ class ActivityMetricsLogger {
if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn " + r);
final TransitionInfo info = getActiveTransitionInfo(r);
- if (info == null || info.allDrawn()) {
- if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn no activity to be drawn");
+ if (info == null || info.mIsDrawn) {
+ if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn not pending drawn " + info);
return null;
}
// Always calculate the delay because the caller may need to know the individual drawn time.
info.mWindowsDrawnDelayMs = info.calculateDelay(timestampNs);
- info.removePendingDrawActivity(r);
- info.updatePendingDraw(false /* keepInitializing */);
+ info.mIsDrawn = true;
final TransitionInfoSnapshot infoSnapshot = new TransitionInfoSnapshot(info);
- if (info.mLoggedTransitionStarting && info.allDrawn()) {
- done(false /* abort */, info, "notifyWindowsDrawn - all windows drawn", timestampNs);
+ if (info.mLoggedTransitionStarting) {
+ done(false /* abort */, info, "notifyWindowsDrawn", timestampNs);
}
if (r.mWmService.isRecentsAnimationTarget(r)) {
r.mWmService.getRecentsAnimationController().logRecentsAnimationStartTime(
@@ -770,12 +743,8 @@ class ActivityMetricsLogger {
info.mCurrentTransitionDelayMs = info.calculateDelay(timestampNs);
info.mReason = activityToReason.valueAt(index);
info.mLoggedTransitionStarting = true;
- // Do not remove activity in initializing state because the transition may be started
- // by starting window. The initializing activity may be requested to visible soon.
- info.updatePendingDraw(true /* keepInitializing */);
- if (info.allDrawn()) {
- done(false /* abort */, info, "notifyTransitionStarting - all windows drawn",
- timestampNs);
+ if (info.mIsDrawn) {
+ done(false /* abort */, info, "notifyTransitionStarting drawn", timestampNs);
}
}
}
@@ -801,10 +770,6 @@ class ActivityMetricsLogger {
if (compatStateInfo.mLastLoggedActivity == r) {
compatStateInfo.mLastLoggedActivity = null;
}
- if (compatStateInfo.mVisibleActivities.isEmpty()) {
- // No need to keep the entry if there are no visible activities.
- mPackageUidToCompatStateInfo.remove(packageUid);
- }
}
/**
@@ -828,12 +793,9 @@ class ActivityMetricsLogger {
return;
}
if (!r.mVisibleRequested || r.finishing) {
- info.removePendingDrawActivity(r);
- if (info.mLastLaunchedActivity == r) {
- // Check if the tracker can be cancelled because the last launched activity may be
- // no longer visible.
- scheduleCheckActivityToBeDrawn(r, 0 /* delay */);
- }
+ // Check if the tracker can be cancelled because the last launched activity may be
+ // no longer visible.
+ scheduleCheckActivityToBeDrawn(r, 0 /* delay */);
}
}
@@ -852,17 +814,12 @@ class ActivityMetricsLogger {
// If we have an active transition that's waiting on a certain activity that will be
// invisible now, we'll never get onWindowsDrawn, so abort the transition if necessary.
- // We have no active transitions.
+ // We have no active transitions. Or the notified activity whose visibility changed is
+ // no longer the launched activity, then we can still wait to get onWindowsDrawn.
if (info == null) {
return;
}
- // The notified activity whose visibility changed is no longer the launched activity.
- // We can still wait to get onWindowsDrawn.
- if (info.mLastLaunchedActivity != r) {
- return;
- }
-
// If the task of the launched activity contains any activity to be drawn, then the
// window drawn event should report later to complete the transition. Otherwise all
// activities in this task may be finished, invisible or drawn, so the transition event
@@ -945,7 +902,6 @@ class ActivityMetricsLogger {
}
logAppTransitionFinished(info, isHibernating != null ? isHibernating : false);
}
- info.mPendingDrawActivities.clear();
mTransitionInfoList.remove(info);
}
@@ -1122,7 +1078,7 @@ class ActivityMetricsLogger {
if (info == null) {
return null;
}
- if (!info.allDrawn() && info.mPendingFullyDrawn == null) {
+ if (!info.mIsDrawn && info.mPendingFullyDrawn == null) {
// There are still undrawn activities, postpone reporting fully drawn until all of its
// windows are drawn. So that is closer to an usable state.
info.mPendingFullyDrawn = () -> {
@@ -1309,13 +1265,14 @@ class ActivityMetricsLogger {
* activity.
* <li>If the current state is NOT_VISIBLE, there is a previously logged state for the
* package UID and there are no other visible activities with the same package UID.
- * <li>The last logged activity with the same package UID is either {@code activity} or the
- * last logged state is NOT_VISIBLE or NOT_LETTERBOXED.
+ * <li>The last logged activity with the same package UID is either {@code activity} (or an
+ * activity that has been removed) or the last logged state is NOT_VISIBLE or NOT_LETTERBOXED.
* </ul>
*
* <p>If the current state is NOT_VISIBLE and the previous state which was logged by {@code
- * activity} wasn't, looks for the first visible activity with the same package UID that has
- * a letterboxed state, or a non-letterboxed state if there isn't one, and logs that state.
+ * activity} (or an activity that has been removed) wasn't, looks for the first visible activity
+ * with the same package UID that has a letterboxed state, or a non-letterboxed state if
+ * there isn't one, and logs that state.
*
* <p>This method assumes that the caller is wrapping the call with a synchronized block so
* that there won't be a race condition between two activities with the same package.
@@ -1351,14 +1308,14 @@ class ActivityMetricsLogger {
if (!isVisible && !visibleActivities.isEmpty()) {
// There is another visible activity for this package UID.
- if (activity == lastLoggedActivity) {
+ if (lastLoggedActivity == null || activity == lastLoggedActivity) {
// Make sure a new visible state is logged if needed.
findAppCompatStateToLog(compatStateInfo, packageUid);
}
return;
}
- if (activity != lastLoggedActivity
+ if (lastLoggedActivity != null && activity != lastLoggedActivity
&& lastLoggedState != APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE
&& lastLoggedState != APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED) {
// Another visible activity for this package UID has logged a letterboxed state.
@@ -1372,15 +1329,25 @@ class ActivityMetricsLogger {
* Looks for the first visible activity in {@code compatStateInfo} that has a letterboxed
* state, or a non-letterboxed state if there isn't one, and logs that state for the given
* {@code packageUid}.
+ *
+ * <p>If there is a visible activity in {@code compatStateInfo} with the same state as the
+ * last logged state for the given {@code packageUid}, changes the last logged activity to
+ * reference the first such activity without actually logging the same state twice.
*/
private void findAppCompatStateToLog(PackageCompatStateInfo compatStateInfo, int packageUid) {
final ArrayList<ActivityRecord> visibleActivities = compatStateInfo.mVisibleActivities;
+ final int lastLoggedState = compatStateInfo.mLastLoggedState;
ActivityRecord activityToLog = null;
int stateToLog = APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
for (int i = 0; i < visibleActivities.size(); i++) {
ActivityRecord activity = visibleActivities.get(i);
int state = activity.getAppCompatState();
+ if (state == lastLoggedState) {
+ // Change last logged activity without logging the same state twice.
+ compatStateInfo.mLastLoggedActivity = activity;
+ return;
+ }
if (state == APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE) {
// This shouldn't happen.
Slog.w(TAG, "Visible activity with NOT_VISIBLE App Compat state for package UID: "
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index e5340db2f0e2..95a286cf9047 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2724,7 +2724,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (windowingMode == WINDOWING_MODE_PINNED && info.supportsPictureInPicture()) {
return false;
}
- if (WindowConfiguration.inMultiWindowMode(windowingMode) && supportsMultiWindow()
+ // Activity should be resizable if the task is.
+ final boolean supportsMultiWindow = task != null
+ ? task.supportsMultiWindow() || supportsMultiWindow()
+ : supportsMultiWindow();
+ if (WindowConfiguration.inMultiWindowMode(windowingMode) && supportsMultiWindow
&& !mAtmService.mForceResizableActivities) {
// The non resizable app will be letterboxed instead of being forced resizable.
return false;
@@ -2801,7 +2805,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final ActivityInfo.WindowLayout windowLayout = info.windowLayout;
return windowLayout == null
|| tda.supportsActivityMinWidthHeightMultiWindow(windowLayout.minWidth,
- windowLayout.minHeight);
+ windowLayout.minHeight, info);
}
/**
@@ -3081,9 +3085,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mAtmService.deferWindowLayout();
try {
- final Transition newTransition = (!mTransitionController.isCollecting()
- && mTransitionController.getTransitionPlayer() != null)
- ? mTransitionController.createTransition(TRANSIT_CLOSE) : null;
mTaskSupervisor.mNoHistoryActivities.remove(this);
makeFinishingLocked();
// Make a local reference to its task since this.task could be set to null once this
@@ -3115,10 +3116,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final boolean endTask = task.getTopNonFinishingActivity() == null
&& !task.isClearingToReuseTask();
- if (newTransition != null) {
- mTransitionController.requestStartTransition(newTransition,
- endTask ? task : null, null /* remote */);
- }
+ mTransitionController.requestCloseTransitionIfNeeded(endTask ? task : this);
if (isState(RESUMED)) {
if (endTask) {
mAtmService.getTaskChangeNotificationController().notifyTaskRemovalStarted(
@@ -3544,13 +3542,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (stopped) {
abortAndClearOptionsAnimation();
}
- if (mTransitionController.isCollecting()) {
- // We don't want the finishing to change the transition ready state since there will not
- // be corresponding setReady for finishing.
- mTransitionController.collectExistenceChange(this);
- } else {
- mTransitionController.requestTransitionIfNeeded(TRANSIT_CLOSE, this);
- }
}
/**
@@ -3732,6 +3723,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// to the restarted activity.
nowVisible = mVisibleRequested;
}
+ mTransitionController.requestCloseTransitionIfNeeded(this);
cleanUp(true /* cleanServices */, true /* setState */);
if (remove) {
if (mStartingData != null && mVisible && task != null) {
@@ -4157,19 +4149,40 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* conditions a) above.
* Multi-windowing mode will be exited if {@code true} is returned.
*/
- boolean canShowWhenLocked() {
- if (!inPinnedWindowingMode() && (mShowWhenLocked || containsShowWhenLockedWindow())) {
+ private static boolean canShowWhenLocked(ActivityRecord r) {
+ if (r == null || r.getTaskFragment() == null) {
+ return false;
+ }
+ if (!r.inPinnedWindowingMode() && (r.mShowWhenLocked || r.containsShowWhenLockedWindow())) {
return true;
- } else if (mInheritShownWhenLocked) {
- final ActivityRecord r = task.getActivityBelow(this);
- return r != null && !r.inPinnedWindowingMode() && (r.mShowWhenLocked
- || r.containsShowWhenLockedWindow());
+ } else if (r.mInheritShownWhenLocked) {
+ final ActivityRecord activity = r.getTaskFragment().getActivityBelow(r);
+ return activity != null && !activity.inPinnedWindowingMode()
+ && (activity.mShowWhenLocked || activity.containsShowWhenLockedWindow());
} else {
return false;
}
}
/**
+ * Determines if the activity can show while lock-screen is displayed. System displays
+ * activities while lock-screen is displayed only if all activities
+ * {@link #canShowWhenLocked(ActivityRecord)}.
+ * @see #canShowWhenLocked(ActivityRecord)
+ */
+ boolean canShowWhenLocked() {
+ final TaskFragment taskFragment = getTaskFragment();
+ if (taskFragment != null && taskFragment.getAdjacentTaskFragment() != null
+ && taskFragment.isEmbedded()) {
+ final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment();
+ final ActivityRecord r = adjacentTaskFragment.getTopNonFinishingActivity();
+ return canShowWhenLocked(this) && canShowWhenLocked(r);
+ } else {
+ return canShowWhenLocked(this);
+ }
+ }
+
+ /**
* @return Whether we are allowed to show non-starting windows at the moment. We disallow
* showing windows during transitions in case we have windows that have wide-color-gamut
* color mode set to avoid jank in the middle of the transition.
@@ -7278,7 +7291,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return false;
}
}
- return !isResizeable() && (info.isFixedOrientation() || hasFixedAspectRatio())
+ // Activity should be resizable if the task is.
+ final boolean isResizeable = task != null
+ ? task.isResizeable() || isResizeable()
+ : isResizeable();
+ return !isResizeable && (info.isFixedOrientation() || hasFixedAspectRatio())
// The configuration of non-standard type should be enforced by system.
// {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} is set when this activity is
// added to a task, but this function is called when resolving the launch params, at
@@ -7648,7 +7665,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// orientation with insets applied.
return;
}
- if (WindowConfiguration.inMultiWindowMode(windowingMode) && isResizeable()) {
+ // Activity should be resizable if the task is.
+ final boolean isResizeable = task != null
+ ? task.isResizeable() || isResizeable()
+ : isResizeable();
+ if (WindowConfiguration.inMultiWindowMode(windowingMode) && isResizeable) {
// Ignore orientation request for resizable apps in multi window.
return;
}
@@ -9013,7 +9034,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
proto.write(PIP_AUTO_ENTER_ENABLED, pictureInPictureArgs.isAutoEnterEnabled());
proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode());
- proto.write(MIN_ASPECT_RATIO, info.getMinAspectRatio());
+ proto.write(MIN_ASPECT_RATIO, getMinAspectRatio());
}
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index ba305929d808..ef4b8390413a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.Manifest.permission.ACTIVITY_EMBEDDING;
import static android.Manifest.permission.CAMERA;
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
+import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS;
import static android.Manifest.permission.START_ANY_ACTIVITY;
import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
@@ -44,7 +45,6 @@ import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static android.os.Process.INVALID_UID;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
@@ -148,6 +148,7 @@ import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.UserState;
+import com.android.server.utils.Slogf;
import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
import java.io.FileDescriptor;
@@ -1323,8 +1324,6 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
// us, we can now deliver.
r.idle = true;
- //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
-
// Check if able to finish booting when device is booting and all resumed activities
// are idle.
if ((mService.isBooting() && mRootWindowContainer.allResumedActivitiesIdle())
@@ -1357,14 +1356,21 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
// Atomically retrieve all of the other things to do.
processStoppingAndFinishingActivities(r, processPausingActivities, "idle");
+ if (DEBUG_IDLE) {
+ Slogf.i(TAG, "activityIdleInternal(): r=%s, booting=%b, mStartingUsers=%s", r, booting,
+ mStartingUsers);
+ }
+
if (!mStartingUsers.isEmpty()) {
final ArrayList<UserState> startingUsers = new ArrayList<>(mStartingUsers);
mStartingUsers.clear();
-
- if (!booting) {
+ // TODO(b/190854171): remove the isHeadlessSystemUserMode() check on master
+ if (!booting || UserManager.isHeadlessSystemUserMode()) {
// Complete user switch.
for (int i = 0; i < startingUsers.size(); i++) {
- mService.mAmInternal.finishUserSwitch(startingUsers.get(i));
+ UserState userState = startingUsers.get(i);
+ Slogf.i(TAG, "finishing switch of user %d", userState.mHandle.getIdentifier());
+ mService.mAmInternal.finishUserSwitch(userState);
}
}
}
@@ -1562,19 +1568,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
// Prevent recursion.
return;
}
- if (task.isVisible()) {
- if (task.mTransitionController.isCollecting()) {
- // We don't want the finishing to change the transition ready state since there will
- // not be corresponding setReady for finishing.
- task.mTransitionController.collectExistenceChange(task);
- } else {
- task.mTransitionController.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.
- task.mTransitionController.collect(task);
- }
+ task.mTransitionController.requestCloseTransitionIfNeeded(task);
task.mInRemoveTask = true;
try {
task.performClearTask(reason);
@@ -2025,6 +2019,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
final void scheduleIdle() {
if (!mHandler.hasMessages(IDLE_NOW_MSG)) {
+ if (DEBUG_IDLE) Slog.d(TAG_IDLE, "scheduleIdle: Callers=" + Debug.getCallers(4));
mHandler.sendEmptyMessage(IDLE_NOW_MSG);
}
}
@@ -2062,6 +2057,16 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
// Update the current top activity.
mTopResumedActivity = topRootTask.getTopResumedActivity();
+ // Update process state if there is no activity state change (e.g. focus change between
+ // multi-window mode activities) to make sure that the current top has top oom-adj.
+ // If the previous top is null, there should be activity state change from it, Then the
+ // process state should also have been updated so no need to update again.
+ if (mTopResumedActivity != null && prevTopActivity != null) {
+ if (mTopResumedActivity.app != null) {
+ mTopResumedActivity.app.addToPendingTop();
+ }
+ mService.updateOomAdj();
+ }
scheduleTopResumedActivityStateIfNeeded();
mService.updateTopApp(mTopResumedActivity);
@@ -2502,7 +2507,8 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
activityType = activityOptions.getLaunchActivityType();
final int windowingMode = activityOptions.getLaunchWindowingMode();
if (activityOptions.freezeRecentTasksReordering()
- && mRecentTasks.isCallerRecents(callingUid)) {
+ && mService.checkPermission(MANAGE_ACTIVITY_TASKS, callingPid, callingUid)
+ == PERMISSION_GRANTED) {
mRecentTasks.setFreezeTaskListReordering();
}
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index bd08d01768e3..b9353e1f9a0c 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -367,6 +367,10 @@ public class AppTransition implements Dump {
setAppTransitionState(APP_STATE_IDLE);
}
+ boolean isIdle() {
+ return mAppTransitionState == APP_STATE_IDLE;
+ }
+
boolean isTimeout() {
return mAppTransitionState == APP_STATE_TIMEOUT;
}
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 535a061ee4ab..f94777339fae 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -934,6 +934,10 @@ public class AppTransitionController {
voiceInteraction);
applyAnimations(closingWcs, closingApps, transit, false /* visible */, animLp,
voiceInteraction);
+ final RecentsAnimationController rac = mService.getRecentsAnimationController();
+ if (rac != null) {
+ rac.sendTasksAppeared();
+ }
for (int i = 0; i < openingApps.size(); ++i) {
openingApps.valueAtUnchecked(i).mOverrideTaskTransition = false;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0de3fa3ad968..29b1a80b7b58 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -115,10 +115,12 @@ import static com.android.server.wm.DisplayContentProto.IME_POLICY;
import static com.android.server.wm.DisplayContentProto.INPUT_METHOD_CONTROL_TARGET;
import static com.android.server.wm.DisplayContentProto.INPUT_METHOD_INPUT_TARGET;
import static com.android.server.wm.DisplayContentProto.INPUT_METHOD_TARGET;
+import static com.android.server.wm.DisplayContentProto.IS_SLEEPING;
import static com.android.server.wm.DisplayContentProto.OPENING_APPS;
import static com.android.server.wm.DisplayContentProto.RESUMED_ACTIVITY;
import static com.android.server.wm.DisplayContentProto.ROOT_DISPLAY_AREA;
import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION;
+import static com.android.server.wm.DisplayContentProto.SLEEP_TOKENS;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
@@ -3293,6 +3295,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
proto.write(FOCUSED_ROOT_TASK_ID, INVALID_TASK_ID);
}
proto.write(DISPLAY_READY, isReady());
+ proto.write(IS_SLEEPING, isSleeping());
+ for (int i = 0; i < mAllSleepTokens.size(); ++i) {
+ mAllSleepTokens.get(i).writeTagToProto(proto, SLEEP_TOKENS);
+ }
+
if (mImeLayeringTarget != null) {
mImeLayeringTarget.dumpDebug(proto, INPUT_METHOD_TARGET, logLevel);
}
@@ -4140,6 +4147,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
target.mActivityRecord.mImeInsetsFrozenUntilStartInput = false;
}
setImeInputTarget(target);
+ mInsetsStateController.updateAboveInsetsState(mInputMethodWindow, mInsetsStateController
+ .getRawInsetsState().getSourceOrDefaultVisibility(ITYPE_IME));
updateImeControlTarget();
}
}
@@ -6153,7 +6162,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// Reparent the SurfaceControl of this DisplayContent to null, to prevent content
// being added to it. This ensures that no app launched explicitly on the
// VirtualDisplay will show up as part of the mirrored content.
- .reparent(mWindowingLayer, null);
+ .reparent(mWindowingLayer, null)
+ .reparent(mOverlayLayer, null);
// Retrieve the size of the DisplayArea to mirror.
updateMirroredSurface(transaction, wc.getDisplayContent().getBounds(), surfaceSize);
mTokenToMirror = tokenToMirror;
@@ -6183,7 +6193,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// Reparent the SurfaceControl of this DisplayContent back to mSurfaceControl,
// to allow content to be added to it. This allows this DisplayContent to stop
// mirroring and show content normally.
- .reparent(mWindowingLayer, mSurfaceControl).apply();
+ .reparent(mWindowingLayer, mSurfaceControl)
+ .reparent(mOverlayLayer, mSurfaceControl)
+ .apply();
// Stop mirroring by destroying the reference to the mirrored layer.
mMirroredSurface = null;
// Do not un-set the token, in case content is removed and mirroring should begin again.
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 73a699bb164d..296bd7882ae6 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -54,6 +54,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
@@ -122,6 +123,7 @@ import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
+import android.gui.DropInputMode;
import android.hardware.power.Boost;
import android.os.Handler;
import android.os.IBinder;
@@ -879,6 +881,20 @@ public class DisplayPolicy {
}
/**
+ * Only trusted overlays are allowed to use FLAG_SLIPPERY.
+ */
+ static int sanitizeFlagSlippery(int flags, int privateFlags, String name) {
+ if ((flags & FLAG_SLIPPERY) == 0) {
+ return flags;
+ }
+ if ((privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) {
+ return flags;
+ }
+ Slog.w(TAG, "Removing FLAG_SLIPPERY for non-trusted overlay " + name);
+ return flags & ~FLAG_SLIPPERY;
+ }
+
+ /**
* Sanitize the layout parameters coming from a client. Allows the policy
* to do things like ensure that windows of a specific type can't take
* input focus.
@@ -949,6 +965,22 @@ public class DisplayPolicy {
if (mExtraNavBarAlt == win) {
mExtraNavBarAltPosition = getAltBarPosition(attrs);
}
+
+ attrs.flags = sanitizeFlagSlippery(attrs.flags, attrs.privateFlags, win.getName());
+ }
+
+ /**
+ * Add additional policy if needed to ensure the window or its children should not receive any
+ * input.
+ */
+ public void setDropInputModePolicy(WindowState win, LayoutParams attrs) {
+ if (attrs.type == TYPE_TOAST
+ && (attrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) == 0) {
+ // Toasts should not receive input. These windows should not have any children, so
+ // force this hierarchy of windows to drop all input.
+ mService.mTransactionFactory.get()
+ .setDropInputMode(win.getSurfaceControl(), DropInputMode.ALL).apply();
+ }
}
/**
@@ -2650,10 +2682,15 @@ public class DisplayPolicy {
}
void updateSystemBarAttributes() {
+ WindowState winCandidate = mFocusedWindow;
+ if (winCandidate == null && mTopFullscreenOpaqueWindowState != null
+ && (mTopFullscreenOpaqueWindowState.mAttrs.flags
+ & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0) {
+ // Only focusable window can take system bar control.
+ winCandidate = mTopFullscreenOpaqueWindowState;
+ }
// 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;
}
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 34e81498b1c3..b6552cb1b962 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -1330,7 +1330,7 @@ public class DisplayRotation {
case ActivityInfo.SCREEN_ORIENTATION_USER:
case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED:
// Works with any rotation except upside down.
- return (preferredRotation >= 0) && (preferredRotation != mUpsideDownRotation);
+ return (preferredRotation >= 0) && (preferredRotation != Surface.ROTATION_180);
}
return false;
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index cddb1e7edb3b..badb1f5a0a12 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -119,8 +119,12 @@ class EnsureActivitiesVisibleHelper {
if (adjacentTaskFragments != null && adjacentTaskFragments.contains(
childTaskFragment)) {
- // Everything behind two adjacent TaskFragments are occluded.
- mBehindFullyOccludedContainer = true;
+ if (!childTaskFragment.isTranslucent(starting)
+ && !childTaskFragment.getAdjacentTaskFragment().isTranslucent(
+ starting)) {
+ // Everything behind two adjacent TaskFragments are occluded.
+ mBehindFullyOccludedContainer = true;
+ }
continue;
}
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index d202587bd306..3948eeec20b0 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -108,6 +108,16 @@ class InsetsSourceProvider {
private final boolean mControllable;
+ /**
+ * Whether to forced the dimensions of the source window to the inset frame and crop out any
+ * overflow.
+ * Used to crop the taskbar inset source when a task animation is occurring to hide the taskbar
+ * rounded corners overlays.
+ *
+ * TODO: Remove when we enable shell transitions (b/202383002)
+ */
+ private boolean mCropToProvidingInsets = false;
+
InsetsSourceProvider(InsetsSource source, InsetsStateController stateController,
DisplayContent displayContent) {
mClientVisible = InsetsState.getDefaultVisibility(source.getType());
@@ -303,6 +313,62 @@ class InsetsSourceProvider {
mFakeControlTarget = fakeTarget;
}
+ /**
+ * Ensures that the inset source window is cropped so that anything that doesn't fit within the
+ * inset frame is cropped out until removeCropToProvidingInsetsBounds is called.
+ *
+ * The inset source surface will get cropped to the be of the size of the insets it's providing.
+ *
+ * For example, for the taskbar window which serves as the ITYPE_EXTRA_NAVIGATION_BAR inset
+ * source, the window is larger than the insets because of the rounded corners overlay, but
+ * during task animations we want to make sure that the overlay is cropped out of the window so
+ * that they don't hide the window animations.
+ *
+ * @param t The transaction to use to apply immediate overflow cropping operations.
+ *
+ * NOTE: The relies on the inset source window to have a leash (usually this would be a leash
+ * for the ANIMATION_TYPE_INSETS_CONTROL animation if the inset is controlled by the client)
+ *
+ * TODO: Remove when we migrate over to shell transitions (b/202383002)
+ */
+ void setCropToProvidingInsetsBounds(Transaction t) {
+ mCropToProvidingInsets = true;
+
+ if (mWin != null && mWin.mSurfaceAnimator.hasLeash()) {
+ // apply to existing leash
+ t.setWindowCrop(mWin.mSurfaceAnimator.mLeash, getProvidingInsetsBoundsCropRect());
+ }
+ }
+
+ /**
+ * Removes any overflow cropping and future cropping to the inset source window's leash that may
+ * have been set with a call to setCropToProvidingInsetsBounds().
+ * @param t The transaction to use to apply immediate removal of overflow cropping.
+ *
+ * TODO: Remove when we migrate over to shell transitions (b/202383002)
+ */
+ void removeCropToProvidingInsetsBounds(Transaction t) {
+ mCropToProvidingInsets = false;
+
+ // apply to existing leash
+ if (mWin != null && mWin.mSurfaceAnimator.hasLeash()) {
+ t.setWindowCrop(mWin.mSurfaceAnimator.mLeash, null);
+ }
+ }
+
+ private Rect getProvidingInsetsBoundsCropRect() {
+ Rect sourceWindowFrame = mWin.getFrame();
+ Rect insetFrame = getSource().getFrame();
+
+ // The rectangle in buffer space we want to crop to
+ return new Rect(
+ insetFrame.left - sourceWindowFrame.left,
+ insetFrame.top - sourceWindowFrame.top,
+ insetFrame.right - sourceWindowFrame.left,
+ insetFrame.bottom - sourceWindowFrame.top
+ );
+ }
+
void updateControlForTarget(@Nullable InsetsControlTarget target, boolean force) {
if (mSeamlessRotating) {
// We are un-rotating the window against the display rotation. We don't want the target
@@ -548,6 +614,11 @@ class InsetsSourceProvider {
mCapturedLeash = animationLeash;
t.setPosition(mCapturedLeash, mSurfacePosition.x, mSurfacePosition.y);
+
+ if (mCropToProvidingInsets) {
+ // Apply crop to hide overflow
+ t.setWindowCrop(mCapturedLeash, getProvidingInsetsBoundsCropRect());
+ }
}
@Override
diff --git a/services/core/java/com/android/server/wm/PackageConfigPersister.java b/services/core/java/com/android/server/wm/PackageConfigPersister.java
index 081a53e7bd05..fe21e5f0011e 100644
--- a/services/core/java/com/android/server/wm/PackageConfigPersister.java
+++ b/services/core/java/com/android/server/wm/PackageConfigPersister.java
@@ -16,10 +16,8 @@
package com.android.server.wm;
-import static android.app.UiModeManager.MODE_NIGHT_AUTO;
-import static android.app.UiModeManager.MODE_NIGHT_CUSTOM;
-
import android.annotation.NonNull;
+import android.content.res.Configuration;
import android.os.Environment;
import android.os.LocaleList;
import android.util.AtomicFile;
@@ -303,7 +301,7 @@ public class PackageConfigPersister {
}
boolean isResetNightMode() {
- return mNightMode == MODE_NIGHT_AUTO || mNightMode == MODE_NIGHT_CUSTOM;
+ return mNightMode == Configuration.UI_MODE_NIGHT_UNDEFINED;
}
@Override
diff --git a/services/core/java/com/android/server/wm/PinnedTaskController.java b/services/core/java/com/android/server/wm/PinnedTaskController.java
index b4963c5b9f1c..b54208d11974 100644
--- a/services/core/java/com/android/server/wm/PinnedTaskController.java
+++ b/services/core/java/com/android/server/wm/PinnedTaskController.java
@@ -17,7 +17,6 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -173,10 +172,8 @@ class PinnedTaskController {
* to avoid flickering when running PiP animation across different orientations.
*/
void deferOrientationChangeForEnteringPipFromFullScreenIfNeeded() {
- final Task topFullscreenTask = mDisplayContent.getDefaultTaskDisplayArea()
- .getTopRootTaskInWindowingMode(WINDOWING_MODE_FULLSCREEN);
- final ActivityRecord topFullscreen = topFullscreenTask != null
- ? topFullscreenTask.topRunningActivity() : null;
+ final ActivityRecord topFullscreen = mDisplayContent.getActivity(
+ a -> a.fillsParent() && !a.getTask().inMultiWindowMode());
if (topFullscreen == null || topFullscreen.hasFixedRotationTransform()) {
return;
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index ee05523b3f2a..6d96cf06a00b 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -473,7 +473,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks, OnRootTaskOrderChan
*/
static void notifyAnimationCancelBeforeStart(IRecentsAnimationRunner recentsAnimationRunner) {
try {
- recentsAnimationRunner.onAnimationCanceled(null /* taskSnapshot */);
+ recentsAnimationRunner.onAnimationCanceled(null /* taskIds */,
+ null /* taskSnapshots */);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to cancel recents animation before start", e);
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 67b3ec8c2b90..fd4b63e26403 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
@@ -163,6 +164,8 @@ public class RecentsAnimationController implements DeathRecipient {
private boolean mNavigationBarAttachedToApp;
private ActivityRecord mNavBarAttachedApp;
+ private final ArrayList<RemoteAnimationTarget> mPendingTaskAppears = new ArrayList<>();
+
/**
* An app transition listener to cancel the recents animation only after the app transition
* starts or is canceled.
@@ -732,11 +735,19 @@ public class RecentsAnimationController implements DeathRecipient {
return;
}
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "addTaskToTargets, target: %s", target);
- try {
- mRunner.onTaskAppeared(target);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to report task appeared", e);
- }
+ mPendingTaskAppears.add(target);
+ }
+ }
+
+ void sendTasksAppeared() {
+ if (mPendingTaskAppears.isEmpty() || mRunner == null) return;
+ try {
+ final RemoteAnimationTarget[] targets = mPendingTaskAppears.toArray(
+ new RemoteAnimationTarget[0]);
+ mRunner.onTasksAppeared(targets);
+ mPendingTaskAppears.clear();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to report task appeared", e);
}
}
@@ -744,10 +755,15 @@ public class RecentsAnimationController implements DeathRecipient {
OnAnimationFinishedCallback finishedCallback) {
final SparseBooleanArray recentTaskIds =
mService.mAtmService.getRecentTasks().getRecentTaskIds();
+ // The target must be built off the root task (the leaf task surface would be cropped
+ // within the root surface). However, recents only tracks leaf task ids, so we'll replace
+ // the task-id with the leaf id.
+ final Task leafTask = task.getTopLeafTask();
+ int taskId = leafTask.mTaskId;
TaskAnimationAdapter adapter = (TaskAnimationAdapter) addAnimation(task,
- !recentTaskIds.get(task.mTaskId), true /* hidden */, finishedCallback);
- mPendingNewTaskTargets.add(task.mTaskId);
- return adapter.createRemoteAnimationTarget();
+ !recentTaskIds.get(taskId), true /* hidden */, finishedCallback);
+ mPendingNewTaskTargets.add(taskId);
+ return adapter.createRemoteAnimationTarget(taskId);
}
void logRecentsAnimationStartTime(int durationMs) {
@@ -782,7 +798,8 @@ public class RecentsAnimationController implements DeathRecipient {
final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
- final RemoteAnimationTarget target = taskAdapter.createRemoteAnimationTarget();
+ final RemoteAnimationTarget target =
+ taskAdapter.createRemoteAnimationTarget(INVALID_TASK_ID);
if (target != null) {
targets.add(target);
} else {
@@ -853,37 +870,37 @@ public class RecentsAnimationController implements DeathRecipient {
mCanceled = true;
if (screenshot && !mPendingAnimations.isEmpty()) {
- final TaskAnimationAdapter adapter = mPendingAnimations.get(0);
- final Task task = adapter.mTask;
- // Screen shot previous task when next task starts transition and notify the runner.
- // We will actually finish the animation once the runner calls cleanUpScreenshot().
- final TaskSnapshot taskSnapshot = screenshotRecentTask(task);
+ final ArrayMap<Task, TaskSnapshot> snapshotMap = screenshotRecentTasks();
mPendingCancelWithScreenshotReorderMode = reorderMode;
- try {
- mRunner.onAnimationCanceled(taskSnapshot);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to cancel recents animation", e);
- }
- if (taskSnapshot != null) {
- // Defer until the runner calls back to cleanupScreenshot()
- adapter.setSnapshotOverlay(taskSnapshot);
+
+ if (!snapshotMap.isEmpty()) {
+ try {
+ int[] taskIds = new int[snapshotMap.size()];
+ TaskSnapshot[] snapshots = new TaskSnapshot[snapshotMap.size()];
+ for (int i = snapshotMap.size() - 1; i >= 0; i--) {
+ taskIds[i] = snapshotMap.keyAt(i).mTaskId;
+ snapshots[i] = snapshotMap.valueAt(i);
+ }
+ mRunner.onAnimationCanceled(taskIds, snapshots);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to cancel recents animation", e);
+ }
// Schedule a new failsafe for if the runner doesn't clean up the screenshot
scheduleFailsafe();
- } else {
- // Do a normal cancel since we couldn't screenshot
- mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
+ return;
}
- } else {
- // Otherwise, notify the runner and clean up the animation immediately
- // Note: In the fallback case, this can trigger multiple onAnimationCancel() calls
- // to the runner if we this actually triggers cancel twice on the caller
- try {
- mRunner.onAnimationCanceled(null /* taskSnapshot */);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to cancel recents animation", e);
- }
- mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
+ // Fallback to a normal cancel since we couldn't screenshot
+ }
+
+ // Notify the runner and clean up the animation immediately
+ // Note: In the fallback case, this can trigger multiple onAnimationCancel() calls
+ // to the runner if we this actually triggers cancel twice on the caller
+ try {
+ mRunner.onAnimationCanceled(null /* taskIds */, null /* taskSnapshots */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to cancel recents animation", e);
}
+ mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
}
}
@@ -957,13 +974,23 @@ public class RecentsAnimationController implements DeathRecipient {
return mRequestDeferCancelUntilNextTransition && mCancelDeferredWithScreenshot;
}
- TaskSnapshot screenshotRecentTask(Task task) {
+ private ArrayMap<Task, TaskSnapshot> screenshotRecentTasks() {
final TaskSnapshotController snapshotController = mService.mTaskSnapshotController;
- final ArraySet<Task> tasks = Sets.newArraySet(task);
- snapshotController.snapshotTasks(tasks);
- snapshotController.addSkipClosingAppSnapshotTasks(tasks);
- return snapshotController.getSnapshot(task.mTaskId, task.mUserId,
- false /* restoreFromDisk */, false /* isLowResolution */);
+ final ArrayMap<Task, TaskSnapshot> snapshotMap = new ArrayMap<>();
+ for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
+ final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
+ final Task task = adapter.mTask;
+ snapshotController.recordTaskSnapshot(task, false /* allowSnapshotHome */);
+ final TaskSnapshot snapshot = snapshotController.getSnapshot(task.mTaskId, task.mUserId,
+ false /* restoreFromDisk */, false /* isLowResolution */);
+ if (snapshot != null) {
+ snapshotMap.put(task, snapshot);
+ // Defer until the runner calls back to cleanupScreenshot()
+ adapter.setSnapshotOverlay(snapshot);
+ }
+ }
+ snapshotController.addSkipClosingAppSnapshotTasks(snapshotMap.keySet());
+ return snapshotMap;
}
void cleanupAnimation(@ReorderMode int reorderMode) {
@@ -985,6 +1012,8 @@ public class RecentsAnimationController implements DeathRecipient {
removeAnimation(taskAdapter);
taskAdapter.onCleanup();
}
+ // Should already be empty, but clean-up pending task-appears in-case they weren't sent.
+ mPendingTaskAppears.clear();
for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) {
final WallpaperAnimationAdapter wallpaperAdapter = mPendingWallpaperAnimations.get(i);
@@ -1214,7 +1243,14 @@ public class RecentsAnimationController implements DeathRecipient {
mLocalBounds.offsetTo(tmpPos.x, tmpPos.y);
}
- RemoteAnimationTarget createRemoteAnimationTarget() {
+ /**
+ * @param overrideTaskId overrides the target's taskId. It may differ from mTaskId and thus
+ * can differ from taskInfo. This mismatch is needed, however, in
+ * some cases where we are animating root tasks but need need leaf
+ * ids for identification. If this is INVALID (-1), then mTaskId
+ * will be used.
+ */
+ RemoteAnimationTarget createRemoteAnimationTarget(int overrideTaskId) {
final ActivityRecord topApp = mTask.getTopVisibleActivity();
final WindowState mainWindow = topApp != null
? topApp.findMainWindow()
@@ -1228,7 +1264,10 @@ public class RecentsAnimationController implements DeathRecipient {
final int mode = topApp.getActivityType() == mTargetActivityType
? MODE_OPENING
: MODE_CLOSING;
- mTarget = new RemoteAnimationTarget(mTask.mTaskId, mode, mCapturedLeash,
+ if (overrideTaskId < 0) {
+ overrideTaskId = mTask.mTaskId;
+ }
+ mTarget = new RemoteAnimationTarget(overrideTaskId, mode, mCapturedLeash,
!topApp.fillsParent(), new Rect(),
insets, mTask.getPrefixOrderIndex(), new Point(mBounds.left, mBounds.top),
mLocalBounds, mBounds, mTask.getWindowConfiguration(),
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index e3600e656307..b1eca9d5d4e4 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2700,6 +2700,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
token = new SleepToken(tag, displayId);
mSleepTokens.put(tokenKey, token);
display.mAllSleepTokens.add(token);
+ ProtoLog.d(WM_DEBUG_STATES, "Create sleep token: tag=%s, displayId=%d", tag, displayId);
} else {
throw new RuntimeException("Create the same sleep token twice: " + token);
}
@@ -2718,6 +2719,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return;
}
+ ProtoLog.d(WM_DEBUG_STATES, "Remove sleep token: tag=%s, displayId=%d", token.mTag,
+ token.mDisplayId);
display.mAllSleepTokens.remove(token);
if (display.mAllSleepTokens.isEmpty()) {
mService.updateSleepIfNeededLocked();
@@ -3729,6 +3732,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return "{\"" + mTag + "\", display " + mDisplayId
+ ", acquire at " + TimeUtils.formatUptime(mAcquireTime) + "}";
}
+
+ void writeTagToProto(ProtoOutputStream proto, long fieldId) {
+ proto.write(fieldId, mTag);
+ }
}
private class RankTaskLayersRunnable implements Runnable {
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 8c056b2a43b3..d8adc512b65a 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -391,7 +391,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
final ShortcutServiceInternal shortcutService =
LocalServices.getService(ShortcutServiceInternal.class);
final Intent[] shortcutIntents = shortcutService.createShortcutIntents(
- callingUid, callingPackage, packageName, shortcutId,
+ UserHandle.getUserId(callingUid), callingPackage, packageName, shortcutId,
user.getIdentifier(), callingPid, callingUid);
if (shortcutIntents == null || shortcutIntents.length == 0) {
throw new IllegalArgumentException("Invalid shortcut id");
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index d712bbf0fdef..50c9b31f425a 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -188,6 +188,10 @@ class SurfaceAnimator {
mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
if (snapshotAnim != null) {
mSnapshot = freezer.takeSnapshotForAnimation();
+ if (mSnapshot == null) {
+ Slog.e(TAG, "No snapshot target to start animation on for " + mAnimatable);
+ return;
+ }
mSnapshot.startAnimation(t, snapshotAnim, type);
}
}
diff --git a/services/core/java/com/android/server/wm/SurfaceFreezer.java b/services/core/java/com/android/server/wm/SurfaceFreezer.java
index c667db86e410..a7ef36b01d91 100644
--- a/services/core/java/com/android/server/wm/SurfaceFreezer.java
+++ b/services/core/java/com/android/server/wm/SurfaceFreezer.java
@@ -26,6 +26,7 @@ import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
+import android.util.Slog;
import android.view.SurfaceControl;
import com.android.internal.annotations.VisibleForTesting;
@@ -49,8 +50,10 @@ import com.android.internal.protolog.common.ProtoLog;
*/
class SurfaceFreezer {
- private final Freezable mAnimatable;
- private final WindowManagerService mWmService;
+ private static final String TAG = "SurfaceFreezer";
+
+ private final @NonNull Freezable mAnimatable;
+ private final @NonNull WindowManagerService mWmService;
@VisibleForTesting
SurfaceControl mLeash;
Snapshot mSnapshot = null;
@@ -59,7 +62,7 @@ class SurfaceFreezer {
/**
* @param animatable The object to animate.
*/
- SurfaceFreezer(Freezable animatable, WindowManagerService service) {
+ SurfaceFreezer(@NonNull Freezable animatable, @NonNull WindowManagerService service) {
mAnimatable = animatable;
mWmService = service;
}
@@ -75,6 +78,7 @@ class SurfaceFreezer {
*/
void freeze(SurfaceControl.Transaction t, Rect startBounds, Point relativePosition,
@Nullable SurfaceControl freezeTarget) {
+ reset(t);
mFreezeBounds.set(startBounds);
mLeash = SurfaceAnimator.createAnimationLeash(mAnimatable, mAnimatable.getSurfaceControl(),
@@ -85,11 +89,14 @@ class SurfaceFreezer {
freezeTarget = freezeTarget != null ? freezeTarget : mAnimatable.getFreezeSnapshotTarget();
if (freezeTarget != null) {
- SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer = createSnapshotBuffer(
+ SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer = createSnapshotBufferInner(
freezeTarget, startBounds);
final HardwareBuffer buffer = screenshotBuffer == null ? null
: screenshotBuffer.getHardwareBuffer();
if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
+ // This can happen when display is not ready.
+ Slog.w(TAG, "Failed to capture screenshot for " + mAnimatable);
+ unfreeze(t);
return;
}
mSnapshot = new Snapshot(t, screenshotBuffer, mLeash);
@@ -123,6 +130,11 @@ class SurfaceFreezer {
* snapshot.
*/
void unfreeze(SurfaceControl.Transaction t) {
+ unfreezeInner(t);
+ mAnimatable.onUnfrozen();
+ }
+
+ private void unfreezeInner(SurfaceControl.Transaction t) {
if (mSnapshot != null) {
mSnapshot.cancelAnimation(t, false /* restarting */);
mSnapshot = null;
@@ -139,6 +151,22 @@ class SurfaceFreezer {
}
}
+ /** Resets the snapshot before taking another one if the animation hasn't been started yet. */
+ private void reset(SurfaceControl.Transaction t) {
+ // Those would have been taken by the SurfaceAnimator if the animation has been started, so
+ // we can remove the leash directly.
+ // No need to reset the mAnimatable leash, as this is called before a new animation leash is
+ // created, so another #onAnimationLeashCreated will be called.
+ if (mSnapshot != null) {
+ mSnapshot.destroy(t);
+ mSnapshot = null;
+ }
+ if (mLeash != null) {
+ t.remove(mLeash);
+ mLeash = null;
+ }
+ }
+
void setLayer(SurfaceControl.Transaction t, int layer) {
if (mLeash != null) {
t.setLayer(mLeash, layer);
@@ -171,6 +199,18 @@ class SurfaceFreezer {
return SurfaceControl.captureLayers(captureArgs);
}
+ @VisibleForTesting
+ SurfaceControl.ScreenshotHardwareBuffer createSnapshotBufferInner(
+ SurfaceControl target, Rect bounds) {
+ return createSnapshotBuffer(target, bounds);
+ }
+
+ @VisibleForTesting
+ GraphicBuffer createFromHardwareBufferInner(
+ SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer) {
+ return GraphicBuffer.createFromHardwareBuffer(screenshotBuffer.getHardwareBuffer());
+ }
+
class Snapshot {
private SurfaceControl mSurfaceControl;
private AnimationAdapter mAnimation;
@@ -181,10 +221,7 @@ class SurfaceFreezer {
*/
Snapshot(SurfaceControl.Transaction t,
SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer, SurfaceControl parent) {
- // We can't use a delegating constructor since we need to
- // reference this::onAnimationFinished
- GraphicBuffer graphicBuffer = GraphicBuffer.createFromHardwareBuffer(
- screenshotBuffer.getHardwareBuffer());
+ GraphicBuffer graphicBuffer = createFromHardwareBufferInner(screenshotBuffer);
mSurfaceControl = mAnimatable.makeAnimationLeash()
.setName("snapshot anim: " + mAnimatable.toString())
@@ -258,5 +295,8 @@ class SurfaceFreezer {
* will be generated (but the rest of the freezing logic will still happen).
*/
@Nullable SurfaceControl getFreezeSnapshotTarget();
+
+ /** Called when the {@link #unfreeze(SurfaceControl.Transaction)} is called. */
+ void onUnfrozen();
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index ba2da06efab4..1b7a012094f6 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -155,6 +155,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
+import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
@@ -178,9 +179,11 @@ import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
+import android.view.InsetsState;
import android.view.RemoteAnimationAdapter;
import android.view.Surface;
import android.view.SurfaceControl;
+import android.view.TaskTransitionSpec;
import android.view.WindowManager;
import android.view.WindowManager.TransitionOldType;
import android.window.ITaskOrganizer;
@@ -1123,7 +1126,11 @@ class Task extends TaskFragment {
if (inMultiWindowMode() || !hasChild()) return false;
if (intent != null) {
final int returnHomeFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME;
- return intent != null && (intent.getFlags() & returnHomeFlags) == returnHomeFlags;
+ final Task task = getDisplayArea() != null ? getDisplayArea().getRootHomeTask() : null;
+ final boolean isLockTaskModeViolation = task != null
+ && mAtmService.getLockTaskController().isLockTaskModeViolation(task);
+ return (intent.getFlags() & returnHomeFlags) == returnHomeFlags
+ && !isLockTaskModeViolation;
}
final Task bottomTask = getBottomMostTask();
return bottomTask != this && bottomTask.returnsToHomeRootTask();
@@ -2374,6 +2381,16 @@ class Task extends TaskFragment {
return true;
}
+ /** Return the top-most leaf-task under this one, or this task if it is a leaf. */
+ public Task getTopLeafTask() {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final Task child = mChildren.get(i).asTask();
+ if (child == null) continue;
+ return child.getTopLeafTask();
+ }
+ return this;
+ }
+
int getDescendantTaskCount() {
final int[] currentCount = {0};
final PooledConsumer c = PooledLambda.obtainConsumer((t, count) -> { count[0]++; },
@@ -2819,6 +2836,30 @@ class Task extends TaskFragment {
return;
}
+ /**
+ * Account for specified insets to crop the animation bounds by to avoid the animation
+ * occurring over "out of bounds" regions
+ *
+ * For example this is used to make sure the tasks are cropped to be fully above the
+ * taskbar when animating.
+ *
+ * @param animationBounds The animations bounds to adjust to account for the custom spec insets.
+ */
+ void adjustAnimationBoundsForTransition(Rect animationBounds) {
+ TaskTransitionSpec spec = mWmService.mTaskTransitionSpec;
+ if (spec != null) {
+ for (@InsetsState.InternalInsetsType int insetType : spec.animationBoundInsets) {
+ InsetsSourceProvider insetProvider = getDisplayContent()
+ .getInsetsStateController()
+ .getSourceProvider(insetType);
+
+ Insets insets = insetProvider.getSource().calculateVisibleInsets(
+ animationBounds);
+ animationBounds.inset(insets);
+ }
+ }
+ }
+
void setDragResizing(boolean dragResizing, int dragResizeMode) {
if (mDragResizing != dragResizing) {
// No need to check if the mode is allowed if it's leaving dragResize
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 275ed0ee28a9..1e367dc78198 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -48,6 +48,7 @@ import android.annotation.ColorInt;
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.WindowConfiguration;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.os.UserHandle;
import android.util.IntArray;
@@ -148,7 +149,8 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
/**
* A launch root task for activity launching with {@link FLAG_ACTIVITY_LAUNCH_ADJACENT} flag.
*/
- private Task mLaunchAdjacentFlagRootTask;
+ @VisibleForTesting
+ Task mLaunchAdjacentFlagRootTask;
/**
* A focusable root task that is purposely to be positioned at the top. Although the root
@@ -864,12 +866,9 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
int layer = 0;
// Place root home tasks to the bottom.
layer = adjustRootTaskLayer(t, mTmpHomeChildren, layer);
- adjustRootTaskLayer(t, mTmpNormalChildren, layer);
-
- // Always on top tasks layer should higher than split divider layer so set it as start.
- t.setLayer(mSplitScreenDividerAnchor, SPLIT_DIVIDER_LAYER);
- layer = SPLIT_DIVIDER_LAYER + 1;
+ layer = adjustRootTaskLayer(t, mTmpNormalChildren, layer);
adjustRootTaskLayer(t, mTmpAlwaysOnTopChildren, layer);
+ t.setLayer(mSplitScreenDividerAnchor, SPLIT_DIVIDER_LAYER);
}
/**
@@ -884,19 +883,33 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
ArrayList<WindowContainer> children, int startLayer) {
mTmpNeedsZBoostIndexes.clear();
final int childCount = children.size();
+ boolean hasAdjacentTask = false;
for (int i = 0; i < childCount; i++) {
final WindowContainer child = children.get(i);
final TaskDisplayArea childTda = child.asTaskDisplayArea();
-
- boolean childNeedsZBoost = childTda != null
+ final boolean childNeedsZBoost = childTda != null
? childTda.childrenNeedZBoost()
: child.needsZBoost();
- if (!childNeedsZBoost) {
- child.assignLayer(t, startLayer++);
- } else {
+ if (childNeedsZBoost) {
mTmpNeedsZBoostIndexes.add(i);
+ continue;
+ }
+
+ final Task childTask = child.asTask();
+ final boolean inAdjacentTask = childTask != null
+ && child.inMultiWindowMode()
+ && childTask.getRootTask().getAdjacentTaskFragment() != null;
+
+ if (inAdjacentTask || child.inSplitScreenWindowingMode()) {
+ hasAdjacentTask = true;
+ } else if (hasAdjacentTask && startLayer < SPLIT_DIVIDER_LAYER) {
+ // Task on top of adjacent tasks should be higher than split divider layer so
+ // set it as start.
+ startLayer = SPLIT_DIVIDER_LAYER + 1;
}
+
+ child.assignLayer(t, startLayer++);
}
final int zBoostSize = mTmpNeedsZBoostIndexes.size();
@@ -1693,13 +1706,17 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
* Whether we can show activity requesting the given min width/height in multi window below
* this {@link TaskDisplayArea}.
*/
- boolean supportsActivityMinWidthHeightMultiWindow(int minWidth, int minHeight) {
- final int configRespectsActivityMinWidthHeightMultiWindow =
- mAtmService.mRespectsActivityMinWidthHeightMultiWindow;
+ boolean supportsActivityMinWidthHeightMultiWindow(int minWidth, int minHeight,
+ @Nullable ActivityInfo activityInfo) {
+ if (activityInfo != null && !activityInfo.shouldCheckMinWidthHeightForMultiWindow()) {
+ return true;
+ }
if (minWidth <= 0 && minHeight <= 0) {
// No request min width/height.
return true;
}
+ final int configRespectsActivityMinWidthHeightMultiWindow =
+ mAtmService.mRespectsActivityMinWidthHeightMultiWindow;
if (configRespectsActivityMinWidthHeightMultiWindow == -1) {
// Device override to ignore min width/height.
return true;
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 99f6f341e977..e66d92e8ea07 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -31,6 +31,7 @@ import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
+import static android.os.Process.INVALID_UID;
import static android.os.UserHandle.USER_NULL;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.TRANSIT_CLOSE;
@@ -221,6 +222,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
/** Organizer that organizing this TaskFragment. */
@Nullable
private ITaskFragmentOrganizer mTaskFragmentOrganizer;
+ private int mTaskFragmentOrganizerUid = INVALID_UID;
+ private @Nullable String mTaskFragmentOrganizerProcessName;
/** Client assigned unique token for this TaskFragment if this is created by an organizer. */
@Nullable
@@ -233,13 +236,6 @@ class TaskFragment extends WindowContainer<WindowContainer> {
*/
private boolean mDelayLastActivityRemoval;
- /**
- * The PID of the organizer that created this TaskFragment. It should be the same as the PID
- * of {@link android.window.TaskFragmentCreationParams#getOwnerToken()}.
- * {@link ActivityRecord#INVALID_PID} if this is not an organizer-created TaskFragment.
- */
- private int mTaskFragmentOrganizerPid = ActivityRecord.INVALID_PID;
-
final Point mLastSurfaceSize = new Point();
private final Rect mTmpInsets = new Rect();
@@ -338,9 +334,11 @@ class TaskFragment extends WindowContainer<WindowContainer> {
mDelayLastActivityRemoval = false;
}
- void setTaskFragmentOrganizer(TaskFragmentOrganizerToken organizer, int pid) {
+ void setTaskFragmentOrganizer(@NonNull TaskFragmentOrganizerToken organizer, int uid,
+ @NonNull String processName) {
mTaskFragmentOrganizer = ITaskFragmentOrganizer.Stub.asInterface(organizer.asBinder());
- mTaskFragmentOrganizerPid = pid;
+ mTaskFragmentOrganizerUid = uid;
+ mTaskFragmentOrganizerProcessName = processName;
}
/** Whether this TaskFragment is organized by the given {@code organizer}. */
@@ -778,6 +776,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
boolean gotOpaqueSplitScreenPrimary = false;
boolean gotOpaqueSplitScreenSecondary = false;
boolean gotTranslucentFullscreen = false;
+ boolean gotTranslucentAdjacent = false;
boolean gotTranslucentSplitScreenPrimary = false;
boolean gotTranslucentSplitScreenSecondary = false;
boolean shouldBeVisible = true;
@@ -806,6 +805,18 @@ class TaskFragment extends WindowContainer<WindowContainer> {
final boolean hasRunningActivities = hasRunningActivity(other);
if (other == this) {
+ if (!adjacentTaskFragments.isEmpty() && !gotTranslucentAdjacent) {
+ // The z-order of this TaskFragment is in middle of two adjacent TaskFragments
+ // and it cannot be visible if the TaskFragment on top is not translucent and
+ // is fully occluding this one.
+ for (int j = adjacentTaskFragments.size() - 1; j >= 0; --j) {
+ final TaskFragment taskFragment = adjacentTaskFragments.get(j);
+ if (!taskFragment.isTranslucent(starting)
+ && taskFragment.getBounds().contains(this.getBounds())) {
+ return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
+ }
+ }
+ }
// Should be visible if there is no other fragment occluding it, unless it doesn't
// have any running activities, not starting one and not home stack.
shouldBeVisible = hasRunningActivities
@@ -875,6 +886,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|| otherTaskFrag.mAdjacentTaskFragment.isTranslucent(starting)) {
// Can be visible behind a translucent adjacent TaskFragments.
gotTranslucentFullscreen = true;
+ gotTranslucentAdjacent = true;
continue;
}
// Can not be visible behind adjacent TaskFragments.
@@ -1758,7 +1770,9 @@ class TaskFragment extends WindowContainer<WindowContainer> {
return false;
}
- return tda.supportsActivityMinWidthHeightMultiWindow(mMinWidth, mMinHeight);
+ final ActivityRecord rootActivity = getTask().getRootActivity();
+ return tda.supportsActivityMinWidthHeightMultiWindow(mMinWidth, mMinHeight,
+ rootActivity != null ? rootActivity.info : null);
}
private int getTaskId() {
@@ -2164,9 +2178,11 @@ class TaskFragment extends WindowContainer<WindowContainer> {
List<IBinder> childActivities = new ArrayList<>();
for (int i = 0; i < getChildCount(); i++) {
WindowContainer wc = getChildAt(i);
- if (mTaskFragmentOrganizerPid != ActivityRecord.INVALID_PID
+ if (mTaskFragmentOrganizerUid != INVALID_UID
&& wc.asActivityRecord() != null
- && wc.asActivityRecord().getPid() == mTaskFragmentOrganizerPid) {
+ && wc.asActivityRecord().info.processName.equals(
+ mTaskFragmentOrganizerProcessName)
+ && wc.asActivityRecord().getUid() == mTaskFragmentOrganizerUid) {
// Only includes Activities that belong to the organizer process for security.
childActivities.add(wc.asActivityRecord().appToken);
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index ce93f2495c22..83ea1e22e6ea 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -54,6 +54,7 @@ import com.android.server.wm.utils.InsetUtils;
import com.google.android.collect.Sets;
import java.io.PrintWriter;
+import java.util.Set;
/**
* When an app token becomes invisible, we take a snapshot (bitmap) of the corresponding task and
@@ -167,7 +168,7 @@ class TaskSnapshotController {
* calling {@link #snapshotTasks} to ensure that the task has an up-to-date snapshot.
*/
@VisibleForTesting
- void addSkipClosingAppSnapshotTasks(ArraySet<Task> tasks) {
+ void addSkipClosingAppSnapshotTasks(Set<Task> tasks) {
if (shouldDisableSnapshots()) {
return;
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 5d82553ad284..4db8ef49a11a 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -338,6 +338,11 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
applyReady();
}
+ @VisibleForTesting
+ boolean allReady() {
+ return mReadyTracker.allReady();
+ }
+
/**
* Build a transaction that "resets" all the re-parenting and layer changes. This is
* intended to be applied at the end of the transition but before the finish callback. This
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 91825ccf98e7..e05457010df8 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -27,6 +27,7 @@ import static android.view.WindowManager.TRANSIT_OPEN;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.IApplicationThread;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.RemoteException;
@@ -35,7 +36,6 @@ import android.util.ArrayMap;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.WindowManager;
-import android.window.IRemoteTransition;
import android.window.ITransitionMetricsReporter;
import android.window.ITransitionPlayer;
import android.window.RemoteTransition;
@@ -69,6 +69,7 @@ class TransitionController {
private ITransitionPlayer mTransitionPlayer;
final TransitionMetricsReporter mTransitionMetricsReporter = new TransitionMetricsReporter();
+ private IApplicationThread mTransitionPlayerThread;
final ActivityTaskManagerService mAtm;
final TaskSnapshotController mTaskSnapshotController;
@@ -137,7 +138,8 @@ class TransitionController {
return mCollectingTransition;
}
- void registerTransitionPlayer(@Nullable ITransitionPlayer player) {
+ void registerTransitionPlayer(@Nullable ITransitionPlayer player,
+ @Nullable IApplicationThread appThread) {
try {
// Note: asBinder() can be null if player is same process (likely in a test).
if (mTransitionPlayer != null) {
@@ -150,6 +152,7 @@ class TransitionController {
player.asBinder().linkToDeath(mTransitionPlayerDeath, 0);
}
mTransitionPlayer = player;
+ mTransitionPlayerThread = appThread;
} catch (RemoteException e) {
throw new RuntimeException("Unable to set transition player");
}
@@ -226,7 +229,7 @@ class TransitionController {
}
/**
- * @see #requestTransitionIfNeeded(int, int, WindowContainer, IRemoteTransition)
+ * @see #requestTransitionIfNeeded(int, int, WindowContainer, WindowContainer, RemoteTransition)
*/
@Nullable
Transition requestTransitionIfNeeded(@WindowManager.TransitionType int type,
@@ -235,7 +238,7 @@ class TransitionController {
}
/**
- * @see #requestTransitionIfNeeded(int, int, WindowContainer, IRemoteTransition)
+ * @see #requestTransitionIfNeeded(int, int, WindowContainer, WindowContainer, RemoteTransition)
*/
@Nullable
Transition requestTransitionIfNeeded(@WindowManager.TransitionType int type,
@@ -306,6 +309,22 @@ class TransitionController {
return transition;
}
+ /** Requests transition for a window container which will be removed or invisible. */
+ void requestCloseTransitionIfNeeded(@NonNull WindowContainer<?> wc) {
+ if (mTransitionPlayer == null) return;
+ if (wc.isVisibleRequested()) {
+ if (!isCollecting()) {
+ requestStartTransition(createTransition(TRANSIT_CLOSE, 0 /* flags */),
+ wc.asTask(), null /* remoteTransition */);
+ }
+ collectExistenceChange(wc);
+ } else {
+ // Removing a non-visible window doesn't require a transition, but if there is one
+ // collecting, this should be a member just in case.
+ collect(wc);
+ }
+ }
+
/** @see Transition#collect */
void collect(@NonNull WindowContainer wc) {
if (mCollectingTransition == null) return;
@@ -347,6 +366,9 @@ class TransitionController {
}
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Finish Transition: %s", record);
mPlayingTransitions.remove(record);
+ if (mPlayingTransitions.isEmpty()) {
+ setAnimationRunning(false /* running */);
+ }
record.finishTransition();
mRunningLock.doNotifyLocked();
}
@@ -356,9 +378,22 @@ class TransitionController {
throw new IllegalStateException("Trying to move non-collecting transition to playing");
}
mCollectingTransition = null;
+ if (mPlayingTransitions.isEmpty()) {
+ setAnimationRunning(true /* running */);
+ }
mPlayingTransitions.add(transition);
}
+ private void setAnimationRunning(boolean running) {
+ if (mTransitionPlayerThread == null) return;
+ final WindowProcessController wpc = mAtm.getProcessController(mTransitionPlayerThread);
+ if (wpc == null) {
+ Slog.w(TAG, "Unable to find process for player thread=" + mTransitionPlayerThread);
+ return;
+ }
+ wpc.setRunningRemoteAnimation(running);
+ }
+
void abort(Transition transition) {
if (transition != mCollectingTransition) {
throw new IllegalStateException("Too late to abort.");
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index d93b649b390a..4b2aa0f76272 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -165,7 +165,8 @@ class WallpaperController {
boolean needsShowWhenLockedWallpaper = false;
if ((w.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0
&& mService.mPolicy.isKeyguardLocked()
- && mService.mPolicy.isKeyguardOccluded()) {
+ && (mService.mPolicy.isKeyguardOccluded()
+ || mService.mPolicy.isKeyguardUnoccluding())) {
// The lowest show when locked window decides whether we need to put the wallpaper
// behind.
needsShowWhenLockedWallpaper = !isFullscreen(w.mAttrs)
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 51ecce0ec9ec..58bc244e9250 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -32,10 +32,6 @@ import static android.os.UserHandle.USER_NULL;
import static android.view.SurfaceControl.Transaction;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
import static android.view.WindowManager.TRANSIT_CHANGE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_BACK;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_FRONT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
@@ -43,6 +39,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SYNC_ENGINE;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.AppTransition.MAX_APP_TRANSITION_DURATION;
+import static com.android.server.wm.AppTransition.isTaskTransitOld;
import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
import static com.android.server.wm.IdentifierProto.HASH_CODE;
import static com.android.server.wm.IdentifierProto.TITLE;
@@ -70,7 +67,6 @@ import android.annotation.ColorInt;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.ActivityThread;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -91,6 +87,7 @@ import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Builder;
import android.view.SurfaceSession;
+import android.view.TaskTransitionSpec;
import android.view.WindowManager;
import android.view.WindowManager.TransitionOldType;
import android.view.animation.Animation;
@@ -111,6 +108,7 @@ import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiFunction;
import java.util.function.Consumer;
@@ -616,7 +614,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
final DisplayContent dc = getDisplayContent();
if (dc != null) {
mSurfaceFreezer.unfreeze(getSyncTransaction());
- dc.mChangingContainers.remove(this);
}
while (!mChildren.isEmpty()) {
final E child = mChildren.peekLast();
@@ -1069,9 +1066,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
// part of a change transition.
if (!visible) {
mSurfaceFreezer.unfreeze(getSyncTransaction());
- if (mDisplayContent != null) {
- mDisplayContent.mChangingContainers.remove(this);
- }
}
WindowContainer parent = getParent();
if (parent != null) {
@@ -2650,6 +2644,13 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
@Override
+ public void onUnfrozen() {
+ if (mDisplayContent != null) {
+ mDisplayContent.mChangingContainers.remove(this);
+ }
+ }
+
+ @Override
public Builder makeAnimationLeash() {
return makeSurface().setContainerLayer();
}
@@ -2734,6 +2735,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
// Separate position and size for use in animators.
final Rect screenBounds = getAnimationBounds(appRootTaskClipMode);
mTmpRect.set(screenBounds);
+ if (this.asTask() != null && isTaskTransitOld(transit)) {
+ this.asTask().adjustAnimationBoundsForTransition(mTmpRect);
+ }
getAnimationPosition(mTmpPoint);
mTmpRect.offsetTo(0, 0);
@@ -2825,33 +2829,20 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
mSurfaceAnimationSources.addAll(sources);
}
- TaskDisplayArea taskDisplayArea = getTaskDisplayArea();
- boolean isSettingBackgroundColor = taskDisplayArea != null
- && isTransitionWithBackgroundColor(transit);
-
- if (isSettingBackgroundColor) {
- Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();
- @ColorInt int backgroundColor = uiContext.getColor(R.color.overview_background);
-
- taskDisplayArea.setBackgroundColor(backgroundColor);
- }
+ AnimationRunnerBuilder animationRunnerBuilder = new AnimationRunnerBuilder();
- // Atomic counter to make sure the clearColor callback is only called one.
- // It will be called twice in the case we cancel the animation without restart
- // (in that case it will run as the cancel and finished callbacks).
- final AtomicInteger callbackCounter = new AtomicInteger(0);
- final Runnable clearBackgroundColorHandler = () -> {
- if (callbackCounter.getAndIncrement() == 0) {
- taskDisplayArea.clearBackgroundColor();
+ if (isTaskTransitOld(transit)) {
+ animationRunnerBuilder.setTaskBackgroundColor(getTaskAnimationBackgroundColor());
+ // TODO: Remove when we migrate to shell (b/202383002)
+ if (mWmService.mTaskTransitionSpec != null) {
+ animationRunnerBuilder.hideInsetSourceViewOverflows(
+ mWmService.mTaskTransitionSpec.animationBoundInsets);
}
- };
-
- final Runnable cleanUpCallback = isSettingBackgroundColor
- ? clearBackgroundColorHandler : () -> {};
+ }
- startAnimation(getPendingTransaction(), adapter, !isVisible(),
- ANIMATION_TYPE_APP_TRANSITION, (type, anim) -> cleanUpCallback.run(),
- cleanUpCallback, thumbnailAdapter);
+ animationRunnerBuilder.build()
+ .startAnimation(getPendingTransaction(), adapter, !isVisible(),
+ ANIMATION_TYPE_APP_TRANSITION, thumbnailAdapter);
if (adapter.getShowWallpaper()) {
getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
@@ -2859,11 +2850,16 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
}
- private boolean isTransitionWithBackgroundColor(@TransitionOldType int transit) {
- return transit == TRANSIT_OLD_TASK_OPEN
- || transit == TRANSIT_OLD_TASK_CLOSE
- || transit == TRANSIT_OLD_TASK_TO_FRONT
- || transit == TRANSIT_OLD_TASK_TO_BACK;
+ private @ColorInt int getTaskAnimationBackgroundColor() {
+ Context uiContext = mDisplayContent.getDisplayPolicy().getSystemUiContext();
+ TaskTransitionSpec customSpec = mWmService.mTaskTransitionSpec;
+ @ColorInt int defaultFallbackColor = uiContext.getColor(R.color.overview_background);
+
+ if (customSpec != null && customSpec.backgroundColor != 0) {
+ return customSpec.backgroundColor;
+ }
+
+ return defaultFallbackColor;
}
final SurfaceAnimationRunner getSurfaceAnimationRunner() {
@@ -3551,4 +3547,73 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
getPendingTransaction().setSecure(mSurfaceControl, !canScreenshot);
return true;
}
+
+ private class AnimationRunnerBuilder {
+ /**
+ * Runs when the surface stops animating
+ */
+ private final List<Runnable> mOnAnimationFinished = new LinkedList<>();
+ /**
+ * Runs when the animation is cancelled but the surface is still animating
+ */
+ private final List<Runnable> mOnAnimationCancelled = new LinkedList<>();
+
+ private void setTaskBackgroundColor(@ColorInt int backgroundColor) {
+ TaskDisplayArea taskDisplayArea = getTaskDisplayArea();
+
+ if (taskDisplayArea != null) {
+ taskDisplayArea.setBackgroundColor(backgroundColor);
+
+ // Atomic counter to make sure the clearColor callback is only called one.
+ // It will be called twice in the case we cancel the animation without restart
+ // (in that case it will run as the cancel and finished callbacks).
+ final AtomicInteger callbackCounter = new AtomicInteger(0);
+ final Runnable clearBackgroundColorHandler = () -> {
+ if (callbackCounter.getAndIncrement() == 0) {
+ taskDisplayArea.clearBackgroundColor();
+ }
+ };
+
+ // We want to make sure this is called both when the surface stops animating and
+ // also when an animation is cancelled (i.e. animation is replaced by another
+ // animation but and so the surface is still animating)
+ mOnAnimationFinished.add(clearBackgroundColorHandler);
+ mOnAnimationCancelled.add(clearBackgroundColorHandler);
+ }
+ }
+
+ private void hideInsetSourceViewOverflows(Set<Integer> insetTypes) {
+ final ArrayList<SurfaceControl> surfaceControls =
+ new ArrayList<>(insetTypes.size());
+
+ for (int insetType : insetTypes) {
+ InsetsSourceProvider insetProvider = getDisplayContent().getInsetsStateController()
+ .getSourceProvider(insetType);
+
+ // Will apply it immediately to current leash and to all future inset animations
+ // until we disable it.
+ insetProvider.setCropToProvidingInsetsBounds(getPendingTransaction());
+
+ // Only clear the size restriction of the inset once the surface animation is over
+ // and not if it's canceled to be replace by another animation.
+ mOnAnimationFinished.add(() -> {
+ insetProvider.removeCropToProvidingInsetsBounds(getPendingTransaction());
+ });
+ }
+ }
+
+ private IAnimationStarter build() {
+ return (Transaction t, AnimationAdapter adapter, boolean hidden,
+ @AnimationType int type, @Nullable AnimationAdapter snapshotAnim) -> {
+ startAnimation(getPendingTransaction(), adapter, !isVisible(), type,
+ (animType, anim) -> mOnAnimationFinished.forEach(Runnable::run),
+ () -> mOnAnimationCancelled.forEach(Runnable::run), snapshotAnim);
+ };
+ }
+ }
+
+ private interface IAnimationStarter {
+ void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
+ @AnimationType int type, @Nullable AnimationAdapter snapshotAnim);
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9b53d3e00a1e..943a3c12e5ed 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
import static android.Manifest.permission.INPUT_CONSUMER;
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
+import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS;
import static android.Manifest.permission.MANAGE_APP_TOKENS;
import static android.Manifest.permission.READ_FRAME_BUFFER;
import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS;
@@ -57,6 +58,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
@@ -266,6 +268,7 @@ import android.view.ScrollCaptureResponse;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
+import android.view.TaskTransitionSpec;
import android.view.View;
import android.view.WindowContentFrameStats;
import android.view.WindowInsets;
@@ -755,6 +758,11 @@ public class WindowManagerService extends IWindowManager.Stub
*/
final Handler mAnimationHandler = new Handler(AnimationThread.getHandler().getLooper());
+ /**
+ * Used during task transitions to allow SysUI and launcher to customize task transitions.
+ */
+ TaskTransitionSpec mTaskTransitionSpec;
+
boolean mHardKeyboardAvailable;
WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
SettingsObserver mSettingsObserver;
@@ -1775,6 +1783,7 @@ public class WindowManagerService extends IWindowManager.Stub
win.mToken.addWindow(win);
displayPolicy.addWindowLw(win, attrs);
+ displayPolicy.setDropInputModePolicy(win, win.mAttrs);
if (type == TYPE_APPLICATION_STARTING && activity != null) {
activity.attachStartingWindow(win);
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "addWindow: %s startingWindow=%s",
@@ -1854,7 +1863,7 @@ public class WindowManagerService extends IWindowManager.Stub
ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addWindow: New client %s"
+ ": window=%s Callers=%s", client.asBinder(), win, Debug.getCallers(5));
- if (win.isVisibleOrAdding() && displayContent.updateOrientation()) {
+ if (win.isVisibleRequestedOrAdding() && displayContent.updateOrientation()) {
displayContent.sendNewConfiguration();
}
@@ -3084,6 +3093,11 @@ public class WindowManagerService extends IWindowManager.Stub
syncInputTransactions(true /* waitForAnimations */);
}
+ @Override
+ public boolean isAppTransitionStateIdle() {
+ return getDefaultDisplayContentLocked().mAppTransition.isIdle();
+ }
+
/**
* Notifies activity manager that some Keyguard flags have changed and that it needs to
* reevaluate the visibilities of the activities.
@@ -8324,8 +8338,10 @@ public class WindowManagerService extends IWindowManager.Stub
h.setWindowToken(window);
h.name = name;
+ flags = DisplayPolicy.sanitizeFlagSlippery(flags, privateFlags, name);
+
final int sanitizedFlags = flags & (LayoutParams.FLAG_NOT_TOUCHABLE
- | LayoutParams.FLAG_SLIPPERY | LayoutParams.FLAG_NOT_FOCUSABLE);
+ | FLAG_SLIPPERY | LayoutParams.FLAG_NOT_FOCUSABLE);
h.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | sanitizedFlags;
h.layoutParamsType = type;
h.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
@@ -8776,4 +8792,22 @@ public class WindowManagerService extends IWindowManager.Stub
: DEFAULT_DISPLAY;
}
}
+
+ @Override
+ public void setTaskTransitionSpec(TaskTransitionSpec spec) {
+ if (!checkCallingPermission(MANAGE_ACTIVITY_TASKS, "setTaskTransitionSpec()")) {
+ throw new SecurityException("Requires MANAGE_ACTIVITY_TASKS permission");
+ }
+
+ mTaskTransitionSpec = spec;
+ }
+
+ @Override
+ public void clearTaskTransitionSpec() {
+ if (!checkCallingPermission(MANAGE_ACTIVITY_TASKS, "clearTaskTransitionSpec()")) {
+ throw new SecurityException("Requires MANAGE_ACTIVITY_TASKS permission");
+ }
+
+ mTaskTransitionSpec = null;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 6e706e9df003..bd8d1164ebef 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -45,6 +45,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
+import android.app.IApplicationThread;
import android.app.WindowConfiguration;
import android.content.ActivityNotFoundException;
import android.content.Intent;
@@ -566,41 +567,144 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: {
final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
final Task task = wc != null ? wc.asTask() : null;
+ final boolean clearRoot = hop.getToTop();
if (task == null) {
throw new IllegalArgumentException("Cannot set non-task as launch root: " + wc);
} else if (!task.mCreatedByOrganizer) {
throw new UnsupportedOperationException(
"Cannot set non-organized task as adjacent flag root: " + wc);
- } else if (task.getAdjacentTaskFragment() == null) {
+ } else if (task.getAdjacentTaskFragment() == null && !clearRoot) {
throw new UnsupportedOperationException(
"Cannot set non-adjacent task as adjacent flag root: " + wc);
}
- final boolean clearRoot = hop.getToTop();
task.getDisplayArea().setLaunchAdjacentFlagRootTask(clearRoot ? null : task);
break;
}
- case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS:
+ case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS: {
effects |= setAdjacentRootsHierarchyOp(hop);
break;
- }
- // The following operations may change task order so they are skipped while in lock task
- // mode. The above operations are still allowed because they don't move tasks. And it may
- // be necessary such as clearing launch root after entering lock task mode.
- if (isInLockTaskMode) {
- Slog.w(TAG, "Skip applying hierarchy operation " + hop + " while in lock task mode");
- return effects;
+ }
+ case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT: {
+ final TaskFragmentCreationParams taskFragmentCreationOptions =
+ hop.getTaskFragmentCreationOptions();
+ createTaskFragment(taskFragmentCreationOptions, errorCallbackToken);
+ break;
+ }
+ case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT: {
+ final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
+ if (wc == null || !wc.isAttached()) {
+ Slog.e(TAG, "Attempt to operate on unknown or detached container: " + wc);
+ break;
+ }
+ final TaskFragment taskFragment = wc.asTaskFragment();
+ if (taskFragment == null || taskFragment.asTask() != null) {
+ throw new IllegalArgumentException(
+ "Can only delete organized TaskFragment, but not Task.");
+ }
+ if (isInLockTaskMode) {
+ final ActivityRecord bottomActivity = taskFragment.getActivity(
+ a -> !a.finishing, false /* traverseTopToBottom */);
+ if (bottomActivity != null
+ && mService.getLockTaskController().activityBlockedFromFinish(
+ bottomActivity)) {
+ Slog.w(TAG, "Skip removing TaskFragment due in lock task mode.");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken,
+ new IllegalStateException(
+ "Not allow to delete task fragment in lock task mode."));
+ break;
+ }
+ }
+ effects |= deleteTaskFragment(taskFragment, errorCallbackToken);
+ break;
+ }
+ case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: {
+ final IBinder fragmentToken = hop.getContainer();
+ if (!mLaunchTaskFragments.containsKey(fragmentToken)) {
+ final Throwable exception = new IllegalArgumentException(
+ "Not allowed to operate with invalid fragment token");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
+ break;
+ }
+ final Intent activityIntent = hop.getActivityIntent();
+ final Bundle activityOptions = hop.getLaunchOptions();
+ final TaskFragment tf = mLaunchTaskFragments.get(fragmentToken);
+ final int result = mService.getActivityStartController()
+ .startActivityInTaskFragment(tf, activityIntent, activityOptions,
+ hop.getCallingActivity());
+ if (!isStartResultSuccessful(result)) {
+ sendTaskFragmentOperationFailure(tf.getTaskFragmentOrganizer(),
+ errorCallbackToken,
+ convertStartFailureToThrowable(result, activityIntent));
+ }
+ break;
+ }
+ case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: {
+ final IBinder fragmentToken = hop.getNewParent();
+ final ActivityRecord activity = ActivityRecord.forTokenLocked(hop.getContainer());
+ if (!mLaunchTaskFragments.containsKey(fragmentToken) || activity == null) {
+ final Throwable exception = new IllegalArgumentException(
+ "Not allowed to operate with invalid fragment token or activity.");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
+ break;
+ }
+ activity.reparent(mLaunchTaskFragments.get(fragmentToken), POSITION_TOP);
+ effects |= TRANSACT_EFFECTS_LIFECYCLE;
+ break;
+ }
+ case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS: {
+ final IBinder fragmentToken = hop.getContainer();
+ final IBinder adjacentFragmentToken = hop.getAdjacentRoot();
+ final TaskFragment tf1 = mLaunchTaskFragments.get(fragmentToken);
+ 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);
+ break;
+ }
+ tf1.setAdjacentTaskFragment(tf2);
+ effects |= TRANSACT_EFFECTS_LIFECYCLE;
+
+ final Bundle bundle = hop.getLaunchOptions();
+ final WindowContainerTransaction.TaskFragmentAdjacentParams adjacentParams =
+ bundle != null ? new WindowContainerTransaction.TaskFragmentAdjacentParams(
+ bundle) : null;
+ if (adjacentParams == null) {
+ break;
+ }
+
+ tf1.setDelayLastActivityRemoval(
+ adjacentParams.shouldDelayPrimaryLastActivityRemoval());
+ if (tf2 != null) {
+ tf2.setDelayLastActivityRemoval(
+ adjacentParams.shouldDelaySecondaryLastActivityRemoval());
+ }
+ break;
+ }
+ default: {
+ // The other operations may change task order so they are skipped while in lock
+ // task mode. The above operations are still allowed because they don't move
+ // tasks. And it may be necessary such as clearing launch root after entering
+ // lock task mode.
+ if (isInLockTaskMode) {
+ Slog.w(TAG, "Skip applying hierarchy operation " + hop
+ + " while in lock task mode");
+ return effects;
+ }
+ }
}
- final WindowContainer wc;
- final IBinder fragmentToken;
switch (type) {
- case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT:
+ case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: {
effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId);
break;
+ }
case HIERARCHY_OP_TYPE_REORDER:
- case HIERARCHY_OP_TYPE_REPARENT:
- wc = WindowContainer.fromBinder(hop.getContainer());
+ case HIERARCHY_OP_TYPE_REPARENT: {
+ final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
if (wc == null || !wc.isAttached()) {
Slog.e(TAG, "Attempt to operate on detached container: " + wc);
break;
@@ -629,7 +733,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
effects |= sanitizeAndApplyHierarchyOp(wc, hop);
break;
- case HIERARCHY_OP_TYPE_LAUNCH_TASK:
+ }
+ case HIERARCHY_OP_TYPE_LAUNCH_TASK: {
mService.mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
"launchTask HierarchyOp");
final Bundle launchOpts = hop.getLaunchOptions();
@@ -638,7 +743,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
final SafeActivityOptions safeOptions =
SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid);
- final Integer[] starterResult = { null };
+ final Integer[] starterResult = {null};
// startActivityFromRecents should not be called in lock.
mService.mH.post(() -> {
try {
@@ -659,10 +764,11 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
}
break;
- case HIERARCHY_OP_TYPE_PENDING_INTENT:
+ }
+ case HIERARCHY_OP_TYPE_PENDING_INTENT: {
String resolvedType = hop.getActivityIntent() != null
? hop.getActivityIntent().resolveTypeIfNeeded(
- mService.mContext.getContentResolver())
+ mService.mContext.getContentResolver())
: null;
Bundle options = null;
@@ -682,57 +788,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
hop.getActivityIntent(), resolvedType, null /* finishReceiver */,
null /* requiredPermission */, options);
break;
- case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT:
- final TaskFragmentCreationParams taskFragmentCreationOptions =
- hop.getTaskFragmentCreationOptions();
- createTaskFragment(taskFragmentCreationOptions, errorCallbackToken);
- break;
- case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT:
- wc = WindowContainer.fromBinder(hop.getContainer());
- if (wc == null || !wc.isAttached()) {
- Slog.e(TAG, "Attempt to operate on unknown or detached container: " + wc);
- break;
- }
- final TaskFragment taskFragment = wc.asTaskFragment();
- if (taskFragment == null || taskFragment.asTask() != null) {
- throw new IllegalArgumentException(
- "Can only delete organized TaskFragment, but not Task.");
- }
- effects |= deleteTaskFragment(taskFragment, errorCallbackToken);
- break;
- case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
- fragmentToken = hop.getContainer();
- if (!mLaunchTaskFragments.containsKey(fragmentToken)) {
- final Throwable exception = new IllegalArgumentException(
- "Not allowed to operate with invalid fragment token");
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
- break;
- }
- final Intent activityIntent = hop.getActivityIntent();
- final Bundle activityOptions = hop.getLaunchOptions();
- final TaskFragment tf = mLaunchTaskFragments.get(fragmentToken);
- final int result = mService.getActivityStartController()
- .startActivityInTaskFragment(tf, activityIntent, activityOptions,
- hop.getCallingActivity());
- if (!isStartResultSuccessful(result)) {
- sendTaskFragmentOperationFailure(tf.getTaskFragmentOrganizer(),
- errorCallbackToken,
- convertStartFailureToThrowable(result, activityIntent));
- }
- break;
- case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT:
- fragmentToken = hop.getNewParent();
- final ActivityRecord activity = ActivityRecord.forTokenLocked(hop.getContainer());
- if (!mLaunchTaskFragments.containsKey(fragmentToken) || activity == null) {
- final Throwable exception = new IllegalArgumentException(
- "Not allowed to operate with invalid fragment token or activity.");
- sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
- break;
- }
- activity.reparent(mLaunchTaskFragments.get(fragmentToken), POSITION_TOP);
- effects |= TRANSACT_EFFECTS_LIFECYCLE;
- break;
- case HIERARCHY_OP_TYPE_REPARENT_CHILDREN:
+ }
+ case HIERARCHY_OP_TYPE_REPARENT_CHILDREN: {
final WindowContainer oldParent = WindowContainer.fromBinder(hop.getContainer());
final WindowContainer newParent = hop.getNewParent() != null
? WindowContainer.fromBinder(hop.getNewParent())
@@ -745,37 +802,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
reparentTaskFragment(oldParent, newParent, errorCallbackToken);
effects |= TRANSACT_EFFECTS_LIFECYCLE;
break;
- case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS:
- fragmentToken = hop.getContainer();
- final IBinder adjacentFragmentToken = hop.getAdjacentRoot();
- final TaskFragment tf1 = mLaunchTaskFragments.get(fragmentToken);
- 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);
- break;
- }
- tf1.setAdjacentTaskFragment(tf2);
- effects |= TRANSACT_EFFECTS_LIFECYCLE;
-
- final Bundle bundle = hop.getLaunchOptions();
- final WindowContainerTransaction.TaskFragmentAdjacentParams adjacentParams =
- bundle != null ? new WindowContainerTransaction.TaskFragmentAdjacentParams(
- bundle) : null;
- if (adjacentParams == null) {
- break;
- }
-
- tf1.setDelayLastActivityRemoval(
- adjacentParams.shouldDelayPrimaryLastActivityRemoval());
- if (tf2 != null) {
- tf2.setDelayLastActivityRemoval(
- adjacentParams.shouldDelaySecondaryLastActivityRemoval());
- }
- break;
+ }
}
return effects;
}
@@ -1031,10 +1058,18 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
@Override
public void registerTransitionPlayer(ITransitionPlayer player) {
enforceTaskPermission("registerTransitionPlayer()");
+ final int callerPid = Binder.getCallingPid();
+ final int callerUid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- mTransitionController.registerTransitionPlayer(player);
+ final WindowProcessController wpc =
+ mService.getProcessController(callerPid, callerUid);
+ IApplicationThread appThread = null;
+ if (wpc != null) {
+ appThread = wpc.getThread();
+ }
+ mTransitionController.registerTransitionPlayer(player, appThread);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -1177,6 +1212,12 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
return;
}
+ if (!ownerActivity.isResizeable()) {
+ final IllegalArgumentException exception = new IllegalArgumentException("Not allowed"
+ + " to operate with non-resizable owner Activity");
+ sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
+ return;
+ }
// The ownerActivity has to belong to the same app as the root Activity of the target Task.
final ActivityRecord rootActivity = ownerActivity.getTask().getRootActivity();
if (rootActivity.getUid() != ownerActivity.getUid()) {
@@ -1190,8 +1231,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
creationParams.getFragmentToken(), true /* createdByOrganizer */);
// Set task fragment organizer immediately, since it might have to be notified about further
// actions.
- taskFragment.setTaskFragmentOrganizer(
- creationParams.getOrganizer(), ownerActivity.getPid());
+ taskFragment.setTaskFragmentOrganizer(creationParams.getOrganizer(),
+ ownerActivity.getUid(), ownerActivity.info.processName);
ownerActivity.getTask().addChild(taskFragment, POSITION_TOP);
taskFragment.setWindowingMode(creationParams.getWindowingMode());
taskFragment.setBounds(creationParams.getInitialBounds());
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index af386419d455..1cfbe07d3f16 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -1110,7 +1110,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
void updateProcessInfo(boolean updateServiceConnectionActivities, boolean activityChange,
boolean updateOomAdj, boolean addPendingTopUid) {
if (addPendingTopUid) {
- mAtm.mAmInternal.addPendingTopUid(mUid, mPid);
+ addToPendingTop();
}
if (updateOomAdj) {
prepareOomAdjustment();
@@ -1121,6 +1121,11 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
mAtm.mH.sendMessage(m);
}
+ /** Makes the process have top state before oom-adj is computed from a posted message. */
+ void addToPendingTop() {
+ mAtm.mAmInternal.addPendingTopUid(mUid, mPid);
+ }
+
void updateServiceConnectionActivities() {
// Posting on handler so WM lock isn't held when we call into AM.
mAtm.mH.sendMessage(PooledLambda.obtainMessage(
@@ -1559,7 +1564,9 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
// activity as it could lead to incorrect display metrics. For ex, IME services
// expect their config to match the config of the display with the IME window
// showing.
+ // If the configuration has been overridden by previous activity, empty it.
mIsActivityConfigOverrideAllowed = false;
+ unregisterActivityConfigurationListener();
break;
default:
break;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 8fafc7d64c29..e0c3cf968f5c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1993,14 +1993,20 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
/**
- * Same as isVisible(), but we also count it as visible between the
- * call to IWindowSession.add() and the first relayout().
+ * Is this window capable of being visible (policy and content), in a visible part of the
+ * hierarchy, and, if an activity window, the activity is visible-requested. Note, this means
+ * if the activity is going-away, this will be {@code false} even when the window is visible.
+ *
+ * The 'adding' part refers to the period of time between IWindowSession.add() and the first
+ * relayout() -- which, for activities, is the same as visibleRequested.
+ *
+ * TODO(b/206005136): This is very similar to isVisibleRequested(). Investigate merging them.
*/
- boolean isVisibleOrAdding() {
+ boolean isVisibleRequestedOrAdding() {
final ActivityRecord atoken = mActivityRecord;
return (mHasSurface || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
&& isVisibleByPolicy() && !isParentWindowHidden()
- && (atoken == null || atoken.isVisible())
+ && (atoken == null || atoken.mVisibleRequested)
&& !mAnimatingExit && !mDestroying;
}
@@ -2732,8 +2738,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
if (DEBUG_INPUT_METHOD) {
- Slog.i(TAG_WM, "isVisibleOrAdding " + this + ": " + isVisibleOrAdding());
- if (!isVisibleOrAdding()) {
+ Slog.i(TAG_WM, "isVisibleRequestedOrAdding " + this + ": "
+ + isVisibleRequestedOrAdding());
+ if (!isVisibleRequestedOrAdding()) {
Slog.i(TAG_WM, " mSurfaceController=" + mWinAnimator.mSurfaceController
+ " relayoutCalled=" + mRelayoutCalled
+ " viewVis=" + mViewVisibility
@@ -2747,7 +2754,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
}
- return isVisibleOrAdding();
+ return isVisibleRequestedOrAdding();
}
private final class DeadWindowEventReceiver extends InputEventReceiver {
@@ -3173,7 +3180,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
public String canReceiveKeysReason(boolean fromUserTouch) {
return "fromTouch= " + fromUserTouch
- + " isVisibleOrAdding=" + isVisibleOrAdding()
+ + " isVisibleRequestedOrAdding=" + isVisibleRequestedOrAdding()
+ " mViewVisibility=" + mViewVisibility
+ " mRemoveOnExit=" + mRemoveOnExit
+ " flags=" + mAttrs.flags
@@ -3185,7 +3192,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
public boolean canReceiveKeys(boolean fromUserTouch) {
- final boolean canReceiveKeys = isVisibleOrAdding()
+ final boolean canReceiveKeys = isVisibleRequestedOrAdding()
&& (mViewVisibility == View.VISIBLE) && !mRemoveOnExit
&& ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0)
&& (mActivityRecord == null || mActivityRecord.windowsAreFocusable(fromUserTouch))
@@ -3451,7 +3458,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
public void pokeDrawLockLw(long timeout) {
- if (isVisibleOrAdding()) {
+ if (isVisibleRequestedOrAdding()) {
if (mDrawLock == null) {
// We want the tag name to be somewhat stable so that it is easier to correlate
// in wake lock statistics. So in particular, we don't want to include the
@@ -4967,20 +4974,27 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
private boolean applyImeWindowsIfNeeded(ToBooleanFunction<WindowState> callback,
boolean traverseTopToBottom) {
- // If this window is the current IME target, so we need to process the IME windows
- // directly above it. The exception is if we are in split screen
- // in which case we process the IME at the DisplayContent level to
+ // No need to apply to IME window if the window is not the current IME layering target.
+ if (!isImeLayeringTarget()) {
+ return false;
+ }
+ // If we are in split screen which case we process the IME at the DisplayContent level to
// ensure it is above the docked divider.
- // (i.e. Like {@link DisplayContent.ImeContainer#skipImeWindowsDuringTraversal}, the IME
- // window will be ignored to traverse when the IME target is still in split-screen mode).
- if (isImeLayeringTarget()
- && (!mDisplayContent.getDefaultTaskDisplayArea().isSplitScreenModeActivated()
- || getTask() == null)) {
- if (mDisplayContent.forAllImeWindows(callback, traverseTopToBottom)) {
- return true;
- }
+ // i.e. Like {@link DisplayContent.ImeContainer#skipImeWindowsDuringTraversal}, the IME
+ // window will be ignored to traverse when the IME target is still in split-screen mode.
+ if (mDisplayContent.getDefaultTaskDisplayArea().isSplitScreenModeActivated()
+ && getTask() != null) {
+ return false;
}
- return false;
+ // Note that we don't process IME window if the IME input target is not on the screen.
+ // In case some unexpected IME visibility cases happen like starting the remote
+ // animation on the keyguard but seeing the IME window that originally on the app
+ // which behinds the keyguard.
+ final WindowState imeInputTarget = getImeInputTarget();
+ if (imeInputTarget != null && !(imeInputTarget.isDrawn() || imeInputTarget.isVisible())) {
+ return false;
+ }
+ return mDisplayContent.forAllImeWindows(callback, traverseTopToBottom);
}
private boolean applyInOrderWithImeWindows(ToBooleanFunction<WindowState> callback,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index a3ff6da9782b..22c4feb18170 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -697,6 +697,20 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private DevicePolicyConstants mConstants;
+ /**
+ * User to be switched to on {@code logoutUser()}.
+ *
+ * <p>Only used on devices with headless system user mode
+ */
+ @GuardedBy("getLockObject()")
+ private @UserIdInt int mLogoutUserId = UserHandle.USER_NULL;
+
+ /**
+ * User the network logging notification was sent to.
+ */
+ // Guarded by mHandler
+ private @UserIdInt int mNetworkLoggingNotificationUserId = UserHandle.USER_NULL;
+
private static final boolean ENABLE_LOCK_GUARD = true;
/**
@@ -3836,9 +3850,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ private boolean notSupportedOnAutomotive(String method) {
+ if (mIsAutomotive) {
+ Slogf.i(LOG_TAG, "%s is not supported on automotive builds", method);
+ return true;
+ }
+ return false;
+ }
+
@Override
public void setPasswordQuality(ComponentName who, int quality, boolean parent) {
- if (!mHasFeature) {
+ if (!mHasFeature || notSupportedOnAutomotive("setPasswordQuality")) {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
@@ -4073,7 +4095,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setPasswordMinimumLength(ComponentName who, int length, boolean parent) {
- if (!mHasFeature) {
+ if (!mHasFeature || notSupportedOnAutomotive("setPasswordMinimumLength")) {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
@@ -4355,7 +4377,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setPasswordMinimumUpperCase(ComponentName who, int length, boolean parent) {
- if (!mHasFeature) {
+ if (!mHasFeature || notSupportedOnAutomotive("setPasswordMinimumUpperCase")) {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
@@ -4388,6 +4410,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setPasswordMinimumLowerCase(ComponentName who, int length, boolean parent) {
+ if (notSupportedOnAutomotive("setPasswordMinimumLowerCase")) {
+ return;
+ }
Objects.requireNonNull(who, "ComponentName is null");
final int userId = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
@@ -4418,7 +4443,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setPasswordMinimumLetters(ComponentName who, int length, boolean parent) {
- if (!mHasFeature) {
+ if (!mHasFeature || notSupportedOnAutomotive("setPasswordMinimumLetters")) {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
@@ -4450,7 +4475,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setPasswordMinimumNumeric(ComponentName who, int length, boolean parent) {
- if (!mHasFeature) {
+ if (!mHasFeature || notSupportedOnAutomotive("setPasswordMinimumNumeric")) {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
@@ -4482,7 +4507,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setPasswordMinimumSymbols(ComponentName who, int length, boolean parent) {
- if (!mHasFeature) {
+ if (!mHasFeature || notSupportedOnAutomotive("setPasswordMinimumSymbols")) {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
@@ -4514,7 +4539,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setPasswordMinimumNonLetter(ComponentName who, int length, boolean parent) {
- if (!mHasFeature) {
+ if (!mHasFeature || notSupportedOnAutomotive("setPasswordMinimumNonLetter")) {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
@@ -9556,7 +9581,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private @UserIdInt int getCurrentForegroundUserId() {
try {
- return mInjector.getIActivityManager().getCurrentUser().id;
+ UserInfo currentUser = mInjector.getIActivityManager().getCurrentUser();
+ if (currentUser == null) {
+ // TODO(b/206107460): should not happen on production, but it's happening on unit
+ // tests that are not properly setting the expectation (because they don't need it)
+ Slogf.wtf(LOG_TAG, "getCurrentForegroundUserId(): mInjector.getIActivityManager()"
+ + ".getCurrentUser() returned null, please ignore when running unit tests");
+ return ActivityManager.getCurrentUser();
+ }
+ return currentUser.id;
} catch (RemoteException e) {
Slogf.wtf(LOG_TAG, "cannot get current user");
}
@@ -9673,6 +9706,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mStatLogger.dump(pw);
pw.println();
pw.println("Encryption Status: " + getEncryptionStatusName(getEncryptionStatus()));
+ pw.println("Logout user: " + getLogoutUserIdUnchecked());
pw.println();
if (mPendingUserCreatedCallbackTokens.isEmpty()) {
@@ -9689,10 +9723,18 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mStateCache.dump(pw);
pw.println();
}
+ mHandler.post(() -> handleDump(pw));
dumpResources(pw);
}
}
+ // Dump state that is guarded by the handler
+ private void handleDump(IndentingPrintWriter pw) {
+ if (mNetworkLoggingNotificationUserId != UserHandle.USER_NULL) {
+ pw.println("mNetworkLoggingNotificationUserId: " + mNetworkLoggingNotificationUserId);
+ }
+ }
+
private void dumpImmutableState(IndentingPrintWriter pw) {
pw.println("Immutable state:");
pw.increaseIndent();
@@ -10782,6 +10824,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Preconditions.checkCallAuthorization(isDeviceOwner(caller));
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SWITCH_USER);
+ boolean switched = false;
+ // Save previous logout user id in case of failure
+ int logoutUserId = getLogoutUserIdUnchecked();
synchronized (getLockObject()) {
long id = mInjector.binderClearCallingIdentity();
try {
@@ -10789,17 +10834,72 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (userHandle != null) {
userId = userHandle.getIdentifier();
}
- return mInjector.getIActivityManager().switchUser(userId);
+ Slogf.i(LOG_TAG, "Switching to user %d (logout user is %d)", userId, logoutUserId);
+ setLogoutUserIdLocked(UserHandle.USER_CURRENT);
+ switched = mInjector.getIActivityManager().switchUser(userId);
+ if (!switched) {
+ Slogf.w(LOG_TAG, "Failed to switch to user %d", userId);
+ }
+ return switched;
} catch (RemoteException e) {
Slogf.e(LOG_TAG, "Couldn't switch user", e);
return false;
} finally {
mInjector.binderRestoreCallingIdentity(id);
+ if (!switched) {
+ setLogoutUserIdLocked(logoutUserId);
+ }
}
}
}
@Override
+ public int getLogoutUserId() {
+ Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
+
+ return getLogoutUserIdUnchecked();
+ }
+
+ private @UserIdInt int getLogoutUserIdUnchecked() {
+ if (!mInjector.userManagerIsHeadlessSystemUserMode()) {
+ // mLogoutUserId is USER_SYSTEM as well, but there's no need to acquire the lock
+ return UserHandle.USER_SYSTEM;
+ }
+ synchronized (getLockObject()) {
+ return mLogoutUserId;
+ }
+ }
+
+ @Override
+ public void clearLogoutUser() {
+ CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(canManageUsers(caller));
+
+ Slogf.i(LOG_TAG, "Clearing logout user as requested by %s", caller);
+ clearLogoutUserUnchecked();
+ }
+
+ private void clearLogoutUserUnchecked() {
+ if (!mInjector.userManagerIsHeadlessSystemUserMode()) return; // ignore
+
+ synchronized (getLockObject()) {
+ setLogoutUserIdLocked(UserHandle.USER_NULL);
+ }
+ }
+
+ @GuardedBy("getLockObject()")
+ private void setLogoutUserIdLocked(@UserIdInt int userId) {
+ if (!mInjector.userManagerIsHeadlessSystemUserMode()) return; // ignore
+
+ if (userId == UserHandle.USER_CURRENT) {
+ userId = getCurrentForegroundUserId();
+ }
+
+ Slogf.d(LOG_TAG, "setLogoutUserId(): %d -> %d", mLogoutUserId, userId);
+ mLogoutUserId = userId;
+ }
+
+ @Override
public int startUserInBackground(ComponentName who, UserHandle userHandle) {
Objects.requireNonNull(who, "ComponentName is null");
Objects.requireNonNull(userHandle, "UserHandle is null");
@@ -10820,10 +10920,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return UserManager.USER_OPERATION_ERROR_MAX_RUNNING_USERS;
}
+ Slogf.i(LOG_TAG, "Starting user %d in background", userId);
if (mInjector.getIActivityManager().startUserInBackground(userId)) {
- Slogf.i(LOG_TAG, "Started used %d in background", userId);
return UserManager.USER_OPERATION_SUCCESS;
} else {
+ Slogf.w(LOG_TAG, "failed to start user %d in background", userId);
return UserManager.USER_OPERATION_ERROR_UNKNOWN;
}
} catch (RemoteException e) {
@@ -10871,13 +10972,30 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return UserManager.USER_OPERATION_ERROR_MANAGED_PROFILE;
}
+ // TODO(b/204585343): remove the headless system user check?
+ if (mInjector.userManagerIsHeadlessSystemUserMode() && callingUserId != mInjector
+ .binderWithCleanCallingIdentity(() -> getCurrentForegroundUserId())) {
+ Slogf.d(LOG_TAG, "logoutUser(): user %d is in background, just stopping, not switching",
+ callingUserId);
+ return stopUserUnchecked(callingUserId);
+ }
+
+ int logoutUserId = getLogoutUserIdUnchecked();
+ if (logoutUserId == UserHandle.USER_NULL) {
+ // Could happen on devices using headless system user mode when called before calling
+ // switchUser() or startUserInBackground() first
+ Slogf.w(LOG_TAG, "logoutUser(): could not determine which user to switch to");
+ return UserManager.USER_OPERATION_ERROR_UNKNOWN;
+ }
final long id = mInjector.binderClearCallingIdentity();
try {
- if (!mInjector.getIActivityManager().switchUser(UserHandle.USER_SYSTEM)) {
- Slogf.w(LOG_TAG, "Failed to switch to primary user");
- // This should never happen as target user is UserHandle.USER_SYSTEM
+ Slogf.i(LOG_TAG, "logoutUser(): switching to user %d", logoutUserId);
+ if (!mInjector.getIActivityManager().switchUser(logoutUserId)) {
+ Slogf.w(LOG_TAG, "Failed to switch to user %d", logoutUserId);
+ // This should never happen as target user is determined by getPreviousUserId()
return UserManager.USER_OPERATION_ERROR_UNKNOWN;
}
+ clearLogoutUserUnchecked();
} catch (RemoteException e) {
// Same process, should not happen.
return UserManager.USER_OPERATION_ERROR_UNKNOWN;
@@ -10888,7 +11006,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return stopUserUnchecked(callingUserId);
}
- private int stopUserUnchecked(int userId) {
+ private int stopUserUnchecked(@UserIdInt int userId) {
+ Slogf.i(LOG_TAG, "Stopping user %d", userId);
final long id = mInjector.binderClearCallingIdentity();
try {
switch (mInjector.getIActivityManager().stopUser(userId, true /*force*/, null)) {
@@ -12671,6 +12790,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
+ public @Nullable ComponentName getProfileOwnerOrDeviceOwnerSupervisionComponent(
+ @NonNull UserHandle userHandle) {
+ return DevicePolicyManagerService.this.getProfileOwnerOrDeviceOwnerSupervisionComponent(
+ userHandle);
+ }
+
+ @Override
public boolean isActiveDeviceOwner(int uid) {
return isDeviceOwner(new CallerIdentity(uid, null, null));
}
@@ -15095,11 +15221,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
if (active) {
if (shouldSendNotification) {
- mHandler.post(() -> sendNetworkLoggingNotification());
+ mHandler.post(() -> handleSendNetworkLoggingNotification());
}
} else {
- mHandler.post(() -> mInjector.getNotificationManager().cancel(
- SystemMessage.NOTE_NETWORK_LOGGING));
+ mHandler.post(() -> handleCancelNetworkLoggingNotification());
}
});
}
@@ -15290,10 +15415,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return true;
}
- private void sendNetworkLoggingNotification() {
+ private void handleSendNetworkLoggingNotification() {
final PackageManagerInternal pm = mInjector.getPackageManagerInternal();
final Intent intent = new Intent(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG);
intent.setPackage(pm.getSystemUiServiceComponent().getPackageName());
+ mNetworkLoggingNotificationUserId = getCurrentForegroundUserId();
// Simple notification clicks are immutable
final PendingIntent pendingIntent = PendingIntent.getBroadcastAsUser(mContext, 0, intent,
PendingIntent.FLAG_IMMUTABLE, UserHandle.CURRENT);
@@ -15308,7 +15434,26 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
.setStyle(new Notification.BigTextStyle()
.bigText(mContext.getString(R.string.network_logging_notification_text)))
.build();
- mInjector.getNotificationManager().notify(SystemMessage.NOTE_NETWORK_LOGGING, notification);
+ Slogf.i(LOG_TAG, "Sending network logging notification to user %d",
+ mNetworkLoggingNotificationUserId);
+ mInjector.getNotificationManager().notifyAsUser(/* tag= */ null,
+ SystemMessage.NOTE_NETWORK_LOGGING, notification,
+ UserHandle.of(mNetworkLoggingNotificationUserId));
+ }
+
+ private void handleCancelNetworkLoggingNotification() {
+ if (mNetworkLoggingNotificationUserId == UserHandle.USER_NULL) {
+ // Happens when setNetworkLoggingActive(false) is called before called with true
+ Slogf.d(LOG_TAG, "Not cancelling network logging notification for USER_NULL");
+ return;
+ }
+
+ Slogf.i(LOG_TAG, "Cancelling network logging notification for user %d",
+ mNetworkLoggingNotificationUserId);
+ mInjector.getNotificationManager().cancelAsUser(/* tag= */ null,
+ SystemMessage.NOTE_NETWORK_LOGGING,
+ UserHandle.of(mNetworkLoggingNotificationUserId));
+ mNetworkLoggingNotificationUserId = UserHandle.USER_NULL;
}
/**
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
index 6c2a8916617b..19eb456a9a95 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
@@ -618,6 +618,60 @@ class DomainVerificationPackageTest {
}
@Test
+ fun migratePackageSelected() {
+ val pkgName = PKG_ONE
+ val pkgBefore = mockPkgSetting(pkgName, UUID_ONE, SIGNATURE_ONE,
+ listOf(DOMAIN_1), listOf(DOMAIN_2))
+ val pkgAfter = mockPkgSetting(pkgName, UUID_TWO, SIGNATURE_TWO,
+ listOf(DOMAIN_1), listOf(DOMAIN_2))
+
+ val map = mutableMapOf<String, PackageSetting>()
+ val service = makeService { map[it] }
+ service.addPackage(pkgBefore)
+
+ // Only insert the package after addPackage call to ensure the service doesn't access
+ // a live package inside the addPackage logic. It should only use the provided input.
+ map[pkgName] = pkgBefore
+
+ assertThat(service.setStatus(UUID_ONE, setOf(DOMAIN_1), STATE_SUCCESS))
+ .isEqualTo(DomainVerificationManager.STATUS_OK)
+
+ assertThat(service.setUserSelection(UUID_ONE, setOf(DOMAIN_2), true, USER_ID))
+ .isEqualTo(DomainVerificationManager.STATUS_OK)
+
+ service.getInfo(pkgName).run {
+ assertThat(identifier).isEqualTo(UUID_ONE)
+ assertThat(hostToStateMap).containsExactlyEntriesIn(mapOf(
+ DOMAIN_1 to STATE_SUCCESS,
+ ))
+ }
+ assertThat(service.getUserState(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf(
+ DOMAIN_1 to DOMAIN_STATE_VERIFIED,
+ DOMAIN_2 to DOMAIN_STATE_SELECTED,
+ ))
+ assertThat(service.queryValidVerificationPackageNames()).containsExactly(pkgName)
+
+ // Now remove the package because migrateState shouldn't use it either
+ map.remove(pkgName)
+
+ service.migrateState(pkgBefore, pkgAfter)
+
+ map[pkgName] = pkgAfter
+
+ service.getInfo(pkgName).run {
+ assertThat(identifier).isEqualTo(UUID_TWO)
+ assertThat(hostToStateMap).containsExactlyEntriesIn(mapOf(
+ DOMAIN_1 to STATE_SUCCESS,
+ ))
+ }
+ assertThat(service.getUserState(pkgName).hostToStateMap).containsExactlyEntriesIn(mapOf(
+ DOMAIN_1 to DOMAIN_STATE_VERIFIED,
+ DOMAIN_2 to DOMAIN_STATE_SELECTED,
+ ))
+ assertThat(service.queryValidVerificationPackageNames()).containsExactly(pkgName)
+ }
+
+ @Test
fun backupAndRestore() {
// This test acts as a proxy for true user restore through PackageManager,
// as that's much harder to test for real.
@@ -798,7 +852,8 @@ class DomainVerificationPackageTest {
pkgName: String,
domainSetId: UUID,
signature: String,
- domains: List<String> = listOf(DOMAIN_1, DOMAIN_2),
+ autoVerifyDomains: List<String> = listOf(DOMAIN_1, DOMAIN_2),
+ otherDomains: List<String> = listOf(),
isSystemApp: Boolean = false
) = mockThrowOnUnmocked<PackageSetting> {
val pkg = mockThrowOnUnmocked<AndroidPackage> {
@@ -806,21 +861,23 @@ class DomainVerificationPackageTest {
whenever(targetSdkVersion) { Build.VERSION_CODES.S }
whenever(isEnabled) { true }
+ fun baseIntent(domain: String) = ParsedIntentInfo().apply {
+ addAction(Intent.ACTION_VIEW)
+ addCategory(Intent.CATEGORY_BROWSABLE)
+ addCategory(Intent.CATEGORY_DEFAULT)
+ addDataScheme("http")
+ addDataScheme("https")
+ addDataPath("/sub", PatternMatcher.PATTERN_LITERAL)
+ addDataAuthority(domain, null)
+ }
+
val activityList = listOf(
ParsedActivity().apply {
- domains.forEach {
- addIntent(
- ParsedIntentInfo().apply {
- autoVerify = true
- addAction(Intent.ACTION_VIEW)
- addCategory(Intent.CATEGORY_BROWSABLE)
- addCategory(Intent.CATEGORY_DEFAULT)
- addDataScheme("http")
- addDataScheme("https")
- addDataPath("/sub", PatternMatcher.PATTERN_LITERAL)
- addDataAuthority(it, null)
- }
- )
+ autoVerifyDomains.forEach {
+ addIntent(baseIntent(it).apply { autoVerify = true })
+ }
+ otherDomains.forEach {
+ addIntent(baseIntent(it).apply { autoVerify = false })
}
},
)
diff --git a/services/tests/mockingservicestests/src/com/android/server/usage/UserUsageStatsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/usage/UserUsageStatsServiceTest.java
index 24c58f49bed6..7358551d1bc5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/usage/UserUsageStatsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/usage/UserUsageStatsServiceTest.java
@@ -72,7 +72,7 @@ public class UserUsageStatsServiceTest {
HashMap<String, Long> installedPkgs = new HashMap<>();
installedPkgs.put(TEST_PACKAGE_NAME, System.currentTimeMillis());
- mService.init(System.currentTimeMillis(), installedPkgs);
+ mService.init(System.currentTimeMillis(), installedPkgs, true);
}
@After
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 2a5bb18ae428..df975cda54a5 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -40,7 +40,6 @@ import android.graphics.drawable.Icon;
import android.os.IBinder;
import android.os.UserHandle;
import android.provider.Settings;
-import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
@@ -54,13 +53,16 @@ import com.android.server.accessibility.test.MessageCapturingHandler;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/**
* APCT tests for {@link AccessibilityManagerService}.
*/
-public class AccessibilityManagerServiceTest extends AndroidTestCase {
+public class AccessibilityManagerServiceTest {
private static final String TAG = "A11Y_MANAGER_SERVICE_TEST";
private static final int ACTION_ID = 20;
private static final String LABEL = "label";
@@ -104,8 +106,8 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase {
private AccessibilityServiceConnection mAccessibilityServiceConnection;
private AccessibilityManagerService mA11yms;
- @Override
- protected void setUp() throws Exception {
+ @Before
+ public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
LocalServices.removeServiceForTest(WindowManagerInternal.class);
LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
@@ -167,44 +169,48 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase {
}
@SmallTest
+ @Test
public void testRegisterSystemActionWithoutPermission() throws Exception {
doThrow(SecurityException.class).when(mMockSecurityPolicy)
.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
try {
mA11yms.registerSystemAction(TEST_ACTION, ACTION_ID);
- fail();
+ Assert.fail();
} catch (SecurityException expected) {
}
verify(mMockSystemActionPerformer, never()).registerSystemAction(ACTION_ID, TEST_ACTION);
}
@SmallTest
+ @Test
public void testRegisterSystemAction() throws Exception {
mA11yms.registerSystemAction(TEST_ACTION, ACTION_ID);
verify(mMockSystemActionPerformer).registerSystemAction(ACTION_ID, TEST_ACTION);
}
- @SmallTest
+ @Test
public void testUnregisterSystemActionWithoutPermission() throws Exception {
doThrow(SecurityException.class).when(mMockSecurityPolicy)
.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
try {
mA11yms.unregisterSystemAction(ACTION_ID);
- fail();
+ Assert.fail();
} catch (SecurityException expected) {
}
verify(mMockSystemActionPerformer, never()).unregisterSystemAction(ACTION_ID);
}
@SmallTest
+ @Test
public void testUnregisterSystemAction() throws Exception {
mA11yms.unregisterSystemAction(ACTION_ID);
verify(mMockSystemActionPerformer).unregisterSystemAction(ACTION_ID);
}
@SmallTest
+ @Test
public void testOnSystemActionsChanged() throws Exception {
setupAccessibilityServiceConnection();
mA11yms.notifySystemActionsChangedLocked(mUserState);
@@ -213,6 +219,7 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase {
}
@SmallTest
+ @Test
public void testOnMagnificationTransitionFailed_capabilitiesIsAll_fallBackToPreviousMode() {
final AccessibilityUserState userState = mA11yms.mUserStates.get(
mA11yms.getCurrentUserIdLocked());
@@ -223,7 +230,7 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase {
mA11yms.onMagnificationTransitionEndedLocked(false);
- assertEquals(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW,
+ Assert.assertEquals(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW,
userState.getMagnificationModeLocked());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java
index 0cd6d86a3ec9..0ac00aafbf6c 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java
@@ -19,13 +19,17 @@ package com.android.server.biometrics.sensors.face.aidl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.hardware.biometrics.common.CommonProps;
import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
import android.hardware.biometrics.face.SensorProps;
+import android.os.RemoteException;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
@@ -33,7 +37,6 @@ import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
-import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.HalClientMonitor;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
@@ -55,6 +58,8 @@ public class FaceProviderTest {
private Context mContext;
@Mock
private UserManager mUserManager;
+ @Mock
+ private IFace mDaemon;
private SensorProps[] mSensorProps;
private LockoutResetDispatcher mLockoutResetDispatcher;
@@ -65,11 +70,12 @@ public class FaceProviderTest {
}
@Before
- public void setUp() {
+ public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
when(mUserManager.getAliveUsers()).thenReturn(new ArrayList<>());
+ when(mDaemon.createSession(anyInt(), anyInt(), any())).thenReturn(mock(ISession.class));
final SensorProps sensor1 = new SensorProps();
sensor1.commonProps = new CommonProps();
@@ -78,11 +84,11 @@ public class FaceProviderTest {
sensor2.commonProps = new CommonProps();
sensor2.commonProps.sensorId = 1;
- mSensorProps = new SensorProps[] {sensor1, sensor2};
+ mSensorProps = new SensorProps[]{sensor1, sensor2};
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
- mFaceProvider = new TestableFaceProvider(mContext, mSensorProps, TAG,
+ mFaceProvider = new TestableFaceProvider(mDaemon, mContext, mSensorProps, TAG,
mLockoutResetDispatcher);
}
@@ -127,17 +133,20 @@ public class FaceProviderTest {
}
private static class TestableFaceProvider extends FaceProvider {
- public TestableFaceProvider(@NonNull Context context,
+ private final IFace mDaemon;
+
+ TestableFaceProvider(@NonNull IFace daemon,
+ @NonNull Context context,
@NonNull SensorProps[] props,
@NonNull String halInstanceName,
@NonNull LockoutResetDispatcher lockoutResetDispatcher) {
super(context, props, halInstanceName, lockoutResetDispatcher);
+ mDaemon = daemon;
}
@Override
synchronized IFace getHalInstance() {
- return mock(IFace.class);
+ return mDaemon;
}
}
-
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
index 8b7c90d985b5..73f1516562bc 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
@@ -19,6 +19,7 @@ package com.android.server.biometrics.sensors.fingerprint.aidl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -28,8 +29,10 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.hardware.biometrics.common.CommonProps;
import android.hardware.biometrics.fingerprint.IFingerprint;
+import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.biometrics.fingerprint.SensorLocation;
import android.hardware.biometrics.fingerprint.SensorProps;
+import android.os.RemoteException;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
@@ -63,6 +66,8 @@ public class FingerprintProviderTest {
@Mock
private UserManager mUserManager;
@Mock
+ private IFingerprint mDaemon;
+ @Mock
private GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
@Mock
private FingerprintStateCallback mFingerprintStateCallback;
@@ -76,13 +81,14 @@ public class FingerprintProviderTest {
}
@Before
- public void setUp() {
+ public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
when(mContext.getResources()).thenReturn(mResources);
when(mResources.obtainTypedArray(anyInt())).thenReturn(mock(TypedArray.class));
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
when(mUserManager.getAliveUsers()).thenReturn(new ArrayList<>());
+ when(mDaemon.createSession(anyInt(), anyInt(), any())).thenReturn(mock(ISession.class));
final SensorProps sensor1 = new SensorProps();
sensor1.commonProps = new CommonProps();
@@ -97,8 +103,9 @@ public class FingerprintProviderTest {
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
- mFingerprintProvider = new TestableFingerprintProvider(mContext, mFingerprintStateCallback,
- mSensorProps, TAG, mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
+ mFingerprintProvider = new TestableFingerprintProvider(mDaemon, mContext,
+ mFingerprintStateCallback, mSensorProps, TAG, mLockoutResetDispatcher,
+ mGestureAvailabilityDispatcher);
}
@SuppressWarnings("rawtypes")
@@ -142,7 +149,10 @@ public class FingerprintProviderTest {
}
private static class TestableFingerprintProvider extends FingerprintProvider {
- public TestableFingerprintProvider(@NonNull Context context,
+ private final IFingerprint mDaemon;
+
+ TestableFingerprintProvider(@NonNull IFingerprint daemon,
+ @NonNull Context context,
@NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull SensorProps[] props,
@NonNull String halInstanceName,
@@ -150,11 +160,12 @@ public class FingerprintProviderTest {
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
super(context, fingerprintStateCallback, props, halInstanceName, lockoutResetDispatcher,
gestureAvailabilityDispatcher);
+ mDaemon = daemon;
}
@Override
synchronized IFingerprint getHalInstance() {
- return mock(IFingerprint.class);
+ return mDaemon;
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 3ac30d0258a5..cadc81600bbb 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -51,6 +51,7 @@ import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
@@ -184,6 +185,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
public DevicePolicyManager parentDpm;
public DevicePolicyManagerServiceTestable dpms;
+ private boolean mIsAutomotive;
+
/*
* The CA cert below is the content of cacert.pem as generated by:
*
@@ -266,6 +269,9 @@ public class DevicePolicyManagerTest extends DpmTestBase {
setUpUserManager();
when(getServices().lockPatternUtils.hasSecureLockScreen()).thenReturn(true);
+
+ mIsAutomotive = mContext.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
}
private TransferOwnershipMetadataManager getMockTransferMetadataManager() {
@@ -2117,10 +2123,13 @@ public class DevicePolicyManagerTest extends DpmTestBase {
assertThat(dpm.getPasswordExpirationTimeout(admin1))
.isEqualTo(originalPasswordExpirationTimeout);
- int originalPasswordQuality = dpm.getPasswordQuality(admin1);
- assertExpectException(SecurityException.class, /* messageRegex= */ null,
- () -> dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_NUMERIC));
- assertThat(dpm.getPasswordQuality(admin1)).isEqualTo(originalPasswordQuality);
+ if (isDeprecatedPasswordApisSupported()) {
+ int originalPasswordQuality = dpm.getPasswordQuality(admin1);
+ assertExpectException(SecurityException.class, /* messageRegex= */ null,
+ () -> dpm.setPasswordQuality(admin1,
+ DevicePolicyManager.PASSWORD_QUALITY_NUMERIC));
+ assertThat(dpm.getPasswordQuality(admin1)).isEqualTo(originalPasswordQuality);
+ }
}
@Test
@@ -5231,6 +5240,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testIsActivePasswordSufficient() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
mContext.packageName = admin1.getPackageName();
setupDeviceOwner();
@@ -5283,6 +5294,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testIsActivePasswordSufficient_noLockScreen() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
// If there is no lock screen, the password is considered empty no matter what, because
// it provides no security.
when(getServices().lockPatternUtils.hasSecureLockScreen()).thenReturn(false);
@@ -5363,6 +5376,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testGetAggregatedPasswordMetrics_IgnoreProfileRequirement()
throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
final int managedProfileUserId = CALLER_USER_HANDLE;
final int managedProfileAdminUid =
UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
@@ -5392,6 +5407,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testCanSetPasswordRequirementOnParentPreS() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
final int managedProfileUserId = CALLER_USER_HANDLE;
final int managedProfileAdminUid =
UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
@@ -5407,6 +5424,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testCannotSetPasswordRequirementOnParent() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
final int managedProfileUserId = CALLER_USER_HANDLE;
final int managedProfileAdminUid =
UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
@@ -5427,6 +5446,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void isActivePasswordSufficient_SeparateWorkChallenge_ProfileQualityRequirementMet()
throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
// Create work profile with empty separate challenge
final int managedProfileUserId = 15;
final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
@@ -5450,6 +5471,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void isActivePasswordSufficient_SeparateWorkChallenge_ProfileComplexityRequirementMet()
throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
// Create work profile with empty separate challenge
final int managedProfileUserId = 15;
final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
@@ -5473,6 +5496,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void isActivePasswordSufficient_SeparateWorkChallenge_ParentQualityRequirementMet()
throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
// Create work profile with empty separate challenge
final int managedProfileUserId = 15;
final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
@@ -5519,6 +5544,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void isActivePasswordSufficient_UnifiedWorkChallenge_ProfileQualityRequirementMet()
throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
// Create work profile with unified challenge
final int managedProfileUserId = 15;
final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
@@ -5565,6 +5592,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void isActivePasswordSufficient_UnifiedWorkChallenge_ParentQualityRequirementMet()
throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
// Create work profile with unified challenge
final int managedProfileUserId = 15;
final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
@@ -5625,6 +5654,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testPasswordQualityAppliesToParentPreS() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
final int managedProfileUserId = CALLER_USER_HANDLE;
final int managedProfileAdminUid =
UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
@@ -7285,6 +7316,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetRequiredPasswordComplexity_UnauthorizedCallersOnDO() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
// DO must be able to set it.
@@ -7300,6 +7333,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetRequiredPasswordComplexity_UnauthorizedCallersOnPO() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
setupProfileOwner();
// PO must be able to set it.
@@ -7314,6 +7349,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetRequiredPasswordComplexity_validValuesOnly() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
setupProfileOwner();
@@ -7335,6 +7372,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetRequiredPasswordComplexity_setAndGet() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
setupProfileOwner();
@@ -7348,6 +7387,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetRequiredPasswordComplexityOnParent_setAndGet() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
final int managedProfileUserId = 15;
final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
@@ -7366,6 +7407,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetRequiredPasswordComplexity_isSufficient() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
mContext.packageName = admin1.getPackageName();
setupDeviceOwner();
@@ -7395,6 +7438,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetRequiredPasswordComplexity_resetBySettingQuality() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
setupProfileOwner();
@@ -7407,6 +7452,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetRequiredPasswordComplexity_overridesQuality() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
setupProfileOwner();
@@ -7421,6 +7468,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetRequiredPasswordComplexityFailsWithQualityOnParent() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
final int managedProfileUserId = CALLER_USER_HANDLE;
final int managedProfileAdminUid =
UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
@@ -7435,6 +7484,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetQualityOnParentFailsWithComplexityOnProfile() throws Exception {
+ assumeDeprecatedPasswordApisSupported();
+
final int managedProfileUserId = CALLER_USER_HANDLE;
final int managedProfileAdminUid =
UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
@@ -8015,4 +8066,13 @@ public class DevicePolicyManagerTest extends DpmTestBase {
when(mContext.getResources().getStringArray(R.array.vendor_policy_exempt_apps))
.thenReturn(new String[0]);
}
+
+ private boolean isDeprecatedPasswordApisSupported() {
+ return !mIsAutomotive;
+ }
+
+ private void assumeDeprecatedPasswordApisSupported() {
+ assumeTrue("device doesn't support deprecated password APIs",
+ isDeprecatedPasswordApisSupported());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java b/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
index 8e2c1f051279..761cea79df28 100644
--- a/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
@@ -160,6 +160,64 @@ public final class DeviceStateProviderImplTest {
}
@Test
+ public void create_stateWithCancelStickyRequestFlag() {
+ String configString = "<device-state-config>\n"
+ + " <device-state>\n"
+ + " <identifier>1</identifier>\n"
+ + " <flags>\n"
+ + " <flag>FLAG_CANCEL_STICKY_REQUESTS</flag>\n"
+ + " </flags>\n"
+ + " <conditions/>\n"
+ + " </device-state>\n"
+ + " <device-state>\n"
+ + " <identifier>2</identifier>\n"
+ + " <conditions/>\n"
+ + " </device-state>\n"
+ + "</device-state-config>\n";
+ DeviceStateProviderImpl.ReadableConfig config = new TestReadableConfig(configString);
+ DeviceStateProviderImpl provider = DeviceStateProviderImpl.createFromConfig(mContext,
+ config);
+
+ DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class);
+ provider.setListener(listener);
+
+ verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
+ final DeviceState[] expectedStates = new DeviceState[]{
+ new DeviceState(1, "", DeviceState.FLAG_CANCEL_STICKY_REQUESTS),
+ new DeviceState(2, "", 0 /* flags */) };
+ assertArrayEquals(expectedStates, mDeviceStateArrayCaptor.getValue());
+ }
+
+ @Test
+ public void create_stateWithInvalidFlag() {
+ String configString = "<device-state-config>\n"
+ + " <device-state>\n"
+ + " <identifier>1</identifier>\n"
+ + " <flags>\n"
+ + " <flag>INVALID_FLAG</flag>\n"
+ + " </flags>\n"
+ + " <conditions/>\n"
+ + " </device-state>\n"
+ + " <device-state>\n"
+ + " <identifier>2</identifier>\n"
+ + " <conditions/>\n"
+ + " </device-state>\n"
+ + "</device-state-config>\n";
+ DeviceStateProviderImpl.ReadableConfig config = new TestReadableConfig(configString);
+ DeviceStateProviderImpl provider = DeviceStateProviderImpl.createFromConfig(mContext,
+ config);
+
+ DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class);
+ provider.setListener(listener);
+
+ verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture());
+ final DeviceState[] expectedStates = new DeviceState[]{
+ new DeviceState(1, "", 0 /* flags */),
+ new DeviceState(2, "", 0 /* flags */) };
+ assertArrayEquals(expectedStates, mDeviceStateArrayCaptor.getValue());
+ }
+
+ @Test
public void create_lidSwitch() {
String configString = "<device-state-config>\n"
+ " <device-state>\n"
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index ea46eab6e8f9..d593e8000048 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -32,7 +32,6 @@ import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
@@ -40,6 +39,7 @@ import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.after;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -48,6 +48,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.KeyguardManager;
import android.app.Notification;
@@ -73,7 +74,6 @@ import android.provider.Settings;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Slog;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
@@ -102,6 +102,7 @@ import java.util.Objects;
@SmallTest
@RunWith(AndroidJUnit4.class)
+@SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service.
public class BuzzBeepBlinkTest extends UiServiceTestCase {
@Mock AudioManager mAudioManager;
@@ -156,6 +157,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
when(mAudioManager.getRingtonePlayer()).thenReturn(mRingtonePlayer);
when(mAudioManager.getStreamVolume(anyInt())).thenReturn(10);
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
+ when(mAudioManager.getFocusRampTimeMs(anyInt(), any(AudioAttributes.class))).thenReturn(50);
when(mUsageStats.isAlertRateLimited(any())).thenReturn(false);
when(mVibrator.hasFrequencyControl()).thenReturn(false);
when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false);
@@ -444,6 +446,11 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
timeout(MAX_VIBRATION_DELAY).times(1));
}
+ private void verifyDelayedNeverVibrate() {
+ verify(mVibrator, after(MAX_VIBRATION_DELAY).never()).vibrate(anyInt(), anyString(), any(),
+ anyString(), any(AudioAttributes.class));
+ }
+
private void verifyVibrate(ArgumentMatcher<VibrationEffect> effectMatcher,
VerificationMode verification) {
ArgumentCaptor<AudioAttributes> captor = ArgumentCaptor.forClass(AudioAttributes.class);
@@ -1588,8 +1595,51 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
// beep wasn't reset
verifyNeverBeep();
verifyNeverVibrate();
- verify(mRingtonePlayer, never()).stopAsync();
- verify(mVibrator, never()).cancel();
+ verifyNeverStopAudio();
+ verifyNeverStopVibrate();
+ }
+
+ @Test
+ public void testRingtoneInsistentBeep_clearEffectsStopsSoundAndVibration() throws Exception {
+ NotificationChannel ringtoneChannel =
+ new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
+ ringtoneChannel.setSound(Uri.fromParts("a", "b", "c"),
+ new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
+ ringtoneChannel.enableVibration(true);
+ NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
+ mService.addNotification(ringtoneNotification);
+ assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification));
+ mService.buzzBeepBlinkLocked(ringtoneNotification);
+ verifyBeepLooped();
+ verifyDelayedVibrateLooped();
+
+ mService.clearSoundLocked();
+ mService.clearVibrateLocked();
+
+ verifyStopAudio();
+ verifyStopVibrate();
+ }
+
+ @Test
+ public void testRingtoneInsistentBeep_neverVibratesWhenEffectsClearedBeforeDelay()
+ throws Exception {
+ NotificationChannel ringtoneChannel =
+ new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
+ ringtoneChannel.setSound(Uri.fromParts("a", "b", "c"),
+ new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
+ ringtoneChannel.enableVibration(true);
+ NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
+ mService.addNotification(ringtoneNotification);
+ assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification));
+ mService.buzzBeepBlinkLocked(ringtoneNotification);
+ verifyBeepLooped();
+ verifyNeverVibrate();
+
+ mService.clearSoundLocked();
+ mService.clearVibrateLocked();
+
+ verifyStopAudio();
+ verifyDelayedNeverVibrate();
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 987236c7c98c..c337ccd67db8 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -379,6 +379,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
/** Test that restore correctly parses the user_set attribute. */
@Test
public void testReadXml_restoresUserSet() throws Exception {
+ mVersionString = "4";
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service =
new TestManagedServices(
@@ -1513,7 +1514,8 @@ public class ManagedServicesTest extends UiServiceTestCase {
for (int userId : mExpectedPrimary.get(service.mApprovalLevel).keySet()) {
String pkgOrCmp = mExpectedPrimary.get(service.mApprovalLevel).get(userId);
xml.append(getXmlEntry(
- pkgOrCmp, userId, true, !(pkgOrCmp.startsWith("non.user.set.package"))));
+ pkgOrCmp, userId, true,
+ !(pkgOrCmp.startsWith("non.user.set.package"))));
}
for (int userId : mExpectedSecondary.get(service.mApprovalLevel).keySet()) {
xml.append(getXmlEntry(
@@ -1541,7 +1543,9 @@ public class ManagedServicesTest extends UiServiceTestCase {
private TypedXmlPullParser getParserWithEntries(ManagedServices service, String... xmlEntries)
throws Exception {
final StringBuffer xml = new StringBuffer();
- xml.append("<" + service.getConfig().xmlTag + ">\n");
+ xml.append("<" + service.getConfig().xmlTag
+ + (mVersionString != null ? " version=\"" + mVersionString + "\" " : "")
+ + ">\n");
for (String xmlEntry : xmlEntries) {
xml.append(xmlEntry);
}
@@ -1726,12 +1730,19 @@ public class ManagedServicesTest extends UiServiceTestCase {
}
private String getXmlEntry(String approved, int userId, boolean isPrimary, boolean userSet) {
+ String userSetString = "";
+ if (mVersionString.equals("4")) {
+ userSetString =
+ ManagedServices.ATT_USER_CHANGED + "=\"" + String.valueOf(userSet) + "\" ";
+ } else if (mVersionString.equals("3")) {
+ userSetString =
+ ManagedServices.ATT_USER_SET + "=\"" + (userSet ? approved : "") + "\" ";
+ }
return "<" + ManagedServices.TAG_MANAGED_SERVICES + " "
+ ManagedServices.ATT_USER_ID + "=\"" + userId +"\" "
+ ManagedServices.ATT_IS_PRIMARY + "=\"" + isPrimary +"\" "
+ ManagedServices.ATT_APPROVED_LIST + "=\"" + approved +"\" "
- + ManagedServices.ATT_USER_SET + "=\"" + (userSet ? approved : "") + "\" "
- + "/>\n";
+ + userSetString + "/>\n";
}
class TestManagedServices extends ManagedServices {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
index 054a401d41af..4b93e35e673a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
@@ -124,6 +125,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
profileIds.add(12);
when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
when(mNm.isNASMigrationDone(anyInt())).thenReturn(true);
+ when(mNm.canUseManagedServices(any(), anyInt(), any())).thenReturn(true);
}
@Test
@@ -178,6 +180,92 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
}
@Test
+ public void testReadXml_upgradeUserSet_preS_VersionThree() throws Exception {
+ String xml = "<enabled_assistants version=\"3\" defaults=\"b/b\">"
+ + "<service_listing approved=\"\" user=\"0\" primary=\"true\""
+ + "user_set=\"true\"/>"
+ + "</enabled_assistants>";
+
+ final TypedXmlPullParser parser = Xml.newFastPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml.toString().getBytes())), null);
+ TriPredicate<String, Integer, String> allowedManagedServicePackages =
+ mNm::canUseManagedServices;
+
+ parser.nextTag();
+ mAssistants.readXml(parser, allowedManagedServicePackages, false, UserHandle.USER_ALL);
+
+ verify(mAssistants, times(0)).upgradeUserSet();
+ assertTrue(isUserSetServicesEmpty(mAssistants, 0));
+ assertTrue(mAssistants.mIsUserChanged.get(0));
+ }
+
+ @Test
+ public void testReadXml_upgradeUserSet_preS_VersionOne() throws Exception {
+ String xml = "<enabled_assistants version=\"1\" defaults=\"b/b\">"
+ + "<service_listing approved=\"\" user=\"0\" primary=\"true\""
+ + "user_set=\"true\"/>"
+ + "</enabled_assistants>";
+
+ final TypedXmlPullParser parser = Xml.newFastPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml.toString().getBytes())), null);
+ TriPredicate<String, Integer, String> allowedManagedServicePackages =
+ mNm::canUseManagedServices;
+
+ parser.nextTag();
+ mAssistants.readXml(parser, allowedManagedServicePackages, false, UserHandle.USER_ALL);
+
+ verify(mAssistants, times(0)).upgradeUserSet();
+ assertTrue(isUserSetServicesEmpty(mAssistants, 0));
+ assertTrue(mAssistants.mIsUserChanged.get(0));
+ }
+
+ @Test
+ public void testReadXml_upgradeUserSet_preS_noUserSet() throws Exception {
+ String xml = "<enabled_assistants version=\"3\" defaults=\"b/b\">"
+ + "<service_listing approved=\"b/b\" user=\"0\" primary=\"true\"/>"
+ + "</enabled_assistants>";
+
+ final TypedXmlPullParser parser = Xml.newFastPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml.toString().getBytes())), null);
+ TriPredicate<String, Integer, String> allowedManagedServicePackages =
+ mNm::canUseManagedServices;
+
+ parser.nextTag();
+ mAssistants.readXml(parser, allowedManagedServicePackages, false, UserHandle.USER_ALL);
+
+ verify(mAssistants, times(1)).upgradeUserSet();
+ assertTrue(isUserSetServicesEmpty(mAssistants, 0));
+ assertFalse(mAssistants.mIsUserChanged.get(0));
+ }
+
+ @Test
+ public void testReadXml_upgradeUserSet_preS_noUserSet_diffDefault() throws Exception {
+ String xml = "<enabled_assistants version=\"3\" defaults=\"a/a\">"
+ + "<service_listing approved=\"b/b\" user=\"0\" primary=\"true\"/>"
+ + "</enabled_assistants>";
+
+ final TypedXmlPullParser parser = Xml.newFastPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml.toString().getBytes())), null);
+ TriPredicate<String, Integer, String> allowedManagedServicePackages =
+ mNm::canUseManagedServices;
+
+ parser.nextTag();
+ mAssistants.readXml(parser, allowedManagedServicePackages, false, UserHandle.USER_ALL);
+
+ verify(mAssistants, times(1)).upgradeUserSet();
+ assertTrue(isUserSetServicesEmpty(mAssistants, 0));
+ assertFalse(mAssistants.mIsUserChanged.get(0));
+ assertEquals(new ArraySet<>(Arrays.asList(new ComponentName("a", "a"))),
+ mAssistants.getDefaultComponents());
+ assertEquals(Arrays.asList(new ComponentName("b", "b")),
+ mAssistants.getAllowedComponents(0));
+ }
+
+ @Test
public void testReadXml_multiApproved() throws Exception {
String xml = "<enabled_assistants version=\"4\" defaults=\"b/b\">"
+ "<service_listing approved=\"a/a:b/b\" user=\"0\" primary=\"true\""
@@ -210,7 +298,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
verify(mNm, never()).setDefaultAssistantForUser(anyInt());
verify(mAssistants, times(1)).addApprovedList(
- new ComponentName("b", "b").flattenToString(), 10, true, null);
+ new ComponentName("b", "b").flattenToString(), 10, true, "");
}
@Test
@@ -380,4 +468,11 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
verify(mNm, times(1)).setDefaultAssistantForUser(eq(mZero.id));
assertEquals(new ArraySet<>(), mAssistants.getDefaultComponents());
}
+
+ // Helper function to hold mApproved lock, avoid GuardedBy lint errors
+ private boolean isUserSetServicesEmpty(NotificationAssistants assistant, int userId) {
+ synchronized (assistant.mApproved) {
+ return assistant.mUserSetServices.get(userId).isEmpty();
+ }
+ }
}
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 0b918025bb50..d4d8b86850c6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -477,7 +477,6 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
@Test
public void testConsecutiveLaunch() {
- mTrampolineActivity.setState(ActivityRecord.State.INITIALIZING, "test");
onActivityLaunched(mTrampolineActivity);
mActivityMetricsLogger.notifyActivityLaunching(mTopActivity.intent,
mTrampolineActivity /* caller */, mTrampolineActivity.getUid());
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 44cff33d6146..fc2c162d058b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -16,9 +16,11 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.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;
import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
@@ -100,7 +102,6 @@ import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
import android.app.ActivityOptions;
-import android.app.WindowConfiguration;
import android.app.servertransaction.ActivityConfigurationChangeItem;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.DestroyActivityItem;
@@ -166,6 +167,8 @@ public class ActivityRecordTests extends WindowTestsBase {
@Before
public void setUp() throws Exception {
setBooted(mAtm);
+ // Because the booted state is set, avoid starting real home if there is no task.
+ doReturn(false).when(mRootWindowContainer).resumeHomeActivity(any(), anyString(), any());
}
private TestStartingWindowOrganizer registerTestStartingWindowOrganizer() {
@@ -558,7 +561,7 @@ public class ActivityRecordTests extends WindowTestsBase {
final ActivityRecord activity = createActivityWith2LevelTask();
final Task task = activity.getTask();
final Task rootTask = activity.getRootTask();
- rootTask.setWindowingMode(WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ rootTask.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
final Rect stableRect = new Rect();
rootTask.mDisplayContent.getStableRect(stableRect);
@@ -600,19 +603,22 @@ public class ActivityRecordTests extends WindowTestsBase {
@Test
public void respectRequestedOrientationForNonResizableInSplitWindows() {
- final Task task = new TaskBuilder(mSupervisor)
- .setCreateParentTask(true).setCreateActivity(true).build();
- final Task rootTask = task.getRootTask();
+ final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea();
+ spyOn(tda);
+ doReturn(true).when(tda).supportsNonResizableMultiWindow();
+ final Task rootTask = mDisplayContent.getDefaultTaskDisplayArea().createRootTask(
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ rootTask.setBounds(0, 0, 1000, 500);
final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setParentTask(task)
+ .setParentTask(rootTask)
+ .setCreateTask(true)
.setOnTop(true)
.setResizeMode(RESIZE_MODE_UNRESIZEABLE)
.setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
.build();
+ final Task task = activity.getTask();
// Task in landscape.
- rootTask.setWindowingMode(WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
- task.setBounds(0, 0, 1000, 500);
assertEquals(ORIENTATION_LANDSCAPE, task.getConfiguration().orientation);
// Asserts fixed orientation request is respected, and the orientation is not changed.
@@ -621,7 +627,7 @@ public class ActivityRecordTests extends WindowTestsBase {
// Clear size compat.
activity.clearSizeCompatMode();
activity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
- activity.mDisplayContent.sendNewConfiguration();
+ mDisplayContent.sendNewConfiguration();
// Relaunching the app should still respect the orientation request.
assertEquals(ORIENTATION_PORTRAIT, activity.getConfiguration().orientation);
@@ -1083,6 +1089,7 @@ public class ActivityRecordTests extends WindowTestsBase {
*/
@Test
public void testFinishActivityIfPossible_nonVisibleNoAppTransition() {
+ registerTestTransitionPlayer();
final ActivityRecord activity = createActivityWithTask();
// Put an activity on top of test activity to make it invisible and prevent us from
// accidentally resuming the topmost one again.
@@ -1093,6 +1100,7 @@ public class ActivityRecordTests extends WindowTestsBase {
activity.finishIfPossible("test", false /* oomAdj */);
verify(activity.mDisplayContent, never()).prepareAppTransition(eq(TRANSIT_CLOSE));
+ assertFalse(activity.inTransition());
}
/**
@@ -1101,11 +1109,7 @@ public class ActivityRecordTests extends WindowTestsBase {
*/
@Test
public void testFinishActivityIfPossible_lastInTaskRequestsTransitionWithTrigger() {
- // Set-up mock shell transitions
- final TestTransitionPlayer testPlayer = new TestTransitionPlayer(
- mAtm.getTransitionController(), mAtm.mWindowOrganizerController);
- mAtm.getTransitionController().registerTransitionPlayer(testPlayer);
-
+ final TestTransitionPlayer testPlayer = registerTestTransitionPlayer();
final ActivityRecord activity = createActivityWithTask();
activity.finishing = false;
activity.mVisibleRequested = true;
@@ -1117,6 +1121,29 @@ public class ActivityRecordTests extends WindowTestsBase {
}
/**
+ * Verify that when collecting activity to the existing close transition, it should not affect
+ * ready state.
+ */
+ @Test
+ public void testFinishActivityIfPossible_collectToExistingTransition() {
+ final TestTransitionPlayer testPlayer = registerTestTransitionPlayer();
+ final ActivityRecord activity = createActivityWithTask();
+ activity.setState(PAUSED, "test");
+ activity.finishIfPossible("test", false /* oomAdj */);
+ final Transition lastTransition = testPlayer.mLastTransit;
+ assertTrue(lastTransition.allReady());
+ assertTrue(activity.inTransition());
+
+ // Collect another activity to the existing transition without changing ready state.
+ final ActivityRecord activity2 = createActivityRecord(activity.getTask());
+ activity2.setState(PAUSING, "test");
+ activity2.finishIfPossible("test", false /* oomAdj */);
+ assertTrue(activity2.inTransition());
+ assertEquals(lastTransition, testPlayer.mLastTransit);
+ assertTrue(lastTransition.allReady());
+ }
+
+ /**
* Verify that complete finish request for non-finishing activity is invalid.
*/
@Test(expected = IllegalArgumentException.class)
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
index a34586bb2e8a..66da2a631868 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
@@ -36,6 +37,7 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.timeout;
@@ -266,6 +268,30 @@ public class ActivityTaskSupervisorTests extends WindowTestsBase {
}
/**
+ * Verifies that process state will be updated with pending top without activity state change.
+ * E.g. switch focus between resumed activities in multi-window mode.
+ */
+ @Test
+ public void testUpdatePendingTopForTopResumed() {
+ final Task task1 = new TaskBuilder(mSupervisor)
+ .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW).build();
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm)
+ .setTask(task1).setUid(ActivityBuilder.DEFAULT_FAKE_UID + 1).build();
+ task1.setResumedActivity(activity1, "test");
+
+ final ActivityRecord activity2 = new TaskBuilder(mSupervisor)
+ .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW)
+ .setCreateActivity(true).build().getTopMostActivity();
+ activity2.getTask().setResumedActivity(activity2, "test");
+
+ mAtm.mAmInternal.deletePendingTopUid(activity1.getUid());
+ clearInvocations(mAtm);
+ activity1.moveFocusableActivityToTop("test");
+ assertTrue(mAtm.mAmInternal.isPendingTopUid(activity1.getUid()));
+ verify(mAtm).updateOomAdj();
+ }
+
+ /**
* We need to launch home again after user unlocked for those displays that do not have
* encryption aware home app.
*/
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index fb8bc7be38ce..c0959d311ed5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -419,6 +419,7 @@ public class AppTransitionTests extends WindowTestsBase {
task.getBounds(taskBounds);
taskFragment.setBounds(0, 0, taskBounds.right / 2, taskBounds.bottom);
spyOn(taskFragment);
+ mockSurfaceFreezerSnapshot(taskFragment.mSurfaceFreezer);
assertTrue(mDc.mChangingContainers.isEmpty());
assertFalse(mDc.mAppTransition.isTransitionSet());
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 24bbf4682157..f3c1ec5b200e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1674,11 +1674,7 @@ public class DisplayContentTests extends WindowTestsBase {
public void testShellTransitRotation() {
DisplayContent dc = createNewDisplay();
- // Set-up mock shell transitions
- final TestTransitionPlayer testPlayer = new TestTransitionPlayer(
- mAtm.getTransitionController(), mAtm.mWindowOrganizerController);
- mAtm.getTransitionController().registerTransitionPlayer(testPlayer);
-
+ final TestTransitionPlayer testPlayer = registerTestTransitionPlayer();
final DisplayRotation dr = dc.getDisplayRotation();
doCallRealMethod().when(dr).updateRotationUnchecked(anyBoolean());
// Rotate 180 degree so the display doesn't have configuration change. This condition is
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index a1e8ca4aa84b..32cca47b991c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -37,6 +37,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
@@ -44,6 +45,7 @@ import android.app.PendingIntent;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Intent;
+import android.content.pm.ShortcutServiceInternal;
import android.graphics.PixelFormat;
import android.os.Binder;
import android.os.IBinder;
@@ -71,6 +73,7 @@ import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import java.util.ArrayList;
@@ -89,6 +92,7 @@ import java.util.concurrent.TimeUnit;
public class DragDropControllerTests extends WindowTestsBase {
private static final int TIMEOUT_MS = 3000;
private static final int TEST_UID = 12345;
+ private static final int TEST_PROFILE_UID = 12345 * UserHandle.PER_USER_RANGE;
private static final int TEST_PID = 67890;
private static final String TEST_PACKAGE = "com.test.package";
@@ -387,6 +391,32 @@ public class DragDropControllerTests extends WindowTestsBase {
}
}
+ @Test
+ public void testValidateProfileAppShortcutArguments_notCallingUid() {
+ doReturn(PERMISSION_GRANTED).when(mWm.mContext)
+ .checkCallingOrSelfPermission(eq(START_TASKS_FROM_RECENTS));
+ final Session session = Mockito.spy(new Session(mWm, new IWindowSessionCallback.Stub() {
+ @Override
+ public void onAnimatorScaleChanged(float scale) {}
+ }));
+ final ShortcutServiceInternal shortcutService = mock(ShortcutServiceInternal.class);
+ final Intent[] shortcutIntents = new Intent[1];
+ shortcutIntents[0] = new Intent();
+ doReturn(shortcutIntents).when(shortcutService).createShortcutIntents(anyInt(), any(),
+ any(), any(), anyInt(), anyInt(), anyInt());
+ LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
+ LocalServices.addService(ShortcutServiceInternal.class, shortcutService);
+
+ ArgumentCaptor<Integer> callingUser = ArgumentCaptor.forClass(Integer.class);
+ session.validateAndResolveDragMimeTypeExtras(
+ createClipDataForShortcut("test_package", "test_shortcut_id",
+ mock(UserHandle.class)),
+ TEST_PROFILE_UID, TEST_PID, TEST_PACKAGE);
+ verify(shortcutService).createShortcutIntents(callingUser.capture(), any(),
+ any(), any(), anyInt(), anyInt(), anyInt());
+ assertTrue(callingUser.getValue() == UserHandle.getUserId(TEST_PROFILE_UID));
+ }
+
private ClipData createClipDataForShortcut(String packageName, String shortcutId,
UserHandle user) {
final Intent data = new Intent();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 9d2a69197013..b4c449a94a40 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -124,7 +124,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
// Verify that the finish callback to reparent the leash is called
verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_RECENTS), eq(adapter));
// Verify the animation canceled callback to the app was made
- verify(mMockRunner).onAnimationCanceled(null /* taskSnapshot */);
+ verify(mMockRunner).onAnimationCanceled(null /* taskIds */, null /* taskSnapshots */);
verifyNoMoreInteractionsExceptAsBinder(mMockRunner);
}
@@ -207,7 +207,8 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
wallpaperWindowToken.cancelAnimation();
assertTrue(mController.isAnimatingTask(activity.getTask()));
assertFalse(mController.isAnimatingWallpaper(wallpaperWindowToken));
- verify(mMockRunner, never()).onAnimationCanceled(null /* taskSnapshot */);
+ verify(mMockRunner, never()).onAnimationCanceled(null /* taskIds */,
+ null /* taskSnapshots */);
}
@Test
@@ -254,7 +255,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
mController.setDeferredCancel(true /* deferred */, false /* screenshot */);
mController.cancelAnimationWithScreenshot(false /* screenshot */);
- verify(mMockRunner).onAnimationCanceled(null /* taskSnapshot */);
+ verify(mMockRunner).onAnimationCanceled(null /* taskIds */, null /* taskSnapshots */);
// Simulate the app transition finishing
mController.mAppTransitionListener.onAppTransitionStartingLocked(false, false, 0, 0, 0);
@@ -281,7 +282,8 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
anyInt(), eq(false) /* restoreFromDisk */, eq(false) /* isLowResolution */);
mController.setDeferredCancel(true /* deferred */, true /* screenshot */);
mController.cancelAnimationWithScreenshot(true /* screenshot */);
- verify(mMockRunner).onAnimationCanceled(mMockTaskSnapshot /* taskSnapshot */);
+ verify(mMockRunner).onAnimationCanceled(any(int[].class) /* taskIds */,
+ any(TaskSnapshot[].class) /* taskSnapshots */);
// Continue the animation (simulating a call to cleanupScreenshot())
mController.continueDeferredCancelAnimation();
@@ -322,7 +324,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
doReturn(mMockTaskSnapshot).when(mWm.mTaskSnapshotController).getSnapshot(anyInt(),
anyInt(), eq(false) /* restoreFromDisk */, eq(false) /* isLowResolution */);
mController.cancelAnimationWithScreenshot(true /* screenshot */);
- verify(mMockRunner).onAnimationCanceled(any());
+ verify(mMockRunner).onAnimationCanceled(any(), any());
// Simulate process crashing and ensure the animation is still canceled
mController.binderDied();
@@ -700,7 +702,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
mController.setWillFinishToHome(true);
mController.cancelAnimationForDisplayChange();
- verify(mMockRunner).onAnimationCanceled(any());
+ verify(mMockRunner).onAnimationCanceled(any(), any());
verify(mAnimationCallbacks).onAnimationFinished(REORDER_MOVE_TO_TOP, false);
}
@@ -715,7 +717,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
mController.setWillFinishToHome(false);
mController.cancelAnimationForDisplayChange();
- verify(mMockRunner).onAnimationCanceled(any());
+ verify(mMockRunner).onAnimationCanceled(any(), any());
verify(mAnimationCallbacks).onAnimationFinished(REORDER_MOVE_TO_ORIGINAL_POSITION, false);
}
@@ -735,7 +737,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
doReturn(mMockTaskSnapshot).when(mWm.mTaskSnapshotController).getSnapshot(anyInt(),
anyInt(), eq(false) /* restoreFromDisk */, eq(false) /* isLowResolution */);
mController.cancelAnimationForHomeStart();
- verify(mMockRunner).onAnimationCanceled(any());
+ verify(mMockRunner).onAnimationCanceled(any(), any());
// Continue the animation (simulating a call to cleanupScreenshot())
mController.continueDeferredCancelAnimation();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 08312ef0b865..575e0820eca9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -36,12 +36,14 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
+import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.fail;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
@@ -699,6 +701,51 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
}
}
+ @UseTestDisplay(addWindows = W_INPUT_METHOD)
+ @Test
+ public void testLaunchRemoteAnimationWithoutImeBehind() {
+ final WindowState win1 = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin1");
+ final WindowState win2 = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin2");
+
+ // Simulating win1 has shown IME and being IME layering/input target
+ mDisplayContent.setImeLayeringTarget(win1);
+ mDisplayContent.setImeInputTarget(win1);
+ mImeWindow.mWinAnimator.mSurfaceController = mock(WindowSurfaceController.class);
+ mImeWindow.mWinAnimator.hide(mDisplayContent.getPendingTransaction(), "test");
+ spyOn(mDisplayContent);
+ doReturn(true).when(mImeWindow.mWinAnimator.mSurfaceController).hasSurface();
+ doReturn(true).when(mImeWindow.mWinAnimator.mSurfaceController)
+ .prepareToShowInTransaction(any(), anyFloat());
+ makeWindowVisibleAndDrawn(mImeWindow);
+ assertTrue(mImeWindow.isOnScreen());
+ assertFalse(mImeWindow.isParentWindowHidden());
+
+ try {
+ // Simulating now win1 is being covered by the lockscreen which has no surface,
+ // and then launching an activity win2 with the remote animation
+ win1.mHasSurface = false;
+ mDisplayContent.mOpeningApps.add(win2.mActivityRecord);
+ final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
+ win2.mActivityRecord, new Point(50, 100), null,
+ new Rect(50, 100, 150, 150), null).mAdapter;
+ adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
+ mFinishedCallback);
+
+ mDisplayContent.applySurfaceChangesTransaction();
+ mController.goodToGo(TRANSIT_OLD_TASK_OPEN);
+ mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+
+ verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_TASK_OPEN),
+ any(), any(), any(), any());
+ // Verify the IME window won't apply surface change transaction with forAllImeWindows
+ verify(mDisplayContent, never()).forAllImeWindows(any(), eq(true));
+ } catch (Exception e) {
+ // no-op
+ } finally {
+ mDisplayContent.mOpeningApps.clear();
+ }
+ }
+
private AnimationAdapter setupForNonAppTargetNavBar(int transit, boolean shouldAttachNavBar) {
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
mDisplayContent.mOpeningApps.add(win.mActivityRecord);
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 bed0a94f3b8f..9639aa78fd5b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -158,46 +158,6 @@ public class SizeCompatTests extends WindowTestsBase {
}
@Test
- public void testKeepBoundsWhenChangingFromFreeformToFullscreen() {
- removeGlobalMinSizeRestriction();
- // Create landscape freeform display and a freeform app.
- DisplayContent display = new TestDisplayContent.Builder(mAtm, 2000, 1000)
- .setCanRotate(false)
- .setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM).build();
- setUpApp(display);
-
- // Put app window into portrait freeform and then make it a compat app.
- final Rect bounds = new Rect(100, 100, 400, 600);
- mTask.setBounds(bounds);
- prepareUnresizable(mActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
- assertEquals(bounds, mActivity.getBounds());
- // Activity is not yet in size compat mode; it is filling the freeform task window.
- assertActivityMaxBoundsSandboxed();
-
- // The activity should be able to accept negative x position [-150, 100 - 150, 600].
- final int dx = bounds.left + bounds.width() / 2;
- final int dy = bounds.top + bounds.height() / 2;
- mTask.setBounds(bounds.left - dx, bounds.top - dy, bounds.right - dx, bounds.bottom - dy);
- // expected:<Rect(-150, 100 - 150, 600)> but was:<Rect(-150, 0 - 150, 500)>
- assertEquals(mTask.getBounds(), mActivity.getBounds());
-
- final int density = mActivity.getConfiguration().densityDpi;
-
- // Change display configuration to fullscreen.
- Configuration c = new Configuration(display.getRequestedOverrideConfiguration());
- c.windowConfiguration.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
- display.onRequestedOverrideConfigurationChanged(c);
-
- // Check if dimensions on screen stay the same by scaling.
- assertScaled();
- assertEquals(bounds.width(), mActivity.getBounds().width());
- assertEquals(bounds.height(), mActivity.getBounds().height());
- assertEquals(density, mActivity.getConfiguration().densityDpi);
- // Size compat mode is sandboxed at the activity level.
- assertActivityMaxBoundsSandboxed();
- }
-
- @Test
public void testFixedAspectRatioBoundsWithDecorInSquareDisplay() {
final int notchHeight = 100;
setUpApp(new TestDisplayContent.Builder(mAtm, 600, 800).setNotch(notchHeight).build());
@@ -687,7 +647,7 @@ public class SizeCompatTests extends WindowTestsBase {
.setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
.setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
.build();
- assertTrue(activity.shouldCreateCompatDisplayInsets());
+ assertFalse(activity.shouldCreateCompatDisplayInsets());
// The non-resizable activity should not be size compat because it is on a resizable task
// in multi-window mode.
@@ -719,7 +679,7 @@ public class SizeCompatTests extends WindowTestsBase {
}
@Test
- public void testShouldCreateCompatDisplayInsetsWhenUnresizeableAndSupportsSizeChangesFalse() {
+ public void testShouldNotCreateCompatDisplayInsetsWhenRootActivityIsResizeable() {
setUpDisplaySizeWithApp(1000, 2500);
// Make the task root resizable.
@@ -728,7 +688,7 @@ public class SizeCompatTests extends WindowTestsBase {
// Create an activity on the same task.
final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false,
RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- assertTrue(activity.shouldCreateCompatDisplayInsets());
+ assertFalse(activity.shouldCreateCompatDisplayInsets());
}
@Test
@@ -1124,6 +1084,7 @@ public class SizeCompatTests extends WindowTestsBase {
@Test
@EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+ ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY,
ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM})
public void testOverrideMinAspectRatioScreenOrientationNotSetThenChangedToPortrait() {
// In this test, the activity's orientation isn't fixed to portrait, therefore the override
@@ -1155,6 +1116,7 @@ public class SizeCompatTests extends WindowTestsBase {
@Test
@EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+ ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY,
ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM})
public void testOverrideMinAspectRatioScreenOrientationLandscapeThenChangedToPortrait() {
// In this test, the activity's orientation isn't fixed to portrait, therefore the override
@@ -1187,6 +1149,7 @@ public class SizeCompatTests extends WindowTestsBase {
@Test
@EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+ ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY,
ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM})
public void testOverrideMinAspectRatioScreenOrientationPortraitThenChangedToUnspecified() {
setUpDisplaySizeWithApp(1000, 1200);
@@ -1215,6 +1178,52 @@ public class SizeCompatTests extends WindowTestsBase {
}
@Test
+ @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+ ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM})
+ @DisableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY})
+ public void testOverrideMinAspectRatioPortraitOnlyDisabledScreenOrientationNotSet() {
+ setUpDisplaySizeWithApp(1000, 1200);
+
+ // Create a size compat activity on the same task.
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setTask(mTask)
+ .setComponent(ComponentName.createRelative(mContext,
+ SizeCompatTests.class.getName()))
+ .setUid(android.os.Process.myUid())
+ .build();
+
+ // The per-package override forces the activity into a 3:2 aspect ratio
+ assertEquals(1200, activity.getBounds().height());
+ assertEquals(1200 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE,
+ activity.getBounds().width(), 0.5);
+ }
+
+ @Test
+ @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+ ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM})
+ @DisableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY})
+ public void testOverrideMinAspectRatioPortraitOnlyDisabledScreenOrientationLandscape() {
+ // In this test, the activity's orientation isn't fixed to portrait, therefore the override
+ // isn't applied.
+
+ setUpDisplaySizeWithApp(1000, 1200);
+
+ // Create a size compat activity on the same task.
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setTask(mTask)
+ .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
+ .setComponent(ComponentName.createRelative(mContext,
+ SizeCompatTests.class.getName()))
+ .setUid(android.os.Process.myUid())
+ .build();
+
+ // The per-package override forces the activity into a 3:2 aspect ratio
+ assertEquals(1000 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE,
+ activity.getBounds().height(), 0.5);
+ assertEquals(1000, activity.getBounds().width());
+ }
+
+ @Test
@EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM})
public void testOverrideMinAspectRatioWithoutGlobalOverride() {
// In this test, only OVERRIDE_MIN_ASPECT_RATIO_1_5 is set, which has no effect without
@@ -2269,6 +2278,12 @@ public class SizeCompatTests extends WindowTestsBase {
activity.info.resizeMode = isUnresizable
? RESIZE_MODE_UNRESIZEABLE
: RESIZE_MODE_RESIZEABLE;
+ final Task task = activity.getTask();
+ if (task != null) {
+ // Update the Task resize value as activity will follow the task.
+ task.mResizeMode = activity.info.resizeMode;
+ task.getRootActivity().info.resizeMode = activity.info.resizeMode;
+ }
activity.mVisibleRequested = true;
if (maxAspect >= 0) {
activity.info.setMaxAspectRatio(maxAspect);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index d475c46eed0c..786c3eae63d0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -254,7 +254,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
});
// Allow transaction to change a TaskFragment created by the organizer.
- mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
+ mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
+ "Test:TaskFragmentOrganizer" /* processName */);
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
}
@@ -276,7 +277,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
});
// Allow transaction to change a TaskFragment created by the organizer.
- mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
+ mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
+ "Test:TaskFragmentOrganizer" /* processName */);
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
}
@@ -301,7 +303,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
});
// Allow transaction to change a TaskFragment created by the organizer.
- mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
+ mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
+ "Test:TaskFragmentOrganizer" /* processName */);
clearInvocations(mAtm.mRootWindowContainer);
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
@@ -337,8 +340,10 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
});
// Allow transaction to change a TaskFragment created by the organizer.
- mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
- taskFragment2.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
+ mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
+ "Test:TaskFragmentOrganizer" /* processName */);
+ taskFragment2.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
+ "Test:TaskFragmentOrganizer" /* processName */);
clearInvocations(mAtm.mRootWindowContainer);
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
@@ -391,7 +396,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
});
// Allow transaction to change a TaskFragment created by the organizer.
- mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* pid */);
+ mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
+ "Test:TaskFragmentOrganizer" /* processName */);
clearInvocations(mAtm.mRootWindowContainer);
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index cb209abf6aa9..6737b1ade785 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -20,12 +20,15 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.clearInvocations;
import android.graphics.Rect;
+import android.os.Binder;
import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl;
import android.window.ITaskFragmentOrganizer;
+import android.window.TaskFragmentInfo;
import android.window.TaskFragmentOrganizer;
import androidx.test.filters.MediumTest;
@@ -64,6 +67,7 @@ public class TaskFragmentTest extends WindowTestsBase {
mTaskFragment = new TaskFragmentBuilder(mAtm)
.setCreateParentTask()
.setOrganizer(mOrganizer)
+ .setFragmentToken(new Binder())
.build();
mLeash = mTaskFragment.getSurfaceControl();
spyOn(mTaskFragment);
@@ -82,6 +86,7 @@ public class TaskFragmentTest extends WindowTestsBase {
@Test
public void testStartChangeTransition_resetSurface() {
+ mockSurfaceFreezerSnapshot(mTaskFragment.mSurfaceFreezer);
final Rect startBounds = new Rect(0, 0, 1000, 1000);
final Rect endBounds = new Rect(500, 500, 1000, 1000);
mTaskFragment.setBounds(startBounds);
@@ -102,4 +107,23 @@ public class TaskFragmentTest extends WindowTestsBase {
verify(mTransaction).setPosition(mLeash, 500, 500);
verify(mTransaction).setWindowCrop(mLeash, 500, 500);
}
+
+ /**
+ * Tests that when a {@link TaskFragmentInfo} is generated from a {@link TaskFragment}, an
+ * activity that has not yet been attached to a process because it is being initialized but
+ * belongs to the TaskFragmentOrganizer process is still reported in the TaskFragmentInfo.
+ */
+ @Test
+ public void testActivityStillReported_NotYetAssignedToProcess() {
+ mTaskFragment.addChild(new ActivityBuilder(mAtm).setUid(DEFAULT_TASK_FRAGMENT_ORGANIZER_UID)
+ .setProcessName(DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME).build());
+ final ActivityRecord activity = mTaskFragment.getTopMostActivity();
+ // Remove the process to simulate an activity that has not yet been attached to a process
+ activity.app = null;
+ final TaskFragmentInfo info = activity.getTaskFragment().getTaskFragmentInfo();
+ assertEquals(1, info.getRunningActivityCount());
+ assertEquals(1, info.getActivities().size());
+ assertEquals(false, info.isEmpty());
+ assertEquals(activity.token, info.getActivities().get(0));
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 4e77fa73fd09..d9a166a62673 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -473,7 +473,7 @@ public class TransitionTests extends WindowTestsBase {
final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class);
final TransitionController controller = new TransitionController(mAtm, snapshotController);
final ITransitionPlayer player = new ITransitionPlayer.Default();
- controller.registerTransitionPlayer(player);
+ controller.registerTransitionPlayer(player, null /* appThread */);
ITaskOrganizer mockOrg = mock(ITaskOrganizer.class);
final Transition openTransition = controller.createTransition(TRANSIT_OPEN);
@@ -539,7 +539,7 @@ public class TransitionTests extends WindowTestsBase {
final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class);
final TransitionController controller = new TransitionController(mAtm, snapshotController);
final ITransitionPlayer player = new ITransitionPlayer.Default();
- controller.registerTransitionPlayer(player);
+ controller.registerTransitionPlayer(player, null /* appThread */);
ITaskOrganizer mockOrg = mock(ITaskOrganizer.class);
final Transition openTransition = controller.createTransition(TRANSIT_OPEN);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index 3f0c13c83816..f366f57bae08 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -316,7 +316,8 @@ public class WallpaperControllerTests extends WindowTestsBase {
final IBinder mockBinder = mock(IBinder.class);
final ITransitionPlayer mockPlayer = mock(ITransitionPlayer.class);
doReturn(mockBinder).when(mockPlayer).asBinder();
- mWm.mAtmService.getTransitionController().registerTransitionPlayer(mockPlayer);
+ mWm.mAtmService.getTransitionController().registerTransitionPlayer(mockPlayer,
+ null /* appThread */);
Transition transit =
mWm.mAtmService.getTransitionController().createTransition(TRANSIT_OPEN);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index bbeb980353ed..6ae3f9447ee2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -1118,16 +1118,15 @@ public class WindowContainerTests extends WindowTestsBase {
final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
spyOn(container);
spyOn(surfaceAnimator);
- spyOn(surfaceFreezer);
+ mockSurfaceFreezerSnapshot(surfaceFreezer);
doReturn(t).when(container).getPendingTransaction();
doReturn(t).when(container).getSyncTransaction();
// Leash and snapshot created for change transition.
container.initializeChangeTransition(new Rect(0, 0, 1000, 2000));
- // Can't really take a snapshot, manually set one.
- surfaceFreezer.mSnapshot = mock(SurfaceFreezer.Snapshot.class);
assertNotNull(surfaceFreezer.mLeash);
+ assertNotNull(surfaceFreezer.mSnapshot);
assertEquals(surfaceFreezer.mLeash, container.getAnimationLeash());
// Start animation: surfaceAnimator take over the leash and snapshot from surfaceFreezer.
@@ -1144,9 +1143,9 @@ public class WindowContainerTests extends WindowTestsBase {
// Prepare another change transition.
container.initializeChangeTransition(new Rect(0, 0, 1000, 2000));
- surfaceFreezer.mSnapshot = mock(SurfaceFreezer.Snapshot.class);
assertNotNull(surfaceFreezer.mLeash);
+ assertNotNull(surfaceFreezer.mSnapshot);
assertEquals(surfaceFreezer.mLeash, container.getAnimationLeash());
assertNotEquals(prevLeash, container.getAnimationLeash());
@@ -1173,6 +1172,64 @@ public class WindowContainerTests extends WindowTestsBase {
assertNull(surfaceAnimator.mSnapshot);
}
+ @Test
+ public void testUnfreezeWindow_removeWindowFromChanging() {
+ final WindowContainer container = createTaskFragmentWithParentTask(
+ createTask(mDisplayContent), false);
+ mockSurfaceFreezerSnapshot(container.mSurfaceFreezer);
+ final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+
+ container.initializeChangeTransition(new Rect(0, 0, 1000, 2000));
+
+ assertTrue(mDisplayContent.mChangingContainers.contains(container));
+
+ container.mSurfaceFreezer.unfreeze(t);
+
+ assertFalse(mDisplayContent.mChangingContainers.contains(container));
+ }
+
+ @Test
+ public void testFailToTaskSnapshot_unfreezeWindow() {
+ final WindowContainer container = createTaskFragmentWithParentTask(
+ createTask(mDisplayContent), false);
+ final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+ spyOn(container.mSurfaceFreezer);
+
+ container.initializeChangeTransition(new Rect(0, 0, 1000, 2000));
+
+ verify(container.mSurfaceFreezer).freeze(any(), any(), any(), any());
+ verify(container.mSurfaceFreezer).unfreeze(any());
+ assertTrue(mDisplayContent.mChangingContainers.isEmpty());
+ }
+
+ @Test
+ public void testRemoveUnstartedFreezeSurfaceWhenFreezeAgain() {
+ final WindowContainer container = createTaskFragmentWithParentTask(
+ createTask(mDisplayContent), false);
+ container.mSurfaceControl = mock(SurfaceControl.class);
+ final SurfaceFreezer surfaceFreezer = container.mSurfaceFreezer;
+ mockSurfaceFreezerSnapshot(surfaceFreezer);
+ final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+ spyOn(container);
+ doReturn(t).when(container).getPendingTransaction();
+ doReturn(t).when(container).getSyncTransaction();
+
+ // Leash and snapshot created for change transition.
+ container.initializeChangeTransition(new Rect(0, 0, 1000, 2000));
+
+ assertNotNull(surfaceFreezer.mLeash);
+ assertNotNull(surfaceFreezer.mSnapshot);
+
+ final SurfaceControl prevLeash = surfaceFreezer.mLeash;
+ final SurfaceFreezer.Snapshot prevSnapshot = surfaceFreezer.mSnapshot;
+ spyOn(prevSnapshot);
+
+ container.initializeChangeTransition(new Rect(0, 0, 1500, 2500));
+
+ verify(t).remove(prevLeash);
+ verify(prevSnapshot).destroy(t);
+ }
+
/* Used so we can gain access to some protected members of the {@link WindowContainer} class */
private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
private final int mLayer;
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 a482bdacfc82..1eed79f189a8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -543,6 +543,36 @@ public class WindowOrganizerTests extends WindowTestsBase {
}
@Test
+ public void testSetAdjacentLaunchRoot() {
+ DisplayContent dc = mWm.mRoot.getDisplayContent(Display.DEFAULT_DISPLAY);
+
+ final Task task1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
+ dc, WINDOWING_MODE_MULTI_WINDOW, null);
+ final RunningTaskInfo info1 = task1.getTaskInfo();
+ final Task task2 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
+ dc, WINDOWING_MODE_MULTI_WINDOW, null);
+ final RunningTaskInfo info2 = task2.getTaskInfo();
+
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.setAdjacentRoots(info1.token, info2.token);
+ mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
+ assertEquals(task1.getAdjacentTaskFragment(), task2);
+ assertEquals(task2.getAdjacentTaskFragment(), task1);
+
+ wct = new WindowContainerTransaction();
+ wct.setLaunchAdjacentFlagRoot(info1.token);
+ mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
+ assertEquals(dc.getDefaultTaskDisplayArea().mLaunchAdjacentFlagRootTask, task1);
+
+ task1.setAdjacentTaskFragment(null);
+ task2.setAdjacentTaskFragment(null);
+ wct = new WindowContainerTransaction();
+ wct.clearLaunchAdjacentFlagRoot(info1.token);
+ mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
+ assertEquals(dc.getDefaultTaskDisplayArea().mLaunchAdjacentFlagRootTask, null);
+ }
+
+ @Test
public void testTileAddRemoveChild() {
final StubOrganizer listener = new StubOrganizer();
mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index ac61bb15ab06..88d8ba308b45 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -77,6 +77,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.hardware.HardwareBuffer;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.Bundle;
@@ -127,6 +128,9 @@ class WindowTestsBase extends SystemServiceTestsBase {
// Default package name
static final String DEFAULT_COMPONENT_PACKAGE_NAME = "com.foo";
+ static final int DEFAULT_TASK_FRAGMENT_ORGANIZER_UID = 10000;
+ static final String DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME = "Test:TaskFragmentOrganizer";
+
// Default base activity name
private static final String DEFAULT_COMPONENT_CLASS_NAME = ".BarActivity";
@@ -798,6 +802,14 @@ class WindowTestsBase extends SystemServiceTestsBase {
};
}
+ /** Sets up a simple implementation of transition player for shell transitions. */
+ TestTransitionPlayer registerTestTransitionPlayer() {
+ final TestTransitionPlayer testPlayer = new TestTransitionPlayer(
+ mAtm.getTransitionController(), mAtm.mWindowOrganizerController);
+ testPlayer.mController.registerTransitionPlayer(testPlayer, null /* appThread */);
+ return testPlayer;
+ }
+
/**
* Avoids rotating screen disturbed by some conditions. It is usually used for the default
* display that is not the instance of {@link TestDisplayContent} (it bypasses the conditions).
@@ -870,6 +882,21 @@ class WindowTestsBase extends SystemServiceTestsBase {
mAtm.mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp = 1;
}
+ /** Mocks the behavior of taking a snapshot. */
+ void mockSurfaceFreezerSnapshot(SurfaceFreezer surfaceFreezer) {
+ final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
+ mock(SurfaceControl.ScreenshotHardwareBuffer.class);
+ final HardwareBuffer hardwareBuffer = mock(HardwareBuffer.class);
+ spyOn(surfaceFreezer);
+ doReturn(screenshotBuffer).when(surfaceFreezer)
+ .createSnapshotBufferInner(any(), any());
+ doReturn(null).when(surfaceFreezer)
+ .createFromHardwareBufferInner(any());
+ doReturn(hardwareBuffer).when(screenshotBuffer).getHardwareBuffer();
+ doReturn(100).when(hardwareBuffer).getWidth();
+ doReturn(100).when(hardwareBuffer).getHeight();
+ }
+
/**
* Builder for creating new activities.
*/
@@ -1219,7 +1246,8 @@ class WindowTestsBase extends SystemServiceTestsBase {
}
if (mOrganizer != null) {
taskFragment.setTaskFragmentOrganizer(
- mOrganizer.getOrganizerToken(), 10000 /* pid */);
+ mOrganizer.getOrganizerToken(), DEFAULT_TASK_FRAGMENT_ORGANIZER_UID,
+ DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME);
}
return taskFragment;
}
@@ -1606,7 +1634,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
}
}
- class TestTransitionPlayer extends ITransitionPlayer.Stub {
+ static class TestTransitionPlayer extends ITransitionPlayer.Stub {
final TransitionController mController;
final WindowOrganizerController mOrganizer;
Transition mLastTransit = null;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index 22ea3d5be71b..72b05c08661b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -23,7 +23,6 @@ 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.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
@@ -442,24 +441,42 @@ public class ZOrderingTests extends WindowTestsBase {
@Test
public void testDockedDividerPosition() {
- final WindowState pinnedStackWindow = createWindow(null, WINDOWING_MODE_PINNED,
- ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent,
- "pinnedStackWindow");
- final WindowState splitScreenWindow = createWindow(null,
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION,
- mDisplayContent, "splitScreenWindow");
- final WindowState splitScreenSecondaryWindow = createWindow(null,
- WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD,
- TYPE_BASE_APPLICATION, mDisplayContent, "splitScreenSecondaryWindow");
- final WindowState assistantStackWindow = createWindow(null,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION,
- mDisplayContent, "assistantStackWindow");
+ final Task pinnedTask =
+ createTask(mDisplayContent, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD);
+ final WindowState pinnedWindow =
+ createAppWindow(pinnedTask, ACTIVITY_TYPE_STANDARD, "pinnedWindow");
+
+ final Task belowTask =
+ createTask(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final WindowState belowTaskWindow =
+ createAppWindow(belowTask, ACTIVITY_TYPE_STANDARD, "belowTaskWindow");
+
+ final Task splitScreenTask1 =
+ createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
+ final WindowState splitWindow1 =
+ createAppWindow(splitScreenTask1, ACTIVITY_TYPE_STANDARD, "splitWindow1");
+ final Task splitScreenTask2 =
+ createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
+ final WindowState splitWindow2 =
+ createAppWindow(splitScreenTask2, ACTIVITY_TYPE_STANDARD, "splitWindow2");
+ splitScreenTask1.setAdjacentTaskFragment(splitScreenTask2);
+ splitScreenTask2.setAdjacentTaskFragment(splitScreenTask1);
+
+ final Task aboveTask =
+ createTask(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final WindowState aboveTaskWindow =
+ createAppWindow(aboveTask, ACTIVITY_TYPE_STANDARD, "aboveTaskWindow");
mDisplayContent.assignChildLayers(mTransaction);
- assertWindowHigher(mDockedDividerWindow, splitScreenWindow);
- assertWindowHigher(mDockedDividerWindow, splitScreenSecondaryWindow);
- assertWindowHigher(pinnedStackWindow, mDockedDividerWindow);
+ assertWindowHigher(splitWindow1, belowTaskWindow);
+ assertWindowHigher(splitWindow1, belowTaskWindow);
+ assertWindowHigher(splitWindow2, belowTaskWindow);
+ assertWindowHigher(splitWindow2, belowTaskWindow);
+ assertWindowHigher(mDockedDividerWindow, splitWindow1);
+ assertWindowHigher(mDockedDividerWindow, splitWindow2);
+ assertWindowHigher(aboveTaskWindow, mDockedDividerWindow);
+ assertWindowHigher(pinnedWindow, aboveTaskWindow);
}
@Test
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 1b8492722c10..ac1fcce20dc0 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -380,6 +380,7 @@ public class UsageStatsService extends SystemService implements
if (userId == UserHandle.USER_SYSTEM) {
UsageStatsIdleService.scheduleUpdateMappingsJob(getContext());
}
+ final boolean deleteObsoleteData = shouldDeleteObsoleteData(UserHandle.of(userId));
synchronized (mLock) {
// This should be safe to add this early. Other than reportEventOrAddToQueue, every
// other user grabs the lock before accessing
@@ -402,7 +403,7 @@ public class UsageStatsService extends SystemService implements
boolean needToFlush = !pendingEvents.isEmpty();
initializeUserUsageStatsServiceLocked(userId, System.currentTimeMillis(),
- installedPackages);
+ installedPackages, deleteObsoleteData);
final UserUsageStatsService userService = getUserUsageStatsServiceLocked(userId);
if (userService == null) {
Slog.i(TAG, "Attempted to unlock stopped or removed user " + userId);
@@ -596,13 +597,13 @@ public class UsageStatsService extends SystemService implements
* when the user is initially unlocked.
*/
private void initializeUserUsageStatsServiceLocked(int userId, long currentTimeMillis,
- HashMap<String, Long> installedPackages) {
+ HashMap<String, Long> installedPackages, boolean deleteObsoleteData) {
final File usageStatsDir = new File(Environment.getDataSystemCeDirectory(userId),
"usagestats");
final UserUsageStatsService service = new UserUsageStatsService(getContext(), userId,
usageStatsDir, this);
try {
- service.init(currentTimeMillis, installedPackages);
+ service.init(currentTimeMillis, installedPackages, deleteObsoleteData);
mUserState.put(userId, service);
} catch (Exception e) {
if (mUserManager.isUserUnlocked(userId)) {
@@ -1165,6 +1166,10 @@ public class UsageStatsService extends SystemService implements
* Called by the Binder stub.
*/
private boolean updatePackageMappingsData() {
+ // don't update the mappings if a profile user is defined
+ if (!shouldDeleteObsoleteData(UserHandle.SYSTEM)) {
+ return true; // return true so job scheduler doesn't reschedule the job
+ }
// fetch the installed packages outside the lock so it doesn't block package manager.
final HashMap<String, Long> installedPkgs = getInstalledPackages(UserHandle.USER_SYSTEM);
synchronized (mLock) {
@@ -1309,6 +1314,13 @@ public class UsageStatsService extends SystemService implements
}
}
+ private boolean shouldDeleteObsoleteData(UserHandle userHandle) {
+ final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
+ // If a profile owner is not defined for the given user, obsolete data should be deleted
+ return dpmInternal == null
+ || dpmInternal.getProfileOwnerOrDeviceOwnerSupervisionComponent(userHandle) == null;
+ }
+
private String buildFullToken(String packageName, String token) {
final StringBuilder sb = new StringBuilder(packageName.length() + token.length() + 1);
sb.append(packageName);
@@ -2532,8 +2544,12 @@ public class UsageStatsService extends SystemService implements
private class MyPackageMonitor extends PackageMonitor {
@Override
public void onPackageRemoved(String packageName, int uid) {
- mHandler.obtainMessage(MSG_PACKAGE_REMOVED, getChangingUserId(), 0, packageName)
- .sendToTarget();
+ final int changingUserId = getChangingUserId();
+ // Only remove the package's data if a profile owner is not defined for the user
+ if (shouldDeleteObsoleteData(UserHandle.of(changingUserId))) {
+ mHandler.obtainMessage(MSG_PACKAGE_REMOVED, changingUserId, 0, packageName)
+ .sendToTarget();
+ }
super.onPackageRemoved(packageName, uid);
}
}
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 36d8c857ca21..fee4a47fd6ff 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -115,8 +115,9 @@ class UserUsageStatsService {
mSystemTimeSnapshot = System.currentTimeMillis();
}
- void init(final long currentTimeMillis, HashMap<String, Long> installedPackages) {
- readPackageMappingsLocked(installedPackages);
+ void init(final long currentTimeMillis, HashMap<String, Long> installedPackages,
+ boolean deleteObsoleteData) {
+ readPackageMappingsLocked(installedPackages, deleteObsoleteData);
mDatabase.init(currentTimeMillis);
if (mDatabase.wasUpgradePerformed()) {
mDatabase.prunePackagesDataOnUpgrade(installedPackages);
@@ -180,12 +181,13 @@ class UserUsageStatsService {
return mDatabase.onPackageRemoved(packageName, timeRemoved);
}
- private void readPackageMappingsLocked(HashMap<String, Long> installedPackages) {
+ private void readPackageMappingsLocked(HashMap<String, Long> installedPackages,
+ boolean deleteObsoleteData) {
mDatabase.readMappingsLocked();
// Package mappings for the system user are updated after 24 hours via a job scheduled by
// UsageStatsIdleService to ensure restored data is not lost on first boot. Additionally,
// this makes user service initialization a little quicker on subsequent boots.
- if (mUserId != UserHandle.USER_SYSTEM) {
+ if (mUserId != UserHandle.USER_SYSTEM && deleteObsoleteData) {
updatePackageMappingsLocked(installedPackages);
}
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 68ef7543c33f..4d2e00785d49 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -963,6 +963,21 @@ public class CarrierConfigManager {
= "carrier_use_ims_first_for_emergency_bool";
/**
+ * When {@code true}, the determination of whether to place a call as an emergency call will be
+ * based on the known {@link android.telephony.emergency.EmergencyNumber}s for the SIM on which
+ * the call is being placed. In a dual SIM scenario, if Sim A has the emergency numbers
+ * 123, 456 and Sim B has the emergency numbers 789, and the user places a call on SIM A to 789,
+ * it will not be treated as an emergency call in this case.
+ * When {@code false}, the determination is based on the emergency numbers from all device SIMs,
+ * regardless of which SIM the call is being placed on. If Sim A has the emergency numbers
+ * 123, 456 and Sim B has the emergency numbers 789, and the user places a call on SIM A to 789,
+ * the call will be dialed as an emergency number, but with an unspecified routing.
+ * @hide
+ */
+ public static final String KEY_USE_ONLY_DIALED_SIM_ECC_LIST_BOOL =
+ "use_only_dialed_sim_ecc_list_bool";
+
+ /**
* When IMS instant lettering is available for a carrier (see
* {@link #KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL}), determines the list of characters
* which may not be contained in messages. Should be specified as a regular expression suitable
@@ -1874,6 +1889,20 @@ public class CarrierConfigManager {
"lte_plus_threshold_bandwidth_khz_int";
/**
+ * The combined channel bandwidth threshold (non-inclusive) in KHz required to display the
+ * NR advanced (i.e. 5G+) data icon. It is 0 by default, meaning minimum bandwidth check is
+ * not enabled. Other factors like bands or frequency can also determine whether the NR
+ * advanced data icon is shown or not.
+ *
+ * @see #KEY_ADDITIONAL_NR_ADVANCED_BANDS_INT_ARRAY
+ * @see #KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT
+ *
+ * @hide
+ */
+ public static final String KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT =
+ "nr_advanced_threshold_bandwidth_khz_int";
+
+ /**
* The string is used to filter redundant string from PLMN Network Name that's supplied by
* specific carrier.
*
@@ -3538,6 +3567,17 @@ public class CarrierConfigManager {
"nr_advanced_capable_pco_id_int";
/**
+ * Enabled NR advanced (i.e. 5G+) icon while roaming. The default value is {@code true}, meaming
+ * the same NR advanced logic used for home network will be used for roaming network as well.
+ * Set this to {@code false} will disable NR advanced icon while the device is roaming,
+ * regardless meeting NR advanced criteria or not.
+ *
+ * @hide
+ */
+ public static final String KEY_ENABLE_NR_ADVANCED_WHILE_ROAMING_BOOL =
+ "enable_nr_advanced_for_roaming_bool";
+
+ /**
* This configuration allows the framework to use user data communication to detect Idle state,
* and this is used on the 5G icon.
*
@@ -3853,6 +3893,30 @@ public class CarrierConfigManager {
public static final String KEY_ENABLE_4G_OPPORTUNISTIC_NETWORK_SCAN_BOOL =
"enabled_4g_opportunistic_network_scan_bool";
+ /**
+ * Only relevant when the device supports opportunistic networks but does not support
+ * simultaneuous 5G+5G. Controls how long, in milliseconds, to wait before opportunistic network
+ * goes out of service before switching the 5G capability back to primary stack. The idea of
+ * waiting a few seconds is to minimize the calling of the expensive capability switching
+ * operation in the case where CBRS goes back into service shortly after going out of it.
+ *
+ * @hide
+ */
+ public static final String KEY_TIME_TO_SWITCH_BACK_TO_PRIMARY_IF_OPPORTUNISTIC_OOS_LONG =
+ "time_to_switch_back_to_primary_if_opportunistic_oos_long";
+
+ /**
+ * Only relevant when the device supports opportunistic networks but does not support
+ * simultaneuous 5G+5G. Controls how long, in milliseconds, after 5G capability has switched back
+ * to primary stack due to opportunistic network being OOS. The idea is to minimizing the
+ * 'ping-ponging' effect where device is constantly witching capability back and forth between
+ * primary and opportunistic stack.
+ *
+ * @hide
+ */
+ public static final String KEY_OPPORTUNISTIC_TIME_TO_SCAN_AFTER_CAPABILITY_SWITCH_TO_PRIMARY_LONG
+ = "opportunistic_time_to_scan_after_capability_switch_to_primary_long";
+
/**
* Indicates zero or more emergency number prefix(es), because some carrier requires
* if users dial an emergency number address with a specific prefix, the combination of the
@@ -5171,6 +5235,16 @@ public class CarrierConfigManager {
public static final String KEY_VONR_SETTING_VISIBILITY_BOOL = "vonr_setting_visibility_bool";
/**
+ * Flag specifying whether VoNR should be enabled for carrier.
+ * If true, VoNr will be enabled. If false, hard disabled.
+ *
+ * Disabled by default.
+ *
+ * @hide
+ */
+ public static final String KEY_VONR_ENABLED_BOOL = "vonr_enabled_bool";
+
+ /**
* Determine whether unthrottle data retry when tracking area code (TAC/LAC) from cell changes
*
* @hide
@@ -5230,6 +5304,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_CARRIER_IMS_GBA_REQUIRED_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL, true);
+ sDefaults.putBoolean(KEY_USE_ONLY_DIALED_SIM_ECC_LIST_BOOL, false);
sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING, "");
sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING, "");
sDefaults.putString(KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING, "");
@@ -5565,6 +5640,7 @@ public class CarrierConfigManager {
sDefaults.putString(KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING, "");
sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true);
sDefaults.putInt(KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT, 20000);
+ sDefaults.putInt(KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 0);
sDefaults.putIntArray(KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY,
new int[]{CARRIER_NR_AVAILABILITY_NSA, CARRIER_NR_AVAILABILITY_SA});
sDefaults.putBoolean(KEY_LTE_ENABLED_BOOL, true);
@@ -5660,6 +5736,7 @@ public class CarrierConfigManager {
sDefaults.putLong(KEY_5G_WATCHDOG_TIME_MS_LONG, 3600000);
sDefaults.putIntArray(KEY_ADDITIONAL_NR_ADVANCED_BANDS_INT_ARRAY, new int[0]);
sDefaults.putInt(KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0);
+ sDefaults.putBoolean(KEY_ENABLE_NR_ADVANCED_WHILE_ROAMING_BOOL, true);
sDefaults.putBoolean(KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL, false);
sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_BOOL, false);
sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, false);
@@ -5713,6 +5790,10 @@ public class CarrierConfigManager {
/* Default value is 2 seconds. */
sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG, 2000);
sDefaults.putBoolean(KEY_ENABLE_4G_OPPORTUNISTIC_NETWORK_SCAN_BOOL, true);
+ sDefaults.putInt(KEY_TIME_TO_SWITCH_BACK_TO_PRIMARY_IF_OPPORTUNISTIC_OOS_LONG, 60000);
+ sDefaults.putInt(
+ KEY_OPPORTUNISTIC_TIME_TO_SCAN_AFTER_CAPABILITY_SWITCH_TO_PRIMARY_LONG,
+ 120000);
sDefaults.putAll(Gps.getDefaults());
sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY,
new int[] {
@@ -5785,6 +5866,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL, false);
sDefaults.putBoolean(KEY_UNTHROTTLE_DATA_RETRY_WHEN_TAC_CHANGES_BOOL, false);
sDefaults.putBoolean(KEY_VONR_SETTING_VISIBILITY_BOOL, false);
+ sDefaults.putBoolean(KEY_VONR_ENABLED_BOOL, false);
}
/**
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 114c90bbd87a..1be1f2f8de30 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -949,6 +949,15 @@ public class SubscriptionManager {
public static final String VOIMS_OPT_IN_STATUS = SimInfo.COLUMN_VOIMS_OPT_IN_STATUS;
/**
+ * TelephonyProvider column name for NR Advanced calling
+ * Determines if the user has enabled VoNR settings for this subscription.
+ *
+ * @hide
+ */
+ public static final String NR_ADVANCED_CALLING_ENABLED =
+ SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED;
+
+ /**
* Profile class of the subscription
* @hide
*/
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index e890acb36b48..9572154ec773 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -36,6 +36,7 @@ import com.android.telephony.Rlog;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -152,16 +153,9 @@ public final class TelephonyScanManager {
throw new RuntimeException(
"Failed to find NetworkScanInfo with id " + message.arg2);
}
- NetworkScanCallback callback = nsi.mCallback;
- Executor executor = nsi.mExecutor;
- if (callback == null) {
- throw new RuntimeException(
- "Failed to find NetworkScanCallback with id " + message.arg2);
- }
- if (executor == null) {
- throw new RuntimeException(
- "Failed to find Executor with id " + message.arg2);
- }
+
+ final NetworkScanCallback callback = nsi.mCallback;
+ final Executor executor = nsi.mExecutor;
switch (message.what) {
case CALLBACK_RESTRICTED_SCAN_RESULTS:
@@ -246,17 +240,24 @@ public final class TelephonyScanManager {
NetworkScanRequest request, Executor executor, NetworkScanCallback callback,
String callingPackage, @Nullable String callingFeatureId) {
try {
+ Objects.requireNonNull(request, "Request was null");
+ Objects.requireNonNull(callback, "Callback was null");
+ Objects.requireNonNull(executor, "Executor was null");
final ITelephony telephony = getITelephony();
if (telephony == null) return null;
- int scanId = telephony.requestNetworkScan(
- subId, request, mMessenger, new Binder(), callingPackage,
- callingFeatureId);
- if (scanId == INVALID_SCAN_ID) {
- Rlog.e(TAG, "Failed to initiate network scan");
- return null;
- }
+ // The lock must be taken before calling requestNetworkScan because the resulting
+ // scanId can be invoked asynchronously on another thread at any time after
+ // requestNetworkScan invoked, leaving a critical section between that call and adding
+ // the record to the ScanInfo cache.
synchronized (mScanInfo) {
+ int scanId = telephony.requestNetworkScan(
+ subId, request, mMessenger, new Binder(), callingPackage,
+ callingFeatureId);
+ if (scanId == INVALID_SCAN_ID) {
+ Rlog.e(TAG, "Failed to initiate network scan");
+ return null;
+ }
// We link to death whenever a scan is started to ensure that we are linked
// at the point that phone process death might matter.
// We never unlink because:
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 1c2164a70a55..7ee6451b2797 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
@@ -84,4 +84,20 @@ open class ImeAppHelper @JvmOverloads constructor(
wmHelper.waitImeGone()
}
}
+
+ @JvmOverloads
+ open fun finishActivity(device: UiDevice, wmHelper: WindowManagerStateHelper? = null) {
+ val finishButton = device.wait(
+ Until.findObject(By.res(getPackage(), "finish_activity_btn")),
+ FIND_TIMEOUT)
+ require(finishButton != null) {
+ "Finish activity button not found, probably IME activity is not on the screen ?"
+ }
+ finishButton.click()
+ if (wmHelper == null) {
+ device.waitForIdle()
+ } else {
+ wmHelper.waitForActivityRemoved(component)
+ }
+ }
} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt
new file mode 100644
index 000000000000..972918e28fa7
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt
@@ -0,0 +1,131 @@
+/*
+ * 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.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.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.*
+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.helpers.SimpleAppHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Unlike {@link OpenImeWindowTest} testing IME window opening transitions, this test also verify
+ * there is no flickering when back to the simple activity without requesting IME to show.
+ *
+ * To run this test: `atest FlickerTests:OpenImeWindowAndCloseTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
+class OpenImeWindowAndCloseTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val simpleApp = SimpleAppHelper(instrumentation)
+ private val testApp = ImeAppHelper(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ eachRun {
+ simpleApp.launchViaIntent(wmHelper)
+ testApp.launchViaIntent(wmHelper)
+ testApp.openIME(device, wmHelper)
+ }
+ }
+ transitions {
+ testApp.finishActivity(device, wmHelper)
+ }
+ teardown {
+ test {
+ simpleApp.exit()
+ }
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun navBarWindowIsVisible() = testSpec.navBarWindowIsVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarWindowIsVisible() = testSpec.statusBarWindowIsVisible()
+
+ @Presubmit
+ @Test
+ fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible()
+
+ @Presubmit
+ @Test
+ fun navBarLayerIsVisible() = testSpec.navBarLayerIsVisible()
+
+ @Presubmit
+ @Test
+ fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
+
+ @Presubmit
+ @Test
+ fun entireScreenCovered() = testSpec.entireScreenCovered()
+
+ @Presubmit
+ @Test
+ fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+
+ @Presubmit
+ @Test
+ fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertLayers {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ @Test
+ fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+ testSpec.assertWm {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(
+ repetitions = 3,
+ supportedRotations = listOf(Surface.ROTATION_0),
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
+ WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+ )
+ )
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
index cf10c5366ce9..08aaea70762f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -28,7 +28,7 @@ import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.statusBarWindowIsVisible
+import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.traces.common.FlickerComponentName
import com.google.common.truth.Truth
import org.junit.FixMethodOrder
@@ -171,6 +171,37 @@ class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransiti
@Test
override fun statusBarWindowIsVisible() = super.statusBarWindowIsVisible()
+ /**
+ * Checks that the status bar layer is visible at the end of the trace
+ *
+ * It is not possible to check at the start because the animation is working differently
+ * in devices with and without blur (b/202936526)
+ */
+ @Presubmit
+ @Test
+ override fun statusBarLayerIsVisible() {
+ testSpec.assertLayersEnd {
+ this.isVisible(FlickerComponentName.STATUS_BAR)
+ }
+ }
+
+ /** {@inheritDoc} */
+ @FlakyTest(bugId = 202936526)
+ @Test
+ override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ fun statusBarLayerPositionAtEnd() {
+ testSpec.assertLayersEnd {
+ val display = this.entry.displays.minByOrNull { it.id }
+ ?: throw RuntimeException("There is no display!")
+ this.visibleRegion(FlickerComponentName.STATUS_BAR)
+ .coversExactly(WindowUtils.getStatusBarPosition(display))
+ }
+ }
+
/** {@inheritDoc} */
@FlakyTest
@Test
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 c55e7c2720db..2620ff407efc 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml
@@ -18,6 +18,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:orientation="vertical"
android:focusableInTouchMode="true"
android:background="@android:color/holo_green_light">
<EditText android:id="@+id/plain_text_input"
@@ -25,4 +26,9 @@
android:layout_width="match_parent"
android:imeOptions="flagNoExtractUi"
android:inputType="text"/>
+ <Button
+ android:id="@+id/finish_activity_btn"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Finish activity" />
</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java
index df60460e7ae3..d7ee2af44111 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java
@@ -19,6 +19,7 @@ package com.android.server.wm.flicker.testapp;
import android.app.Activity;
import android.os.Bundle;
import android.view.WindowManager;
+import android.widget.Button;
public class ImeActivity extends Activity {
@Override
@@ -29,5 +30,9 @@ public class ImeActivity extends Activity {
.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
getWindow().setAttributes(p);
setContentView(R.layout.activity_ime);
+ Button button = findViewById(R.id.finish_activity_btn);
+ button.setOnClickListener(view -> {
+ finish();
+ });
}
}
diff --git a/tools/aapt/SdkConstants.h b/tools/aapt/SdkConstants.h
index 955581cf8655..daf91b032638 100644
--- a/tools/aapt/SdkConstants.h
+++ b/tools/aapt/SdkConstants.h
@@ -47,6 +47,7 @@ enum {
SDK_Q = 29,
SDK_R = 30,
SDK_S = 31,
+ SDK_S_V2 = 32,
};
#endif // H_AAPT_SDK_CONSTANTS
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index cbcbf05c860c..f8e448f0f676 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -60,6 +60,7 @@ static const std::vector<std::pair<uint16_t, ApiVersion>> sAttrIdMap = {
{0x0606, SDK_Q},
{0x0616, SDK_R},
{0x064b, SDK_S},
+ {0x064c, SDK_S_V2},
};
static bool less_entry_id(const std::pair<uint16_t, ApiVersion>& p, uint16_t entryId) {
diff --git a/tools/aapt2/SdkConstants.h b/tools/aapt2/SdkConstants.h
index 6bb6ddb13bdb..0f27ac50b3bf 100644
--- a/tools/aapt2/SdkConstants.h
+++ b/tools/aapt2/SdkConstants.h
@@ -57,6 +57,7 @@ enum : ApiVersion {
SDK_Q = 29,
SDK_R = 30,
SDK_S = 31,
+ SDK_S_V2 = 32,
};
ApiVersion FindAttributeSdkLevel(const ResourceId& id);
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index 72eaa3561a02..a8845ef96bc3 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -120,6 +120,13 @@ bool BinaryResourceParser::Parse() {
static_cast<int>(parser.chunk()->type)));
}
}
+
+ if (!staged_entries_to_remove_.empty()) {
+ diag_->Error(DiagMessage(source_) << "didn't find " << staged_entries_to_remove_.size()
+ << " original staged resources");
+ return false;
+ }
+
return true;
}
@@ -393,6 +400,12 @@ bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
return false;
}
+ if (const auto to_remove_it = staged_entries_to_remove_.find({name, res_id});
+ to_remove_it != staged_entries_to_remove_.end()) {
+ staged_entries_to_remove_.erase(to_remove_it);
+ continue;
+ }
+
NewResourceBuilder res_builder(name);
res_builder.SetValue(std::move(resource_value), config)
.SetId(res_id, OnIdConflict::CREATE_ENTRY)
@@ -533,9 +546,8 @@ bool BinaryResourceParser::ParseStagedAliases(const ResChunk_header* chunk) {
// Since a the finalized resource entry is cloned and added to the resource table under the
// staged resource id, remove the cloned resource entry from the table.
if (!table_->RemoveResource(resource_name, staged_id)) {
- diag_->Error(DiagMessage(source_) << "failed to find resource entry for staged "
- << " resource ID " << staged_id);
- return false;
+ // If we haven't seen this resource yet let's add a record to skip it when parsing.
+ staged_entries_to_remove_.insert({resource_name, staged_id});
}
}
return true;
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.h b/tools/aapt2/format/binary/BinaryResourceParser.h
index cd71d160703a..1c83166c5cce 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.h
+++ b/tools/aapt2/format/binary/BinaryResourceParser.h
@@ -119,6 +119,10 @@ class BinaryResourceParser {
// A mapping of resource ID to type spec flags.
std::unordered_map<ResourceId, uint32_t> entry_type_spec_flags_;
+
+ // A collection of staged resources that got finalized already and we're supposed to prune -
+ // but the original staged resource record hasn't been parsed yet.
+ std::set<std::pair<ResourceName, ResourceId>> staged_entries_to_remove_;
};
} // namespace aapt
diff --git a/tools/finalize_res/finalize_res.py b/tools/finalize_res/finalize_res.py
index aaf01875024e..724443c01852 100755
--- a/tools/finalize_res/finalize_res.py
+++ b/tools/finalize_res/finalize_res.py
@@ -17,6 +17,7 @@
"""
Finalize resource values in <staging-public-group> tags
+and convert those to <staging-public-group-final>
Usage: finalize_res.py core/res/res/values/public.xml public_finalized.xml
"""
@@ -24,18 +25,40 @@ Usage: finalize_res.py core/res/res/values/public.xml public_finalized.xml
import re, sys, codecs
def finalize_item(raw):
- global _type, _id
- _id += 1
- return '<public type="%s" name="%s" id="%s" />' % (_type, raw.group(1), '0x{0:0{1}x}'.format(_id-1,8))
+ global _type_ids, _type
+ id = _type_ids[_type]
+ _type_ids[_type] += 1
+ name = raw.group(1)
+ val = '<public type="%s" name="%s" id="%s" />' % (_type, name, '0x{0:0{1}x}'.format(id,8))
+ if re.match(r'_*removed.+', name):
+ val = '<!-- ' + val.replace('<public', '< public') + ' -->'
+ return val
def finalize_group(raw):
- global _type, _id
+ global _type_ids, _type
_type = raw.group(1)
- _id = int(raw.group(2), 16)
- return re.sub(r'<public name="(.+?)" */>', finalize_item, raw.group(3))
+ id = int(raw.group(2), 16)
+ _type_ids[_type] = _type_ids.get(_type, id)
+ (res, count) = re.subn(r' {0,2}<public name="(.+?)" */>', finalize_item, raw.group(3))
+ if count > 0:
+ res = raw.group(0).replace("staging-public-group", "staging-public-group-final") + '\n' + res
+ return res
+
+def collect_ids(raw):
+ global _type_ids
+ for m in re.finditer(r'<public type="(.+?)" name=".+?" id="(.+?)" />', raw):
+ type = m.group(1)
+ id = int(m.group(2), 16)
+ _type_ids[type] = max(id + 1, _type_ids.get(type, 0))
with open(sys.argv[1]) as f:
+ global _type_ids, _type
+ _type_ids = {}
raw = f.read()
+ collect_ids(raw)
raw = re.sub(r'<staging-public-group type="(.+?)" first-id="(.+?)">(.+?)</staging-public-group>', finalize_group, raw, flags=re.DOTALL)
+ raw = re.sub(r' *\n', '\n', raw)
+ raw = re.sub(r'\n{3,}', '\n\n', raw)
with open(sys.argv[2], "w") as f:
f.write(raw)
+