summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java2
-rw-r--r--core/api/test-current.txt8
-rw-r--r--core/java/android/app/ActivityManager.java29
-rw-r--r--core/java/android/app/ActivityManagerInternal.java7
-rw-r--r--core/java/android/app/ActivityThread.java27
-rw-r--r--core/java/android/app/ContextImpl.java57
-rw-r--r--core/java/android/app/IActivityManager.aidl2
-rw-r--r--core/java/android/app/admin/DevicePolicyManagerInternal.java8
-rw-r--r--core/java/android/appwidget/AppWidgetHostView.java16
-rw-r--r--core/java/android/companion/CompanionDeviceManager.java3
-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/view/IRecentsAnimationRunner.aidl2
-rw-r--r--core/java/android/view/IWindowManager.aidl17
-rw-r--r--core/java/android/view/SurfaceView.java29
-rw-r--r--core/java/android/view/ViewRootImpl.java50
-rw-r--r--core/java/android/view/WindowManager.java19
-rw-r--r--core/java/android/widget/RemoteViews.java16
-rw-r--r--core/java/android/window/TaskFragmentInfo.java1
-rw-r--r--core/java/android/window/WindowContextController.java39
-rw-r--r--core/java/android/window/WindowTokenClient.java91
-rw-r--r--core/res/res/values/config.xml5
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/tests/coretests/src/android/window/WindowContextControllerTest.java16
-rw-r--r--data/etc/car/com.android.car.shell.xml1
-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.java69
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java45
-rw-r--r--libs/WindowManager/Jetpack/window-extensions-release.aarbin18462 -> 19183 bytes
-rw-r--r--libs/WindowManager/Shell/res/layout/pip_menu.xml21
-rw-r--r--libs/WindowManager/Shell/res/values/strings.xml3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java65
-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.java3
-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.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java9
-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/RecentTasksController.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java19
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/util/StagedSplitBounds.java114
-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/recents/RecentTasksControllerTest.java31
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/StagedSplitBoundsTest.java94
-rw-r--r--libs/hwui/pipeline/skia/FunctorDrawable.h4
-rw-r--r--libs/hwui/pipeline/skia/TransformCanvas.cpp14
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java4
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java9
-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/media/InfoMediaManager.java8
-rw-r--r--packages/SystemUI/Android.bp12
-rw-r--r--packages/SystemUI/AndroidManifest.xml4
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt176
-rw-r--r--packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt3
-rw-r--r--packages/SystemUI/res/drawable/stat_sys_managed_profile_status.xml2
-rw-r--r--packages/SystemUI/res/layout/global_screenshot_static.xml2
-rw-r--r--packages/SystemUI/res/layout/qs_user_dialog_content.xml128
-rw-r--r--packages/SystemUI/res/layout/screen_record_dialog.xml3
-rw-r--r--packages/SystemUI/res/values/strings.xml2
-rw-r--r--packages/SystemUI/res/values/styles.xml1
-rw-r--r--packages/SystemUI/res/xml/media_collapsed.xml4
-rw-r--r--packages/SystemUI/shared/Android.bp5
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt157
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt38
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/flags/FlagReader.kt5
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/GroupTask.java45
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java9
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java98
-rw-r--r--packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java56
-rw-r--r--packages/SystemUI/src-release/com/android/systemui/flags/FeatureFlagManager.java10
-rw-r--r--packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java12
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java22
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java3
-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.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java7
-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/flags/FeatureFlagReader.java175
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java61
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSSquishinessController.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/TileLayout.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java12
-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/InternetTile.java17
-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.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt3
-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/statusbar/LightRevealScrim.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java8
-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.java24
-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/events/PrivacyDotViewController.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java161
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java2
-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.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java65
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java114
-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.kt138
-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.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt118
-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/dagger/StatusBarPolicyModule.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowView.java93
-rw-r--r--packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java58
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt35
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java68
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java4
-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.java7
-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/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/monet/ColorSchemeTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSSquishinessControllerTest.kt17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt10
-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/tiles/CastTileTest.java25
-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.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java5
-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/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/KeyguardStatusBarViewControllerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java29
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt68
-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.kt10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManagerTest.kt141
-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--services/core/java/com/android/server/TelephonyRegistry.java102
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java10
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java19
-rw-r--r--services/core/java/com/android/server/am/UserController.java46
-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/fingerprint/FingerprintService.java9
-rw-r--r--services/core/java/com/android/server/camera/CameraServiceProxy.java96
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java7
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodMenuController.java2
-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/pm/verify/domain/DomainVerificationService.java2
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java27
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java18
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java4
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java15
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java46
-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/RecentsAnimationController.java51
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java2
-rw-r--r--services/core/java/com/android/server/wm/Task.java10
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java22
-rw-r--r--services/core/java/com/android/server/wm/WindowContextListenerController.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java41
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java228
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java7
-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/wmtests/src/com/android/server/wm/ActivityRecordTests.java22
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java37
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java52
-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.java23
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java6
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java26
-rw-r--r--services/usage/java/com/android/server/usage/UserUsageStatsService.java10
249 files changed, 4535 insertions, 3148 deletions
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
index 1c40a06c1c86..42fb24f570d2 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
@@ -217,7 +217,7 @@ public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase
}
@Override
- public void onTaskAppeared(RemoteAnimationTarget app) throws RemoteException {
+ public void onTasksAppeared(RemoteAnimationTarget[] app) throws RemoteException {
/* no-op */
}
};
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 7acc0d7d3a23..e3a6dd07b526 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -113,7 +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_FULL}) public void setStopBackgroundUsersOnSwitch(int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) 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();
@@ -128,9 +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_BG_USERS_ON_SWITCH_DEFAULT = -1; // 0xffffffff
- field public static final int STOP_BG_USERS_ON_SWITCH_FALSE = 0; // 0x0
- field public static final int STOP_BG_USERS_ON_SWITCH_TRUE = 1; // 0x1
+ 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 {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 50a562b66f16..f0deecac96c5 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4081,45 +4081,46 @@ public class ActivityManager {
* @hide
*/
@TestApi
- public static final int STOP_BG_USERS_ON_SWITCH_DEFAULT = -1;
+ public static final int STOP_USER_ON_SWITCH_DEFAULT = -1;
/**
- * Overrides value defined by the platform and stop background users on switch.
+ * Overrides value defined by the platform and stop user on switch.
*
* @hide
*/
@TestApi
- public static final int STOP_BG_USERS_ON_SWITCH_TRUE = 1;
+ public static final int STOP_USER_ON_SWITCH_TRUE = 1;
/**
- * Overrides value defined by the platform and don't stop background users on switch.
+ * Overrides value defined by the platform and don't stop user on switch.
*
* @hide
*/
@TestApi
- public static final int STOP_BG_USERS_ON_SWITCH_FALSE = 0;
+ public static final int STOP_USER_ON_SWITCH_FALSE = 0;
/** @hide */
- @IntDef(prefix = { "STOP_BG_USERS_ON_SWITCH_" }, value = {
- STOP_BG_USERS_ON_SWITCH_DEFAULT,
- STOP_BG_USERS_ON_SWITCH_TRUE,
- STOP_BG_USERS_ON_SWITCH_FALSE
+ @IntDef(prefix = { "STOP_USER_ON_SWITCH_" }, value = {
+ STOP_USER_ON_SWITCH_DEFAULT,
+ STOP_USER_ON_SWITCH_TRUE,
+ STOP_USER_ON_SWITCH_FALSE
})
- public @interface StopBgUsersOnSwitch {}
+ public @interface StopUserOnSwitch {}
/**
- * Sets whether background users should be stopped when the current user is switched.
+ * Sets whether the current foreground user (and its profiles) should be stopped after switched
+ * out.
*
- * <p>Should only be used on tests.
+ * <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_FULL})
- public void setStopBackgroundUsersOnSwitch(@StopBgUsersOnSwitch int value) {
+ public void setStopUserOnSwitch(@StopUserOnSwitch int value) {
try {
- getService().setStopBackgroundUsersOnSwitch(value);
+ getService().setStopUserOnSwitch(value);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index b416c95329b2..7be4c3e1465b 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -16,7 +16,7 @@
package android.app;
-import static android.app.ActivityManager.StopBgUsersOnSwitch;
+import static android.app.ActivityManager.StopUserOnSwitch;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -663,9 +663,10 @@ public abstract class ActivityManagerInternal {
@Nullable VoiceInteractionManagerProvider provider);
/**
- * Sets whether background users should be stopped when the current user is switched.
+ * Sets whether the current foreground user (and its profiles) should be stopped after switched
+ * out.
*/
- public abstract void setStopBackgroundUsersOnSwitch(@StopBgUsersOnSwitch int value);
+ public abstract void setStopUserOnSwitch(@StopUserOnSwitch int value);
/**
* Provides the interface to communicate between voice interaction manager service and
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 431755e092e3..81f0b4483806 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -29,6 +29,7 @@ import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
import static android.app.servertransaction.ActivityLifecycleItem.PRE_ON_CREATE;
import static android.content.ContentResolver.DEPRECATE_DATA_COLUMNS;
import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.window.ConfigurationHelper.diffPublicWithSizeBuckets;
import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded;
@@ -314,7 +315,7 @@ public final class ActivityThread extends ClientTransactionHandler
@UnsupportedAppUsage
private ContextImpl mSystemContext;
- private ContextImpl mSystemUiContext;
+ private final SparseArray<ContextImpl> mDisplaySystemUiContexts = new SparseArray<>();
@UnsupportedAppUsage
static volatile IPackageManager sPackageManager;
@@ -2611,22 +2612,26 @@ public final class ActivityThread extends ClientTransactionHandler
}
@Override
+ @NonNull
public ContextImpl getSystemUiContext() {
- synchronized (this) {
- if (mSystemUiContext == null) {
- mSystemUiContext = ContextImpl.createSystemUiContext(getSystemContext());
- }
- return mSystemUiContext;
- }
+ return getSystemUiContext(DEFAULT_DISPLAY);
}
/**
- * Create the context instance base on system resources & display information which used for UI.
+ * Gets the context instance base on system resources & display information which used for UI.
* @param displayId The ID of the display where the UI is shown.
* @see ContextImpl#createSystemUiContext(ContextImpl, int)
*/
- public ContextImpl createSystemUiContext(int displayId) {
- return ContextImpl.createSystemUiContext(getSystemUiContext(), displayId);
+ @NonNull
+ public ContextImpl getSystemUiContext(int displayId) {
+ synchronized (this) {
+ ContextImpl systemUiContext = mDisplaySystemUiContexts.get(displayId);
+ if (systemUiContext == null) {
+ systemUiContext = ContextImpl.createSystemUiContext(getSystemContext(), displayId);
+ mDisplaySystemUiContexts.put(displayId, systemUiContext);
+ }
+ return systemUiContext;
+ }
}
public void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
@@ -3745,7 +3750,7 @@ public final class ActivityThread extends ClientTransactionHandler
if (pkgName != null && !pkgName.isEmpty()
&& r.packageInfo.mPackageName.contains(pkgName)) {
for (int id : dm.getDisplayIds()) {
- if (id != Display.DEFAULT_DISPLAY) {
+ if (id != DEFAULT_DISPLAY) {
Display display =
dm.getCompatibleDisplay(id, appContext.getResources());
appContext = (ContextImpl) appContext.createDisplayContext(display);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index b5ed1717496e..ed496c61bddb 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2618,7 +2618,10 @@ class ContextImpl extends Context {
overrideConfig, display.getDisplayAdjustments().getCompatibilityInfo(),
mResources.getLoaders()));
context.mDisplay = display;
- context.mContextType = CONTEXT_TYPE_DISPLAY_CONTEXT;
+ // Inherit context type if the container is from System or System UI context to bypass
+ // UI context check.
+ context.mContextType = mContextType == CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI
+ ? CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI : CONTEXT_TYPE_DISPLAY_CONTEXT;
// Display contexts and any context derived from a display context should always override
// the display that would otherwise be inherited from mToken (or the global configuration if
// mToken is null).
@@ -2671,7 +2674,8 @@ class ContextImpl extends Context {
// Step 2. Create the base context of the window context, it will also create a Resources
// associated with the WindowTokenClient and set the token to the base context.
- final ContextImpl windowContextBase = createWindowContextBase(windowTokenClient, display);
+ final ContextImpl windowContextBase = createWindowContextBase(windowTokenClient,
+ display.getDisplayId());
// Step 3. Create a WindowContext instance and set it as the outer context of the base
// context to make the service obtained by #getSystemService(String) able to query
@@ -2696,9 +2700,7 @@ class ContextImpl extends Context {
if (display == null) {
throw new IllegalArgumentException("Display must not be null");
}
- final ContextImpl tokenContext = createWindowContextBase(token, display);
- tokenContext.setResources(createWindowContextResources(tokenContext));
- return tokenContext;
+ return createWindowContextBase(token, display.getDisplayId());
}
/**
@@ -2706,13 +2708,13 @@ class ContextImpl extends Context {
* window.
*
* @param token The token to associate with {@link Resources}
- * @param display The {@link Display} to associate with.
+ * @param displayId The ID of {@link Display} to associate with.
*
* @see #createWindowContext(Display, int, Bundle)
* @see #createTokenContext(IBinder, Display)
*/
@UiContext
- ContextImpl createWindowContextBase(@NonNull IBinder token, @NonNull Display display) {
+ ContextImpl createWindowContextBase(@NonNull IBinder token, int displayId) {
ContextImpl baseContext = new ContextImpl(this, mMainThread, mPackageInfo, mParams,
mAttributionSource.getAttributionTag(),
mAttributionSource.getNext(),
@@ -2726,8 +2728,8 @@ class ContextImpl extends Context {
baseContext.setResources(windowContextResources);
// Associate the display with window context resources so that configuration update from
// the server side will also apply to the display's metrics.
- baseContext.mDisplay = ResourcesManager.getInstance()
- .getAdjustedDisplay(display.getDisplayId(), windowContextResources);
+ baseContext.mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(displayId,
+ windowContextResources);
return baseContext;
}
@@ -2963,6 +2965,16 @@ class ContextImpl extends Context {
mContentCaptureOptions = options;
}
+ @Override
+ protected void finalize() throws Throwable {
+ // If token is a WindowTokenClient, the Context is usually associated with a
+ // WindowContainer. We should detach from WindowContainer when the Context is finalized.
+ if (mToken instanceof WindowTokenClient) {
+ ((WindowTokenClient) mToken).detachFromWindowContainerIfNeeded();
+ }
+ super.finalize();
+ }
+
@UnsupportedAppUsage
static ContextImpl createSystemContext(ActivityThread mainThread) {
LoadedApk packageInfo = new LoadedApk(mainThread);
@@ -2983,22 +2995,13 @@ class ContextImpl extends Context {
* @param displayId The ID of the display where the UI is shown.
*/
static ContextImpl createSystemUiContext(ContextImpl systemContext, int displayId) {
- final LoadedApk packageInfo = systemContext.mPackageInfo;
- ContextImpl context = new ContextImpl(null, systemContext.mMainThread, packageInfo,
- ContextParams.EMPTY, null, null, null, null, null, 0, null, null);
- context.setResources(createResources(null, packageInfo, null, displayId, null,
- packageInfo.getCompatibilityInfo(), null));
- context.updateDisplay(displayId);
+ final WindowTokenClient token = new WindowTokenClient();
+ ContextImpl context = systemContext.createWindowContextBase(token, displayId);
+ token.attachContext(context);
+ token.attachToDisplayContent(displayId);
context.mContextType = CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI;
- return context;
- }
- /**
- * The overloaded method of {@link #createSystemUiContext(ContextImpl, int)}.
- * Uses {@Code Display.DEFAULT_DISPLAY} as the target display.
- */
- static ContextImpl createSystemUiContext(ContextImpl systemContext) {
- return createSystemUiContext(systemContext, Display.DEFAULT_DISPLAY);
+ return context;
}
@UnsupportedAppUsage
@@ -3206,7 +3209,13 @@ class ContextImpl extends Context {
@Override
public IBinder getWindowContextToken() {
- return mContextType == CONTEXT_TYPE_WINDOW_CONTEXT ? mToken : null;
+ switch (mContextType) {
+ case CONTEXT_TYPE_WINDOW_CONTEXT:
+ case CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI:
+ return mToken;
+ default:
+ return null;
+ }
}
private void checkMode(int mode) {
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 601ec9a152ca..0210a94eafcc 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -341,7 +341,7 @@ interface IActivityManager {
@UnsupportedAppUsage
boolean switchUser(int userid);
@UnsupportedAppUsage
- void setStopBackgroundUsersOnSwitch(int value);
+ void setStopUserOnSwitch(int value);
boolean removeTask(int taskId);
@UnsupportedAppUsage
void registerProcessObserver(in IProcessObserver observer);
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/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 7c2b1b72fbf1..8be2b4873c67 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -97,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;
@@ -540,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.
@@ -557,8 +557,7 @@ public class AppWidgetHostView extends FrameLayout {
// inflate any requested LayoutParams.
mRemoteContext = getRemoteContextEnsuringCorrectCachedApkPath();
- int layoutId = rvToApply.getLayoutId();
- if (rvToApply.canRecycleView(mView)) {
+ if (!mColorMappingChanged && rvToApply.canRecycleView(mView)) {
try {
rvToApply.reapply(mContext, mView, mInteractionHandler, mCurrentSize,
mColorResources);
@@ -583,7 +582,6 @@ public class AppWidgetHostView extends FrameLayout {
}
}
- mLayoutId = layoutId;
mViewMode = VIEW_MODE_CONTENT;
}
@@ -591,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.
@@ -626,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 (remoteViews.canRecycleView(mView)) {
+ if (!mColorMappingChanged && remoteViews.canRecycleView(mView)) {
try {
mLastExecutionSignal = remoteViews.reapplyAsync(mContext,
mView,
@@ -666,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);
@@ -907,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();
}
@@ -937,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/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/view/IRecentsAnimationRunner.aidl b/core/java/android/view/IRecentsAnimationRunner.aidl
index aca17e448b82..c7fd38092ec7 100644
--- a/core/java/android/view/IRecentsAnimationRunner.aidl
+++ b/core/java/android/view/IRecentsAnimationRunner.aidl
@@ -63,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 9e41e4d2906c..ae32a481691a 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -866,6 +866,23 @@ interface IWindowManager
void attachWindowContextToWindowToken(IBinder clientToken, IBinder token);
/**
+ * Attaches a {@code clientToken} to associate with DisplayContent.
+ * <p>
+ * Note that this API should be invoked after calling
+ * {@link android.window.WindowTokenClient#attachContext(Context)}
+ * </p>
+ *
+ * @param clientToken {@link android.window.WindowContext#getWindowContextToken()
+ * the WindowContext's token}
+ * @param displayId The display associated with the window context
+ *
+ * @return the DisplayContent's {@link android.app.res.Configuration} if the Context is
+ * attached to the DisplayContent successfully. {@code null}, otherwise.
+ * @throws android.view.WindowManager.InvalidDisplayException if the display ID is invalid
+ */
+ Configuration attachToDisplayContent(IBinder clientToken, int displayId);
+
+ /**
* Detaches {@link android.window.WindowContext} from the window manager node it's currently
* attached to. It is no-op if the WindowContext is not attached to a window manager node.
*
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/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 65d0e497a5b1..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
@@ -3351,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) {
@@ -4049,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);
@@ -4061,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) {
@@ -10507,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;
}
@@ -10548,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/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 57b7d618917d..2357d13c8d41 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -5746,9 +5746,11 @@ public class RemoteViews implements Parcelable, Filter {
// 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 (!rvToApply.canRecycleView(v)) {
- throw new RuntimeException("Attempting to re-apply RemoteViews to a view that"
- + " that does not share the same root layout id.");
+ if (hasMultipleLayouts()) {
+ 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.");
+ }
}
rvToApply.performApply(v, (ViewGroup) v.getParent(), handler, colorResources);
@@ -5792,9 +5794,11 @@ public class RemoteViews implements Parcelable, Filter {
// 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 (!rvToApply.canRecycleView(v)) {
- throw new RuntimeException("Attempting to re-apply RemoteViews to a view that"
- + " that does not share the same root layout id.");
+ if (hasMultipleLayouts()) {
+ 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 new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(),
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/android/window/WindowContextController.java b/core/java/android/window/WindowContextController.java
index 5aa623388574..17b675f93f86 100644
--- a/core/java/android/window/WindowContextController.java
+++ b/core/java/android/window/WindowContextController.java
@@ -19,13 +19,10 @@ package android.window;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
-import android.os.RemoteException;
import android.view.IWindowManager;
import android.view.WindowManager.LayoutParams.WindowType;
-import android.view.WindowManagerGlobal;
import com.android.internal.annotations.VisibleForTesting;
@@ -38,7 +35,6 @@ import com.android.internal.annotations.VisibleForTesting;
* @hide
*/
public class WindowContextController {
- private final IWindowManager mWms;
/**
* {@code true} to indicate that the {@code mToken} is associated with a
* {@link com.android.server.wm.DisplayArea}. Note that {@code mToken} is able to attach a
@@ -56,14 +52,7 @@ public class WindowContextController {
* {@link Context#getWindowContextToken()}.
*/
public WindowContextController(@NonNull WindowTokenClient token) {
- this(token, WindowManagerGlobal.getWindowManagerService());
- }
-
- /** Used for test only. DO NOT USE it in production code. */
- @VisibleForTesting
- public WindowContextController(@NonNull WindowTokenClient token, IWindowManager mockWms) {
mToken = token;
- mWms = mockWms;
}
/**
@@ -80,19 +69,7 @@ public class WindowContextController {
throw new IllegalStateException("A Window Context can be only attached to "
+ "a DisplayArea once.");
}
- try {
- final Configuration configuration = mWms.attachWindowContextToDisplayArea(mToken, type,
- displayId, options);
- if (configuration != null) {
- mAttachedToDisplayArea = true;
- // Send the DisplayArea's configuration to WindowContext directly instead of
- // waiting for dispatching from WMS.
- mToken.onConfigurationChanged(configuration, displayId,
- false /* shouldReportConfigChange */);
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ mAttachedToDisplayArea = mToken.attachToDisplayArea(type, displayId, options);
}
/**
@@ -120,22 +97,14 @@ public class WindowContextController {
throw new IllegalStateException("The Window Context should have been attached"
+ " to a DisplayArea.");
}
- try {
- mWms.attachWindowContextToWindowToken(mToken, windowToken);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ mToken.attachToWindowToken(windowToken);
}
/** Detaches the window context from the node it's currently associated with. */
public void detachIfNeeded() {
if (mAttachedToDisplayArea) {
- try {
- mWms.detachWindowContextFromWindowContainer(mToken);
- mAttachedToDisplayArea = false;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ mToken.detachFromWindowContainerIfNeeded();
+ mAttachedToDisplayArea = false;
}
}
}
diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java
index f3e3859b4256..b331a9e81e27 100644
--- a/core/java/android/window/WindowTokenClient.java
+++ b/core/java/android/window/WindowTokenClient.java
@@ -21,6 +21,7 @@ import static android.window.ConfigurationHelper.isDifferentDisplay;
import static android.window.ConfigurationHelper.shouldUpdateResources;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityThread;
import android.app.IWindowToken;
import android.app.ResourcesManager;
@@ -31,7 +32,11 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.IBinder;
+import android.os.RemoteException;
import android.util.Log;
+import android.view.IWindowManager;
+import android.view.WindowManager.LayoutParams.WindowType;
+import android.view.WindowManagerGlobal;
import com.android.internal.annotations.VisibleForTesting;
@@ -59,10 +64,14 @@ public class WindowTokenClient extends IWindowToken.Stub {
private final ResourcesManager mResourcesManager = ResourcesManager.getInstance();
+ private IWindowManager mWms;
+
private final Configuration mConfiguration = new Configuration();
private boolean mShouldDumpConfigForIme;
+ private boolean mAttachToWindowContainer;
+
/**
* Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient}
* can only attach one {@link Context}.
@@ -84,6 +93,88 @@ public class WindowTokenClient extends IWindowToken.Stub {
}
/**
+ * Attaches this {@link WindowTokenClient} to a {@link com.android.server.wm.DisplayArea}.
+ *
+ * @param type The window type of the {@link WindowContext}
+ * @param displayId The {@link Context#getDisplayId() ID of display} to associate with
+ * @param options The window context launched option
+ * @return {@code true} if attaching successfully.
+ */
+ public boolean attachToDisplayArea(@WindowType int type, int displayId,
+ @Nullable Bundle options) {
+ try {
+ final Configuration configuration = getWindowManagerService()
+ .attachWindowContextToDisplayArea(this, type, displayId, options);
+ if (configuration == null) {
+ return false;
+ }
+ onConfigurationChanged(configuration, displayId, false /* shouldReportConfigChange */);
+ mAttachToWindowContainer = true;
+ return true;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Attaches this {@link WindowTokenClient} to a {@code DisplayContent}.
+ *
+ * @param displayId The {@link Context#getDisplayId() ID of display} to associate with
+ * @return {@code true} if attaching successfully.
+ */
+ public boolean attachToDisplayContent(int displayId) {
+ final IWindowManager wms = getWindowManagerService();
+ // #createSystemUiContext may call this method before WindowManagerService is initialized.
+ if (wms == null) {
+ return false;
+ }
+ try {
+ final Configuration configuration = wms.attachToDisplayContent(this, displayId);
+ if (configuration == null) {
+ return false;
+ }
+ onConfigurationChanged(configuration, displayId, false /* shouldReportConfigChange */);
+ mAttachToWindowContainer = true;
+ return true;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Attaches this {@link WindowTokenClient} to a {@code windowToken}.
+ *
+ * @param windowToken the window token to associated with
+ */
+ public void attachToWindowToken(IBinder windowToken) {
+ try {
+ getWindowManagerService().attachWindowContextToWindowToken(this, windowToken);
+ mAttachToWindowContainer = true;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** Detaches this {@link WindowTokenClient} from associated WindowContainer if there's one. */
+ public void detachFromWindowContainerIfNeeded() {
+ if (!mAttachToWindowContainer) {
+ return;
+ }
+ try {
+ getWindowManagerService().detachWindowContextFromWindowContainer(this);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private IWindowManager getWindowManagerService() {
+ if (mWms == null) {
+ mWms = WindowManagerGlobal.getWindowManagerService();
+ }
+ return mWms;
+ }
+
+ /**
* Called when {@link Configuration} updates from the server side receive.
*
* @param newConfig the updated {@link Configuration}
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/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/android/window/WindowContextControllerTest.java b/core/tests/coretests/src/android/window/WindowContextControllerTest.java
index a6e351d9cee7..52cb9f318dd0 100644
--- a/core/tests/coretests/src/android/window/WindowContextControllerTest.java
+++ b/core/tests/coretests/src/android/window/WindowContextControllerTest.java
@@ -24,16 +24,13 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
-import android.content.res.Configuration;
import android.os.Binder;
import android.platform.test.annotations.Presubmit;
-import android.view.IWindowManager;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -59,17 +56,14 @@ import org.mockito.MockitoAnnotations;
public class WindowContextControllerTest {
private WindowContextController mController;
@Mock
- private IWindowManager mMockWms;
- @Mock
private WindowTokenClient mMockToken;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mController = new WindowContextController(mMockToken, mMockWms);
+ mController = new WindowContextController(mMockToken);
doNothing().when(mMockToken).onConfigurationChanged(any(), anyInt(), anyBoolean());
- doReturn(new Configuration()).when(mMockWms).attachWindowContextToDisplayArea(any(),
- anyInt(), anyInt(), any());
+ doReturn(true).when(mMockToken).attachToDisplayArea(anyInt(), anyInt(), any());
}
@Test(expected = IllegalStateException.class)
@@ -81,10 +75,10 @@ public class WindowContextControllerTest {
}
@Test
- public void testDetachIfNeeded_NotAttachedYet_DoNothing() throws Exception {
+ public void testDetachIfNeeded_NotAttachedYet_DoNothing() {
mController.detachIfNeeded();
- verify(mMockWms, never()).detachWindowContextFromWindowContainer(any());
+ verify(mMockToken, never()).detachFromWindowContainerIfNeeded();
}
@Test
@@ -93,8 +87,6 @@ public class WindowContextControllerTest {
null /* options */);
assertThat(mController.mAttachedToDisplayArea).isTrue();
- verify(mMockToken).onConfigurationChanged(any(), eq(DEFAULT_DISPLAY),
- eq(false) /* shouldReportConfigChange */);
mController.detachIfNeeded();
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/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 20515e71a91b..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,15 +517,19 @@ 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 = container.getPrimaryContainer().toActivityStack();
ActivityStack secondaryContainer = container.getSecondaryContainer().toActivityStack();
@@ -639,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 80d9c2c1719c..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;
/**
@@ -227,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);
}
@@ -234,6 +238,9 @@ class TaskFragmentContainer {
// Finish associated activities
for (Activity activity : mActivitiesToFinishOnExit) {
+ if (controller.shouldRetainAssociatedActivity(this, activity)) {
+ continue;
+ }
activity.finish();
}
mActivitiesToFinishOnExit.clear();
@@ -267,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/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
index 830d13dd6dc5..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/res/layout/pip_menu.xml b/libs/WindowManager/Shell/res/layout/pip_menu.xml
index 7dc2f31e9871..9fe024748610 100644
--- a/libs/WindowManager/Shell/res/layout/pip_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/pip_menu.xml
@@ -65,28 +65,25 @@
<LinearLayout
android:id="@+id/top_end_container"
android:layout_gravity="top|end"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
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/enter_split"
+ android:id="@+id/dismiss"
android:layout_width="@dimen/pip_action_size"
android:layout_height="@dimen/pip_action_size"
- android:layout_gravity="top|start"
+ android:contentDescription="@string/pip_phone_close"
android:gravity="center"
- android:contentDescription="@string/pip_phone_enter_split"
- android:src="@drawable/pip_expand"
+ android:src="@drawable/pip_ic_close_white"
android:background="?android:selectableItemBackgroundBorderless" />
</LinearLayout>
@@ -100,14 +97,4 @@
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/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index c88fc16e218e..764854af3b3f 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -24,9 +24,6 @@
<!-- 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>
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 f7af4e1dd1d1..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
@@ -1036,10 +1036,9 @@ public class BubbleController {
// 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.getRanking().isSuspended()) {
+ } else if (entry != null && mTmpRanking.isBubble() && !isActiveBubble) {
entry.setFlagBubble(true);
- onEntryUpdated(entry, true /* shouldBubbleUp */);
+ onEntryUpdated(entry, shouldBubbleUp && !entry.getRanking().isSuspended());
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
index 711a0ac76702..b80dcd063589 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
@@ -43,7 +43,6 @@ 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,14 +160,13 @@ 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, newSplitScreenOptional,
- displayController, pipUiEventLogger, shellTaskOrganizer, mainExecutor);
+ pipTransitionController, splitScreenOptional, displayController, pipUiEventLogger,
+ shellTaskOrganizer, mainExecutor);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index ec701470354c..944dfed57cb6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -55,7 +55,6 @@ 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;
@@ -216,15 +215,14 @@ 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, newSplitScreenOptional,
- displayController, pipUiEventLogger, shellTaskOrganizer, mainExecutor);
+ pipTransitionController, splitScreenOptional, displayController, pipUiEventLogger,
+ shellTaskOrganizer, mainExecutor);
}
@WMSingleton
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 6cc5f09827af..b6e5804a64dd 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,7 +77,6 @@ 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;
@@ -127,8 +126,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private final int mExitAnimationDuration;
private final int mCrossFadeAnimationDuration;
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
- private final Optional<LegacySplitScreenController> mLegacySplitScreenOptional;
- private final Optional<SplitScreenController> mSplitScreenOptional;
+ private final Optional<LegacySplitScreenController> mSplitScreenOptional;
protected final ShellTaskOrganizer mTaskOrganizer;
protected final ShellExecutor mMainExecutor;
@@ -254,8 +252,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
@NonNull PipAnimationController pipAnimationController,
@NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
@NonNull PipTransitionController pipTransitionController,
- Optional<LegacySplitScreenController> legacySplitScreenOptional,
- Optional<SplitScreenController> splitScreenOptional,
+ Optional<LegacySplitScreenController> splitScreenOptional,
@NonNull DisplayController displayController,
@NonNull PipUiEventLogger pipUiEventLogger,
@NonNull ShellTaskOrganizer shellTaskOrganizer,
@@ -277,7 +274,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mPipAnimationController = pipAnimationController;
mPipUiEventLoggerLogger = pipUiEventLogger;
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
- mLegacySplitScreenOptional = legacySplitScreenOptional;
mSplitScreenOptional = splitScreenOptional;
mTaskOrganizer = shellTaskOrganizer;
mMainExecutor = mainExecutor;
@@ -377,11 +373,8 @@ 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, boolean requestEnterSplit) {
+ public void exitPip(int animationDurationMs) {
if (!mPipTransitionState.isInPip()
|| mPipTransitionState.getTransitionState() == PipTransitionState.EXITING_PIP
|| mToken == null) {
@@ -394,7 +387,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, requestEnterSplit)
+ final int direction = syncWithSplitScreenBounds(destinationBounds)
? TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
: TRANSITION_DIRECTION_LEAVE_PIP;
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
@@ -403,7 +396,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 && !requestEnterSplit
+ direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
: WINDOWING_MODE_FULLSCREEN);
wct.setBounds(mToken, destinationBounds);
@@ -442,7 +435,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);
- mLegacySplitScreenOptional.ifPresent(splitScreen -> {
+ mSplitScreenOptional.ifPresent(splitScreen -> {
if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
wct.reparent(mToken, splitScreen.getSecondaryRoot(), true /* onTop */);
}
@@ -1172,7 +1165,6 @@ 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();
@@ -1218,10 +1210,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
null /* callback */, false /* withStartDelay */);
});
} else {
- applyFinishBoundsResize(wct, direction, isPipTopLeft);
+ applyFinishBoundsResize(wct, direction);
}
} else {
- applyFinishBoundsResize(wct, direction, isPipTopLeft);
+ applyFinishBoundsResize(wct, direction);
}
finishResizeForMenu(destinationBounds);
@@ -1249,11 +1241,7 @@ 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.
- if (direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN) {
- taskBounds = destinationBounds;
- } else {
- taskBounds = null;
- }
+ taskBounds = null;
applyWindowingModeChangeOnExit(wct, direction);
} else {
// Just a resize in PIP
@@ -1273,20 +1261,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
* applying it.
*/
public void applyFinishBoundsResize(@NonNull WindowContainerTransaction 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());
+ @PipAnimationController.TransitionDirection int direction) {
+ mTaskOrganizer.applyTransaction(wct);
}
/**
@@ -1371,27 +1347,18 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
/**
- * Sync with {@link LegacySplitScreenController} or {@link SplitScreenController} on destination
- * bounds if PiP is going to split screen.
+ * Sync with {@link LegacySplitScreenController} 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, 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()) {
+ private boolean syncWithSplitScreenBounds(Rect destinationBoundsOut) {
+ if (!mSplitScreenOptional.isPresent()) {
return false;
}
- LegacySplitScreenController legacySplitScreen = mLegacySplitScreenOptional.get();
+ LegacySplitScreenController legacySplitScreen = mSplitScreenOptional.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/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index 5687f4d62444..ae8c1b6f8c1a 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,11 +95,6 @@ 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();
@@ -463,10 +458,6 @@ 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 69ae45d12795..47a8c67a22e6 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(false /* skipAnimation */);
+ mMotionHelper.expandLeavePip();
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 10bc7e250cc8..8c431f08a385 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
@@ -482,8 +482,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
false /* fromShelfAdjustment */,
wct /* windowContainerTransaction */);
if (wct != null) {
- mPipTaskOrganizer.applyFinishBoundsResize(wct, TRANSITION_DIRECTION_SAME,
- false /* wasPipTopLeft */);
+ mPipTaskOrganizer.applyFinishBoundsResize(wct, TRANSITION_DIRECTION_SAME);
}
};
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 06446573840c..3eeba6eb5366 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,6 +18,8 @@ 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;
@@ -32,7 +34,6 @@ public class PipMenuIconsAlgorithm {
protected ViewGroup mViewRoot;
protected ViewGroup mTopEndContainer;
protected View mDragHandle;
- protected View mEnterSplitButton;
protected View mSettingsButton;
protected View mDismissButton;
@@ -43,13 +44,14 @@ public class PipMenuIconsAlgorithm {
* Bind the necessary views.
*/
public void bindViews(ViewGroup viewRoot, ViewGroup topEndContainer, View dragHandle,
- View enterSplitButton, View settingsButton, View dismissButton) {
+ View settingsButton, View dismissButton) {
mViewRoot = viewRoot;
mTopEndContainer = topEndContainer;
mDragHandle = dragHandle;
- mEnterSplitButton = enterSplitButton;
mSettingsButton = settingsButton;
mDismissButton = dismissButton;
+
+ bindInitialViewState();
}
/**
@@ -70,4 +72,22 @@ 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 7bbebe5bf287..8ef2b6b12030 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_ENTER_SPLIT = false;
+ private static final boolean ENABLE_RESIZE_HANDLE = false;
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 mEnterSplitButton;
+ protected View mResizeHandle;
protected View mTopEndContainer;
protected PipMenuIconsAlgorithm mPipMenuIconsAlgorithm;
@@ -177,23 +177,14 @@ public class PipMenuView extends FrameLayout {
}
});
- mEnterSplitButton = findViewById(R.id.enter_split);
- mEnterSplitButton.setAlpha(0);
- mEnterSplitButton.setOnClickListener(v -> {
- if (mMenuContainer.getAlpha() != 0) {
- enterSplit();
- }
- });
-
- findViewById(R.id.resize_handle).setAlpha(0);
-
+ mResizeHandle = findViewById(R.id.resize_handle);
+ mResizeHandle.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,
- findViewById(R.id.resize_handle), mEnterSplitButton, mSettingsButton,
- mDismissButton);
+ mResizeHandle, mSettingsButton, mDismissButton);
mDismissFadeOutDurationMs = context.getResources()
.getInteger(R.integer.config_pipExitAnimationDuration);
@@ -277,13 +268,14 @@ public class PipMenuView extends FrameLayout {
mSettingsButton.getAlpha(), 1f);
ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA,
mDismissButton.getAlpha(), 1f);
- ObjectAnimator enterSplitAnim = ObjectAnimator.ofFloat(mEnterSplitButton, View.ALPHA,
- mEnterSplitButton.getAlpha(), ENABLE_ENTER_SPLIT ? 1f : 0f);
+ ObjectAnimator resizeAnim = ObjectAnimator.ofFloat(mResizeHandle, View.ALPHA,
+ mResizeHandle.getAlpha(),
+ ENABLE_RESIZE_HANDLE && showResizeHandle ? 1f : 0f);
if (menuState == MENU_STATE_FULL) {
mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim,
- enterSplitAnim);
+ resizeAnim);
} else {
- mMenuContainerAnimator.playTogether(enterSplitAnim);
+ mMenuContainerAnimator.playTogether(resizeAnim);
}
mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
mMenuContainerAnimator.setDuration(ANIMATION_HIDE_DURATION_MS);
@@ -336,7 +328,7 @@ public class PipMenuView extends FrameLayout {
mMenuContainer.setAlpha(0f);
mSettingsButton.setAlpha(0f);
mDismissButton.setAlpha(0f);
- mEnterSplitButton.setAlpha(0f);
+ mResizeHandle.setAlpha(0f);
}
void pokeMenu() {
@@ -376,10 +368,9 @@ public class PipMenuView extends FrameLayout {
mSettingsButton.getAlpha(), 0f);
ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA,
mDismissButton.getAlpha(), 0f);
- ObjectAnimator enterSplitAnim = ObjectAnimator.ofFloat(mEnterSplitButton, View.ALPHA,
- mEnterSplitButton.getAlpha(), 0f);
- mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim,
- enterSplitAnim);
+ ObjectAnimator resizeAnim = ObjectAnimator.ofFloat(mResizeHandle, View.ALPHA,
+ mResizeHandle.getAlpha(), 0f);
+ mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim, resizeAnim);
mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_OUT);
mMenuContainerAnimator.setDuration(getFadeOutDuration(animationType));
mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
@@ -531,14 +522,6 @@ 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 c634b7f220b0..dbd09fd7b265 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
@@ -338,29 +338,22 @@ 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(boolean skipAnimation) {
- expandLeavePip(skipAnimation, false /* enterSplit */);
- }
-
- /**
- * Resizes the pinned task to split-screen mode.
- */
- void expandIntoSplit() {
- expandLeavePip(false, true /* enterSplit */);
+ void expandLeavePip() {
+ expandLeavePip(false /* skipAnimation */);
}
/**
* Resizes the pinned stack back to unknown windowing mode, which could be freeform or
* fullscreen depending on the display area's windowing mode.
*/
- private void expandLeavePip(boolean skipAnimation, boolean enterSplit) {
+ void expandLeavePip(boolean skipAnimation) {
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, enterSplit);
+ mPipTaskOrganizer.exitPip(skipAnimation ? 0 : LEAVE_PIP_DURATION);
}
/**
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 570fd5eab9f6..9f2f6a575aca 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,12 +139,7 @@ public class PipTouchHandler {
@Override
public void onPipExpand() {
- mMotionHelper.expandLeavePip(false /* skipAnimation */);
- }
-
- @Override
- public void onEnterSplit() {
- mMotionHelper.expandIntoSplit();
+ mMotionHelper.expandLeavePip();
}
@Override
@@ -904,7 +899,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(false /* skipAnimation */);
+ mMotionHelper.expandLeavePip();
}
} 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 00083d986dbe..a2e9b64046fd 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, false /* requestEnterSplit */);
+ mPipTaskOrganizer.exitPip(mResizeAnimationDuration);
onPipDisappeared();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index 836a6f610bbd..7cf3bafe499a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -41,10 +41,13 @@ 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.
@@ -62,6 +65,13 @@ public class RecentTasksController implements TaskStackListenerCallback,
// 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
@@ -97,15 +107,20 @@ public class RecentTasksController implements TaskStackListenerCallback,
/**
* 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) {
+ 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);
}
/**
@@ -116,6 +131,8 @@ public class RecentTasksController implements TaskStackListenerCallback,
if (pairedTaskId != INVALID_TASK_ID) {
mSplitTasks.delete(taskId);
mSplitTasks.delete(pairedTaskId);
+ mTaskSplitBoundsMap.remove(taskId);
+ mTaskSplitBoundsMap.remove(pairedTaskId);
}
}
@@ -203,7 +220,8 @@ public class RecentTasksController implements TaskStackListenerCallback,
if (pairedTaskId != INVALID_TASK_ID) {
final ActivityManager.RecentTaskInfo pairedTaskInfo = rawMapping.get(pairedTaskId);
rawMapping.remove(pairedTaskId);
- recentTasks.add(new GroupedRecentTaskInfo(taskInfo, pairedTaskInfo));
+ recentTasks.add(new GroupedRecentTaskInfo(taskInfo, pairedTaskInfo,
+ mTaskSplitBoundsMap.get(pairedTaskId)));
} else {
recentTasks.add(new GroupedRecentTaskInfo(taskInfo));
}
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 7457be2d0871..04058ed6388c 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
@@ -202,25 +202,11 @@ 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 moveToSideStage(ActivityManager.RunningTaskInfo task,
- @SplitPosition int sideStagePosition, WindowContainerTransaction wct) {
- return mStageCoordinator.moveToSideStage(task, sideStagePosition, wct);
- }
-
public boolean removeFromSideStage(int taskId) {
return mStageCoordinator.removeFromSideStage(taskId);
}
@@ -238,11 +224,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT);
}
- 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);
}
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 3c35e6a69bf5..3589f7c14cd3 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
@@ -96,6 +96,7 @@ 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;
@@ -280,11 +281,6 @@ 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);
mSideStage.evictAllChildren(evictWct);
@@ -696,11 +692,25 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
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);
+ recentTasks.addSplitPair(mainStageTopTaskId, sideStageTopTaskId, splitBounds);
}
});
}
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
index 0331ba19defe..603d05d78fc0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java
@@ -30,25 +30,34 @@ import androidx.annotation.Nullable;
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);
+ this(task1, null, null);
}
public GroupedRecentTaskInfo(@NonNull ActivityManager.RecentTaskInfo task1,
- @Nullable ActivityManager.RecentTaskInfo task2) {
+ @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() {
- return "Task1: " + getTaskInfo(mTaskInfo1) + ", Task2: " + getTaskInfo(mTaskInfo2);
+ String taskString = "Task1: " + getTaskInfo(mTaskInfo1)
+ + ", Task2: " + getTaskInfo(mTaskInfo2);
+ if (mStagedSplitBounds != null) {
+ taskString += ", SplitBounds: " + mStagedSplitBounds.toString();
+ }
+ return taskString;
}
private String getTaskInfo(ActivityManager.RecentTaskInfo taskInfo) {
@@ -67,6 +76,7 @@ public class GroupedRecentTaskInfo implements Parcelable {
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeTypedObject(mTaskInfo1, flags);
parcel.writeTypedObject(mTaskInfo2, flags);
+ parcel.writeTypedObject(mStagedSplitBounds, flags);
}
@Override
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/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 0172cf324eea..0270093da938 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,7 +50,6 @@ 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;
@@ -76,8 +75,7 @@ public class PipTaskOrganizerTest extends ShellTestCase {
@Mock private PipTransitionController mMockPipTransitionController;
@Mock private PipSurfaceTransactionHelper mMockPipSurfaceTransactionHelper;
@Mock private PipUiEventLogger mMockPipUiEventLogger;
- @Mock private Optional<LegacySplitScreenController> mMockOptionalLegacySplitScreen;
- @Mock private Optional<SplitScreenController> mMockOptionalSplitScreen;
+ @Mock private Optional<LegacySplitScreenController> mMockOptionalSplitScreen;
@Mock private ShellTaskOrganizer mMockShellTaskOrganizer;
private TestShellExecutor mMainExecutor;
private PipBoundsState mPipBoundsState;
@@ -101,9 +99,8 @@ public class PipTaskOrganizerTest extends ShellTestCase {
mMockSyncTransactionQueue, mPipTransitionState, mPipBoundsState,
mPipBoundsAlgorithm, mMockPhonePipMenuController,
mMockPipAnimationController, mMockPipSurfaceTransactionHelper,
- mMockPipTransitionController, mMockOptionalLegacySplitScreen,
- mMockOptionalSplitScreen, mMockDisplayController, mMockPipUiEventLogger,
- mMockShellTaskOrganizer, mMainExecutor));
+ mMockPipTransitionController, mMockOptionalSplitScreen, mMockDisplayController,
+ mMockPipUiEventLogger, mMockShellTaskOrganizer, mMainExecutor));
mMainExecutor.flushAll();
preparePipTaskOrg();
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index a1e12319ac70..19a5417aace6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -20,6 +20,8 @@ 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;
@@ -31,10 +33,9 @@ import static org.mockito.Mockito.verify;
import static java.lang.Integer.MAX_VALUE;
import android.app.ActivityManager;
-import android.app.WindowConfiguration;
import android.content.Context;
+import android.graphics.Rect;
import android.view.SurfaceControl;
-import android.window.TaskAppearedInfo;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -45,6 +46,7 @@ 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;
@@ -106,8 +108,11 @@ public class RecentTasksControllerTest extends ShellTestCase {
setRawList(t1, t2, t3, t4, t5, t6);
// Mark a couple pairs [t2, t4], [t3, t5]
- mRecentTasksController.addSplitPair(t2.taskId, t4.taskId);
- mRecentTasksController.addSplitPair(t3.taskId, t5.taskId);
+ 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);
@@ -126,7 +131,8 @@ public class RecentTasksControllerTest extends ShellTestCase {
setRawList(t1, t2, t3);
// Add a pair
- mRecentTasksController.addSplitPair(t2.taskId, t3.taskId);
+ 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
@@ -201,10 +207,23 @@ public class RecentTasksControllerTest extends ShellTestCase {
int[] flattenedTaskIds = new int[recentTasks.size() * 2];
for (int i = 0; i < recentTasks.size(); i++) {
GroupedRecentTaskInfo pair = recentTasks.get(i);
- flattenedTaskIds[2 * i] = pair.mTaskInfo1.taskId;
+ 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),
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/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/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index edbfd2a8f03e..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;
}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index 5df8e3c83a7a..2a72c501d7d0 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -258,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();
@@ -337,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/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/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 eae6f27db738..bca5071380de 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -50,17 +50,6 @@ java_library {
srcs: ["src/com/android/systemui/EventLogTags.logtags"],
}
-java_library {
- name: "SystemUI-flags",
- srcs: [
- "src/com/android/systemui/flags/Flags.java",
- ],
- libs: [
- "SystemUI-flag-types",
- ],
- static_kotlin_stdlib: false,
-}
-
filegroup {
name: "ReleaseJavaFiles",
srcs: [
@@ -126,7 +115,6 @@ android_library {
"iconloader_base",
"SystemUI-tags",
"SystemUI-proto",
- "SystemUI-flags",
"monet",
"dagger2",
"jsr330",
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 58e3d398553c..49a01df96530 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"
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 865f96be1775..faa7554525c5 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -16,11 +16,16 @@
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
@@ -32,6 +37,7 @@ 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"
@@ -52,7 +58,8 @@ class DialogLaunchAnimator(
private val currentAnimations = hashSetOf<DialogLaunchAnimation>()
/**
- * 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
@@ -60,7 +67,12 @@ 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 " +
@@ -78,7 +90,8 @@ class DialogLaunchAnimator(
val launchAnimation = DialogLaunchAnimation(
context, launchAnimator, hostDialogProvider, view,
- onDialogDismissed = { currentAnimations.remove(it) }, originalDialog = dialog)
+ onDialogDismissed = { currentAnimations.remove(it) }, originalDialog = dialog,
+ animateBackgroundBoundsChange)
val hostDialog = launchAnimation.hostDialog
currentAnimations.add(launchAnimation)
@@ -208,7 +221,10 @@ private class DialogLaunchAnimation(
private val onDialogDismissed: (DialogLaunchAnimation) -> 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
@@ -221,10 +237,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
+ private val dialogContentParent = FrameLayout(context)
/**
* The background color of [originalDialogView], taking into consideration the [originalDialog]
@@ -246,6 +263,11 @@ private class DialogLaunchAnimation(
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.
@@ -374,9 +396,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
@@ -394,29 +413,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,
@@ -428,7 +464,7 @@ private class DialogLaunchAnimation(
oldRight: Int,
oldBottom: Int
) {
- dialogView.removeOnLayoutChangeListener(this)
+ dialogContentParent.removeOnLayoutChangeListener(this)
isOriginalDialogViewLaidOut = true
maybeStartLaunchAnimation()
@@ -479,6 +515,13 @@ private class DialogLaunchAnimation(
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)
+ }
}
)
}
@@ -548,7 +591,11 @@ private class DialogLaunchAnimation(
}
touchSurface.visibility = View.VISIBLE
- originalDialogView!!.visibility = View.INVISIBLE
+ 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
@@ -578,12 +625,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
@@ -662,4 +707,81 @@ private class DialogLaunchAnimation(
return (touchSurface.parent as? View)?.isShown ?: true
}
+
+ /** 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()
+ }
+ }
}
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/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/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/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/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/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 986f82f98565..6b26d0744c98 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -241,6 +241,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] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 3f855c762273..4d2986f40a33 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -952,6 +952,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">
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/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index 25db478e57b7..d172006d986d 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -45,9 +45,6 @@ android_library {
":wm_shell-aidls",
":wm_shell_util-sources",
],
- libs: [
- "SystemUI-flags",
- ],
static_libs: [
"PluginCoreLib",
"androidx.dynamicanimation_dynamicanimation",
@@ -62,6 +59,7 @@ java_library {
srcs: [
"src/com/android/systemui/flags/Flag.kt",
],
+ include_srcs: true,
static_kotlin_stdlib: false,
java_version: "1.8",
min_sdk_version: "current",
@@ -78,7 +76,6 @@ java_library {
],
static_libs: [
"SystemUI-flag-types",
- "SystemUI-flags",
],
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
index 68834bc2aa23..9574101b466c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
@@ -16,37 +16,168 @@
package com.android.systemui.flags
-interface Flag<T> {
+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
-) : Flag<Boolean>
+ 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 = ""
-) : Flag<String>
+ 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
-) : Flag<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
-) : Flag<Long>
+ 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
-) : Flag<Float>
+ 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
-) : Flag<Double> \ No newline at end of file
+ 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
index cbb942bc3015..1dc555e300b4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt
@@ -16,10 +16,13 @@
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
@@ -34,10 +37,12 @@ class FlagManager constructor(
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"
}
@@ -46,14 +51,26 @@ class FlagManager constructor(
private val settingsObserver: ContentObserver = SettingsObserver()
fun getFlagsFuture(): ListenableFuture<Collection<Flag<*>>> {
- val knownFlagMap = Flags.collectFlags()
- // Possible todo in the future: query systemui async to actually get the known flag ids.
- return CallbackToFutureAdapter.getFuture(
- CallbackToFutureAdapter.Resolver {
- completer: CallbackToFutureAdapter.Completer<Collection<Flag<*>>> ->
- completer.set(knownFlagMap.values as Collection<Flag<*>>)
- "Retrieving Flags"
- })
+ 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) {
@@ -149,4 +166,7 @@ class FlagManager constructor(
}
}
-class InvalidFlagStorageException : Exception("Data found but is invalid") \ No newline at end of file
+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
index ee6dea5364f4..91a391272be7 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/flags/FlagReader.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/flags/FlagReader.kt
@@ -20,6 +20,11 @@ package com.android.systemui.flags
*/
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
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/GroupTask.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/GroupTask.java
deleted file mode 100644
index 323b20e41a5c..000000000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/GroupTask.java
+++ /dev/null
@@ -1,45 +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.shared.recents.model;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-/**
- * A group task in the recent tasks list.
- * TODO: Move this into Launcher
- */
-public class GroupTask {
- public @NonNull Task task1;
- public @Nullable Task task2;
-
- public GroupTask(@NonNull Task t1, @Nullable Task t2) {
- task1 = t1;
- task2 = t2;
- }
-
- public GroupTask(@NonNull GroupTask group) {
- task1 = new Task(group.task1);
- task2 = group.task2 != null
- ? new Task(group.task2)
- : null;
- }
-
- public boolean containsTask(int taskId) {
- return task1.key.id == taskId || (task2 != null && task2.key.id == taskId);
- }
-}
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 b95123d2fa41..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
@@ -195,8 +195,13 @@ public class ActivityManagerWrapper {
}
@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/RecentsAnimationListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
index a74de2e0c085..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
@@ -39,5 +39,5 @@ public interface RecentsAnimationListener {
* 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/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index 99b6aed497cc..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
@@ -53,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;
/**
@@ -127,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);
@@ -138,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;
@@ -150,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());
@@ -198,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.");
@@ -217,7 +219,7 @@ public class RemoteTransitionCompat implements Parcelable {
mWrapped = wrapped;
mInfo = info;
mFinishCB = finishCB;
- mPausingTask = pausingTask;
+ mPausingTasks = pausingTasks;
mPipTask = pipTask;
mLeashMap = leashMap;
mTransition = transition;
@@ -226,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;
}
@@ -292,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) {
@@ -339,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 9311966f82f2..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,22 +16,26 @@
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 static com.android.systemui.flags.FlagManager.FLAGS_PERMISSION;
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;
@@ -61,30 +65,52 @@ public class FeatureFlagManager implements FlagReader, FlagWriter, Dumpable {
private final FlagManager mFlagManager;
private final SecureSettings mSecureSettings;
+ private final Resources mResources;
private final Map<Integer, Boolean> mBooleanFlagCache = new HashMap<>();
@Inject
- public FeatureFlagManager(FlagManager flagManager,
- SecureSettings secureSettings, Context context,
+ public FeatureFlagManager(
+ FlagManager flagManager,
+ Context context,
+ SecureSettings secureSettings,
+ @Main Resources resources,
DumpManager dumpManager) {
mFlagManager = flagManager;
mSecureSettings = secureSettings;
- IntentFilter filter = new IntentFilter(ACTION_SET_FLAG);
- context.registerReceiver(mReceiver, filter, FLAGS_PERMISSION, null);
+ 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. */
@Override
- public boolean isEnabled(int id, boolean defaultValue) {
+ 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) {
try {
@@ -95,6 +121,10 @@ public class FeatureFlagManager implements FlagReader, FlagWriter, Dumpable {
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) {
@@ -151,9 +181,15 @@ public class FeatureFlagManager implements FlagReader, FlagWriter, Dumpable {
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);
+ }
}
}
diff --git a/packages/SystemUI/src-release/com/android/systemui/flags/FeatureFlagManager.java b/packages/SystemUI/src-release/com/android/systemui/flags/FeatureFlagManager.java
index 6ff175f589a6..0934b32a71e4 100644
--- a/packages/SystemUI/src-release/com/android/systemui/flags/FeatureFlagManager.java
+++ b/packages/SystemUI/src-release/com/android/systemui/flags/FeatureFlagManager.java
@@ -16,7 +16,6 @@
package com.android.systemui.flags;
-import android.content.Context;
import android.util.SparseBooleanArray;
import androidx.annotation.NonNull;
@@ -24,7 +23,6 @@ import androidx.annotation.NonNull;
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.util.settings.SecureSettings;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -41,8 +39,7 @@ import javax.inject.Inject;
public class FeatureFlagManager implements FlagReader, FlagWriter, Dumpable {
SparseBooleanArray mAccessedFlags = new SparseBooleanArray();
@Inject
- public FeatureFlagManager(
- SecureSettings secureSettings, Context context, DumpManager dumpManager) {
+ public FeatureFlagManager(DumpManager dumpManager) {
dumpManager.registerDumpable("SysUIFlags", this);
}
@@ -53,6 +50,11 @@ public class FeatureFlagManager implements FlagReader, FlagWriter, Dumpable {
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;
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/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index a41a49799c2d..a3801546fa98 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);
@@ -2043,7 +2052,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
/**
* @return if udfps is available on this device. will return true even if the user hasn't
- * enrolled udfps.
+ * enrolled udfps. This may be false if called before onAllAuthenticatorsRegistered.
*/
public boolean isUdfpsAvailable() {
return mAuthController.getUdfpsProps() != null
@@ -2092,7 +2101,6 @@ 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 runningOrRestarting = mFingerprintRunningState == BIOMETRIC_STATE_RUNNING
@@ -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
*/
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 3c80a186a4a7..8a0b5b8704e6 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -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/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/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 dacc169f85ee..7bb4708443e9 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt
@@ -17,6 +17,7 @@ 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
@@ -24,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
@@ -61,6 +63,7 @@ class SidefpsController @Inject constructor(
private val layoutInflater: LayoutInflater,
fingerprintManager: FingerprintManager?,
private val windowManager: WindowManager,
+ private val activityTaskManager: ActivityTaskManager,
overviewProxyService: OverviewProxyService,
displayManager: DisplayManager,
@Main mainExecutor: DelayableExecutor,
@@ -130,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) {
@@ -228,11 +231,19 @@ class SidefpsController @Inject constructor(
}
@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
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
index 70bc56bd1425..94743407f03d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
@@ -63,13 +63,13 @@ abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView>
@Override
protected void onViewAttached() {
- mPanelExpansionStateManager.addListener(mPanelExpansionListener);
+ mPanelExpansionStateManager.addExpansionListener(mPanelExpansionListener);
mDumpManger.registerDumpable(getDumpTag(), this);
}
@Override
protected void onViewDetached() {
- mPanelExpansionStateManager.removeListener(mPanelExpansionListener);
+ mPanelExpansionStateManager.removeExpansionListener(mPanelExpansionListener);
mDumpManger.unregisterDumpable(getDumpTag());
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 81a4d590aec6..eb36915f9753 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -760,10 +760,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
@@ -786,7 +788,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:
@@ -830,6 +833,7 @@ public class UdfpsController implements DozeReceiver {
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);
@@ -840,7 +844,7 @@ public class UdfpsController implements DozeReceiver {
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/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index 495366c8f69f..d1ea45cac081 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -126,7 +126,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
mInputBouncerHiddenAmount = KeyguardBouncer.EXPANSION_HIDDEN;
mIsBouncerVisible = mKeyguardViewManager.bouncerIsOrWillBeShowing();
mConfigurationController.addCallback(mConfigurationListener);
- mPanelExpansionStateManager.addListener(mPanelExpansionListener);
+ mPanelExpansionStateManager.addExpansionListener(mPanelExpansionListener);
updateAlpha();
updatePauseAuth();
@@ -145,7 +145,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
mKeyguardViewManager.removeAlternateAuthInterceptor(mAlternateAuthInterceptor);
mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
mConfigurationController.removeCallback(mConfigurationListener);
- mPanelExpansionStateManager.removeListener(mPanelExpansionListener);
+ mPanelExpansionStateManager.removeExpansionListener(mPanelExpansionListener);
if (mLockScreenShadeTransitionController.getUdfpsKeyguardViewController() == this) {
mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(null);
}
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/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/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/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 ab083a920a10..34f441510a7e 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java
@@ -21,15 +21,8 @@ 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;
/**
@@ -39,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);
}
/**
@@ -71,23 +49,6 @@ 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);
- }
-
- /** 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 void assertLegacyPipelineEnabled() {
if (isNewNotifPipelineRenderingEnabled()) {
throw new IllegalStateException("Old pipeline code running w/ new pipeline enabled");
@@ -118,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() {
@@ -132,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() {
@@ -150,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() {
@@ -194,10 +151,4 @@ public class FeatureFlags {
public static boolean isProviderModelSettingEnabled(Context context) {
return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL);
}
-
- /** Simple interface for beinga alerted when a specific flag changes value. */
- public interface Listener {
- /** */
- void onFlagChanged(Flag<?> flag);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index f09c797a6608..c33aa9e5ee28 100644
--- a/packages/SystemUI/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,6 +76,9 @@ 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 =
@@ -80,6 +87,9 @@ public class Flags {
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 =
@@ -96,6 +106,11 @@ public class Flags {
public static final BooleanFlag ONGOING_CALL_IN_IMMERSIVE_CHIP_TAP =
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/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/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 6a1eae75f9a9..1eef6e87cec0 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;
@@ -131,10 +128,10 @@ import com.android.systemui.navigationbar.gestural.QuickswitchOrientedNavHandle;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
-import com.android.systemui.shared.rotation.RotationButton;
-import com.android.systemui.shared.rotation.RotationButtonController;
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;
@@ -614,8 +611,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mDeviceProvisionedController.addCallback(mUserSetupListener);
mNotificationShadeDepthController.addListener(mDepthListener);
- updateAccessibilityButtonModeIfNeeded();
-
return barView;
}
@@ -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();
@@ -1558,7 +1525,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/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 1784f73e1f53..cdf770f80387 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -178,7 +178,10 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
@Override
public void setSquishinessFraction(float squishinessFraction) {
- // No-op, paged layouts are not squishy.
+ int nPages = mPages.size();
+ for (int i = 0; i < nPages; i++) {
+ mPages.get(i).setSquishinessFraction(squishinessFraction);
+ }
}
private void updateListening() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSquishinessController.kt b/packages/SystemUI/src/com/android/systemui/qs/QSSquishinessController.kt
index 4854600994aa..c1c146d40e38 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSquishinessController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSquishinessController.kt
@@ -3,15 +3,14 @@ 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 com.android.systemui.qs.tileimpl.HeightOverrideable
import javax.inject.Inject
import javax.inject.Named
@QSScope
class QSSquishinessController @Inject constructor(
- private val qsTileHost: QSTileHost,
@Named(QQS_FOOTER) private val qqsFooterActionsView: FooterActionsView,
private val qsAnimator: QSAnimator,
+ private val qsPanelController: QSPanelController,
private val quickQSPanelController: QuickQSPanelController
) {
@@ -34,18 +33,10 @@ class QSSquishinessController @Inject constructor(
* Change the height of all tiles and repositions their siblings.
*/
private fun updateSquishiness() {
- // Update tile positions in the layout
+ (qsPanelController.tileLayout as QSPanel.QSTileLayout).setSquishinessFraction(squishiness)
val tileLayout = quickQSPanelController.tileLayout as TileLayout
tileLayout.setSquishinessFraction(squishiness)
- // Adjust their heights as well
- for (tile in qsTileHost.tiles) {
- val tileView = quickQSPanelController.getTileView(tile)
- (tileView as? HeightOverrideable)?.let {
- it.squishinessFraction = squishiness
- }
- }
-
// Calculate how much we should move the footer
val tileHeightOffset = tileLayout.height - tileLayout.tilesHeight
val footerTopMargin = (qqsFooterActionsView.layoutParams as ViewGroup.MarginLayoutParams)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 0fc4f4a94bda..a923effea1e1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -39,11 +39,11 @@ 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.StatusIconContainer;
import com.android.systemui.statusbar.policy.Clock;
import com.android.systemui.statusbar.policy.VariableDateView;
-import com.android.systemui.statusbar.window.StatusBarWindowView;
import java.util.List;
@@ -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;
@@ -161,10 +162,12 @@ public class QuickStatusBarHeader extends FrameLayout {
void onAttach(TintedIconManager iconManager,
QSExpansionPathInterpolator qsExpansionPathInterpolator,
List<String> rssiIgnoredSlots,
- boolean useCombinedQSHeader) {
+ boolean useCombinedQSHeader,
+ StatusBarContentInsetsProvider insetsProvider) {
mUseCombinedQSHeader = useCombinedQSHeader;
mTintedIconManager = iconManager;
mRssiIgnoredSlots = rssiIgnoredSlots;
+ mInsetsProvider = insetsProvider;
int fillColor = Utils.getColorAttrDefaultColor(getContext(),
android.R.attr.textColorPrimary);
@@ -436,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;
@@ -469,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 1b3450436c6f..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))
@@ -226,7 +230,7 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
}
mView.onAttach(mIconManager, mQSExpansionPathInterpolator, rssiIgnoredSlots,
- mFeatureFlags.useCombinedQSHeaders());
+ 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 58c05089b062..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;
@@ -285,5 +286,11 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
}
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/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/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index 23b2a7642e36..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;
@@ -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 f6dbb0b95ecd..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
@@ -128,7 +128,9 @@ public class InternetDialog extends SystemUIDialog implements
private boolean mCanConfigMobileData;
// Wi-Fi entries
+ @VisibleForTesting
protected WifiEntry mConnectedWifiEntry;
+ @VisibleForTesting
protected int mWifiEntriesCount;
// Wi-Fi scanning progress bar
@@ -334,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);
});
@@ -576,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 5673136e1828..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
@@ -76,8 +76,7 @@ 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;
@@ -100,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 =
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 93828b3bcc99..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
@@ -63,7 +63,8 @@ class InternetDialogFactory @Inject constructor(
canConfigMobileData, canConfigWifi, aboveStatusBar, uiEventLogger, handler,
executor)
if (view != null) {
- dialogLaunchAnimator.showFromView(internetDialog!!, view)
+ dialogLaunchAnimator.showFromView(internetDialog!!, view,
+ animateBackgroundBoundsChange = true)
} else {
internetDialog?.show()
}
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/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/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index eb89be1945c6..46004db3067a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -37,6 +37,7 @@ 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.ScrimController
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener
@@ -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()
}
@@ -458,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/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/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 daae43f69d3b..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);
@@ -1056,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);
}
@@ -1206,7 +1212,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
}
private boolean mDemoInetCondition;
- private WifiSignalController.WifiState mDemoWifiState;
+ private WifiState mDemoWifiState;
@Override
public void onDemoModeStarted() {
@@ -1241,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/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/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index d5912e0ddbe7..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;
@@ -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/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/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 03786b9b58ee..f068a8ec8294 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -47,7 +47,6 @@ import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.window.StatusBarWindowView;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -239,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/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index df0f872d979c..32659e416535 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -35,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;
@@ -173,6 +173,7 @@ 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;
@@ -782,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();
@@ -1561,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);
}
}
@@ -1646,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);
}
@@ -2203,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
@@ -2238,14 +2241,22 @@ public class NotificationPanelViewController extends PanelViewController {
private void updateQsExpansion() {
if (mQs == null) return;
float qsExpansionFraction = computeQsExpansionFraction();
+ float squishiness = mNotificationStackScrollLayoutController
+ .getNotificationSquishinessFraction();
mQs.setQsExpansion(qsExpansionFraction, getExpandedFraction(), getHeaderTranslation(),
- mNotificationStackScrollLayoutController.getNotificationSquishinessFraction());
+ 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);
}
@@ -3787,45 +3798,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;
@@ -3936,6 +3908,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() {
@@ -4672,39 +4693,29 @@ public class NotificationPanelViewController extends PanelViewController {
mView.removeCallbacks(mMaybeHideExpandedRunnable);
}
- private final PanelBar.PanelStateChangeListener mPanelStateChangeListener =
- new PanelBar.PanelStateChangeListener() {
+ @PanelState
+ private int mCurrentPanelState = STATE_CLOSED;
- @PanelBar.PanelState
- private int mCurrentState = 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 0b3e040bd321..01587f7fe98c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -447,7 +447,7 @@ public class NotificationShadeWindowViewController {
setDragDownHelper(mLockscreenShadeTransitionController.getTouchHelper());
mDepthController.setRoot(mView);
- mPanelExpansionStateManager.addListener(mDepthController);
+ mPanelExpansionStateManager.addExpansionListener(mDepthController);
}
public NotificationShadeWindowView getView() {
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 b508ddfdafba..2823d985102f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -67,7 +67,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
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;
@@ -153,8 +153,6 @@ public abstract class PanelViewController {
private boolean mAnimateAfterExpanding;
private boolean mIsFlinging;
- PanelBar mBar;
-
private String mViewName;
private float mInitialTouchY;
private float mInitialTouchX;
@@ -294,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.
@@ -462,7 +456,6 @@ public abstract class PanelViewController {
protected void onTrackingStopped(boolean expand) {
mTracking = false;
- mBar.onTrackingStopped(expand);
mStatusBar.onTrackingStopped(expand);
updatePanelExpansionAndVisibility();
}
@@ -470,7 +463,6 @@ public abstract class PanelViewController {
protected void onTrackingStarted() {
endClosing();
mTracking = true;
- mBar.onTrackingStarted();
mStatusBar.onTrackingStarted();
notifyExpandingStarted();
updatePanelExpansionAndVisibility();
@@ -848,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()) {
@@ -1089,12 +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());
- }
- updateVisibility();
mPanelExpansionStateManager.onPanelExpansionChanged(
mExpandedFraction, isExpanded(), mTracking);
+ updateVisibility();
}
public boolean isExpanded() {
@@ -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 41312243be34..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;
@@ -40,20 +38,14 @@ import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.window.StatusBarWindowView;
import com.android.systemui.util.leak.RotationUtils;
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;
@@ -77,18 +69,10 @@ public class PhoneStatusBarView extends PanelBar {
mContentInsetsProvider = Dependency.get(StatusBarContentInsetsProvider.class);
}
- public void setBar(StatusBar bar) {
- mBar = bar;
- }
-
void setTouchEventHandler(TouchEventHandler handler) {
mTouchEventHandler = handler;
}
- public void setScrimController(ScrimController scrimController) {
- mScrimController = scrimController;
- }
-
@Override
public void onFinishInflate() {
mBattery = findViewById(R.id.battery);
@@ -175,7 +159,6 @@ public class PhoneStatusBarView extends PanelBar {
@Override
public boolean onTouchEvent(MotionEvent event) {
- mBar.onTouchEvent(event);
if (mTouchEventHandler == null) {
Log.w(
TAG,
@@ -192,7 +175,7 @@ public class PhoneStatusBarView extends PanelBar {
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- mBar.onTouchEvent(event);
+ mTouchEventHandler.onInterceptTouchEvent(event);
return super.onInterceptTouchEvent(event);
}
@@ -232,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;
@@ -252,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;
@@ -262,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/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index cef0613c3f9a..1077347eab0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -271,7 +271,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
ScrimController.this.onThemeChanged();
}
});
- panelExpansionStateManager.addListener(
+ panelExpansionStateManager.addExpansionListener(
(fraction, expanded, tracking) -> setRawPanelExpansionFraction(fraction)
);
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 73b9b3831163..cbaa4683c364 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -230,7 +230,6 @@ 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.statusbar.window.StatusBarWindowView;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.DumpUtilsKt;
import com.android.systemui.util.WallpaperController;
@@ -335,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) {
@@ -360,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);
@@ -510,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
@@ -642,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;
@@ -778,6 +772,7 @@ public class StatusBar extends SystemUI implements
SystemStatusAnimationScheduler animationScheduler,
StatusBarLocationPublisher locationPublisher,
StatusBarIconController statusBarIconController,
+ StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
LockscreenShadeTransitionController lockscreenShadeTransitionController,
FeatureFlags featureFlags,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
@@ -874,6 +869,7 @@ public class StatusBar extends SystemUI implements
mAnimationScheduler = animationScheduler;
mStatusBarLocationPublisher = locationPublisher;
mStatusBarIconController = statusBarIconController;
+ mStatusBarHideIconsForBouncerManager = statusBarHideIconsForBouncerManager;
mFeatureFlags = featureFlags;
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
mMainHandler = mainHandler;
@@ -887,7 +883,7 @@ public class StatusBar extends SystemUI implements
mStartingSurfaceOptional = startingSurfaceOptional;
lockscreenShadeTransitionController.setStatusbar(this);
- mPanelExpansionStateManager.addListener(this::onPanelExpansionChanged);
+ mPanelExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged);
mBubbleExpandListener =
(isExpanding, key) -> mContext.getMainExecutor().execute(() -> {
@@ -939,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();
@@ -1128,7 +1125,7 @@ public class StatusBar extends SystemUI implements
mNotificationLogger.setUpWithContainer(notifListContainer);
mNotificationIconAreaController.setupShelf(mNotificationShelfController);
- mPanelExpansionStateManager.addListener(mWakeUpCoordinator);
+ mPanelExpansionStateManager.addExpansionListener(mWakeUpCoordinator);
mUserSwitcherController.init(mNotificationShadeWindowView);
@@ -1142,12 +1139,6 @@ public class StatusBar extends SystemUI implements
PhoneStatusBarView oldStatusBarView = mStatusBarView;
mStatusBarView = (PhoneStatusBarView) statusBarFragment.getView();
- mStatusBarView.setBar(this);
- mStatusBarView.setPanelStateChangeListener(
- mNotificationPanelViewController.getPanelStateChangeListener());
- mStatusBarView.setScrimController(mScrimController);
-
- mNotificationPanelViewController.setBar(mStatusBarView);
mPhoneStatusBarViewController = mPhoneStatusBarViewControllerFactory
.create(mStatusBarView, mNotificationPanelViewController
@@ -1200,9 +1191,11 @@ public class StatusBar extends SystemUI implements
mAnimationScheduler,
mStatusBarLocationPublisher,
mNotificationIconAreaController,
+ mPanelExpansionStateManager,
mFeatureFlags,
() -> Optional.of(this),
mStatusBarIconController,
+ mStatusBarHideIconsForBouncerManager,
mKeyguardStateController,
mNetworkController,
mStatusBarStateController,
@@ -1877,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) {
@@ -1921,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() {
@@ -2430,6 +2385,8 @@ public class StatusBar extends SystemUI implements
if (mLightRevealScrim != null) {
pw.println(
+ "mLightRevealScrim.getRevealEffect(): " + mLightRevealScrim.getRevealEffect());
+ pw.println(
"mLightRevealScrim.getRevealAmount(): " + mLightRevealScrim.getRevealAmount());
}
@@ -3100,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();
}
@@ -3427,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());
}
}
@@ -3517,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) {
@@ -4260,7 +4212,7 @@ public class StatusBar extends SystemUI implements
+ "mStatusBarKeyguardViewManager was null");
return;
}
- if (mKeyguardStateController.isKeyguardFadingAway() && !mCallingFadingAwayAfterReveal) {
+ if (mKeyguardStateController.isKeyguardFadingAway()) {
mStatusBarKeyguardViewManager.onKeyguardFadedAway();
}
}
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 6ae8331dfde5..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,48 +115,118 @@ 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 minDotPadding = if (isPrivacyDotEnabled)
@@ -165,7 +238,7 @@ class StatusBarContentInsetsProvider @Inject constructor(
val minLeft: Int
val minRight: Int
- if (isRtl) {
+ if (configurationController.isLayoutRtl) {
minLeft = max(minDotPadding, roundedCornerPadding)
minRight = roundedCornerPadding
} else {
@@ -178,10 +251,10 @@ class StatusBarContentInsetsProvider @Inject constructor(
targetRotation,
dc,
context.resources.configuration.windowConfiguration.maxBounds,
- SystemBarUtils.getStatusBarHeight(context),
+ SystemBarUtils.getStatusBarHeightForRotation(context, targetRotation),
minLeft,
minRight,
- isRtl,
+ configurationController.isLayoutRtl,
dotWidth)
}
@@ -252,7 +325,7 @@ fun getPrivacyChipBoundingRectForInsets(
* @param currentRotation current device rotation
* @param targetRotation rotation for which to calculate the status bar content rect
* @param displayCutout [DisplayCutout] for the current display. possibly null
- * @param windowMetrics [WindowMetrics] for the current window
+ * @param maxBounds the display bounds in our current rotation
* @param statusBarHeight height of the status bar for the target rotation
* @param minLeft the minimum padding to enforce on the left
* @param minRight the minimum padding to enforce on the right
@@ -464,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/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 30e668ac4431..58d28813df0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -279,7 +279,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mBouncer = mKeyguardBouncerFactory.create(container, mExpansionCallback);
mNotificationPanelViewController = notificationPanelViewController;
if (panelExpansionStateManager != null) {
- panelExpansionStateManager.addListener(this);
+ panelExpansionStateManager.addExpansionListener(this);
}
mBypassController = bypassController;
mNotificationContainer = notificationContainer;
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/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 5a3cb6f569a6..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
@@ -92,6 +92,7 @@ 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;
@@ -224,6 +225,7 @@ public interface StatusBarPhoneModule {
SystemStatusAnimationScheduler animationScheduler,
StatusBarLocationPublisher locationPublisher,
StatusBarIconController statusBarIconController,
+ StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
LockscreenShadeTransitionController transitionController,
FeatureFlags featureFlags,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
@@ -322,6 +324,7 @@ public interface StatusBarPhoneModule {
animationScheduler,
locationPublisher,
statusBarIconController,
+ statusBarHideIconsForBouncerManager,
transitionController,
featureFlags,
keyguardUnlockAnimationController,
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
index aa748b00d570..2c7c8e113fc5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt
@@ -16,6 +16,8 @@
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
@@ -23,42 +25,136 @@ import javax.inject.Inject
/**
* A class responsible for managing the notification panel's current state.
*
- * TODO(b/200063118): Move [PanelBar.panelExpansionChanged] logic to this class and make this class
- * the one source of truth for the state of panel expansion.
+ * TODO(b/200063118): Make this class the one source of truth for the state of panel expansion.
*/
@SysUISingleton
class PanelExpansionStateManager @Inject constructor() {
- private val listeners: MutableList<PanelExpansionListener> = mutableListOf()
+ 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 has changed.
+ * 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 addListener(listener: PanelExpansionListener) {
- listeners.add(listener)
+ fun addExpansionListener(listener: PanelExpansionListener) {
+ expansionListeners.add(listener)
listener.onPanelExpansionChanged(fraction, expanded, tracking)
}
- /** Removes a listener. */
- fun removeListener(listener: PanelExpansionListener) {
- listeners.remove(listener)
+ /** Removes an expansion listener. */
+ fun removeExpansionListener(listener: PanelExpansionListener) {
+ expansionListeners.remove(listener)
}
- /** Called when the panel expansion has changed. Notifies all listeners of change. */
+ /** 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
- listeners.forEach { it.onPanelExpansionChanged(fraction, expanded, 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/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/window/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowView.java
index 8b11e4c1b352..06cc96e2e0cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowView.java
@@ -21,26 +21,15 @@ 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.
*/
@@ -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/unfold/SysUIUnfoldModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
index cc2c2083cbab..65106f1df93c 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
@@ -41,7 +41,9 @@ annotation class SysUIUnfoldScope
* no objects will get constructed if these parameters are empty.
*/
@Module(subcomponents = [SysUIUnfoldComponent::class])
-object SysUIUnfoldModule {
+class SysUIUnfoldModule {
+ constructor() {}
+
@Provides
@SysUISingleton
fun provideSysUIUnfoldComponent(
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/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 54278066b5d3..209df6b54f8f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
@@ -60,9 +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))
+
+ 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.
@@ -126,6 +137,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
@@ -138,6 +154,7 @@ class DialogLaunchAnimatorTest : SysuiTestCase() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ window.setLayout(DIALOG_WIDTH, DIALOG_HEIGHT)
setContentView(contentView)
}
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 c98a504b8784..2d510923b942 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt
@@ -18,8 +18,12 @@ 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
@@ -60,9 +64,11 @@ 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
@@ -84,6 +90,8 @@ class SidefpsControllerTest : SysuiTestCase() {
@Mock
lateinit var windowManager: WindowManager
@Mock
+ lateinit var activityTaskManager: ActivityTaskManager
+ @Mock
lateinit var sidefpsView: View
@Mock
lateinit var displayManager: DisplayManager
@@ -144,7 +152,8 @@ class SidefpsControllerTest : SysuiTestCase() {
sideFpsController = SidefpsController(
context.createDisplayContext(display), layoutInflater, fingerprintManager,
- windowManager, overviewProxyService, displayManager, executor, handler
+ windowManager, activityTaskManager, overviewProxyService, displayManager, executor,
+ handler
)
overlayController = ArgumentCaptor.forClass(ISidefpsController::class.java).apply {
@@ -211,12 +220,23 @@ class SidefpsControllerTest : SysuiTestCase() {
testIgnoredFor(REASON_AUTH_KEYGUARD)
}
- private fun testIgnoredFor(reason: Int) {
- overlayController.show(SENSOR_ID, reason)
+ @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
@@ -267,4 +287,9 @@ 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() \ No newline at end of file
+ .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 cfac9cb592a0..d90eb73a1595 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -405,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 6f0456ef8f5b..0e86964147d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -171,7 +171,7 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
verify(mStatusBarStateController).removeCallback(mStatusBarStateListener);
for (PanelExpansionListener listener : mExpansionListeners) {
- verify(mPanelExpansionStateManager).removeListener(listener);
+ verify(mPanelExpansionStateManager).removeExpansionListener(listener);
}
verify(mKeyguardStateController).removeCallback(mKeyguardStateControllerCallback);
}
@@ -435,7 +435,7 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
private void captureExpansionListeners() {
verify(mPanelExpansionStateManager, times(2))
- .addListener(mExpansionListenerCaptor.capture());
+ .addExpansionListener(mExpansionListenerCaptor.capture());
// first (index=0) is from super class, UdfpsAnimationViewController.
// second (index=1) is from UdfpsKeyguardViewController
mExpansionListeners = mExpansionListenerCaptor.getAllValues();
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 2fa32ba1fe75..634763866d02 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java
@@ -53,8 +53,6 @@ import java.io.StringWriter;
public class FeatureFlagManagerTest extends SysuiTestCase {
FeatureFlagManager mFeatureFlagManager;
- @Mock private FlagManager mFlagManager;
- @Mock private SecureSettings mSecureSettings;
@Mock private Context mContext;
@Mock private DumpManager mDumpManager;
@@ -62,14 +60,11 @@ public class FeatureFlagManagerTest extends SysuiTestCase {
public void setup() {
MockitoAnnotations.initMocks(this);
- mFeatureFlagManager = new FeatureFlagManager(mSecureSettings, mContext, mDumpManager);
+ mFeatureFlagManager = new FeatureFlagManager(mDumpManager);
}
@After
public void onFinished() {
- // SecureSettings and Context are provided for constructor consistency with the
- // debug version of the FeatureFlagManager, but should never be used.
- verifyZeroInteractions(mSecureSettings, mContext);
// The dump manager should be registered with even for the release version, but that's it.
verify(mDumpManager).registerDumpable(anyString(), any());
verifyNoMoreInteractions(mDumpManager);
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/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/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/qs/QSSquishinessControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSquishinessControllerTest.kt
index 3059aa1ae658..f41d7b127a9e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSquishinessControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSquishinessControllerTest.kt
@@ -4,13 +4,10 @@ import android.testing.AndroidTestingRunner
import android.view.ViewGroup
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.plugins.qs.QSTile
-import com.android.systemui.qs.tileimpl.QSTileViewImpl
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.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.never
@@ -21,14 +18,13 @@ import org.mockito.junit.MockitoJUnit
@SmallTest
class QSSquishinessControllerTest : SysuiTestCase() {
- @Mock private lateinit var qsTileHost: QSTileHost
@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 qstileView: QSTileViewImpl
- @Mock private lateinit var qstile: QSTile
@Mock private lateinit var tileLayout: TileLayout
+ @Mock private lateinit var pagedTileLayout: PagedTileLayout
@JvmField @Rule val mockitoRule = MockitoJUnit.rule()
@@ -36,11 +32,10 @@ class QSSquishinessControllerTest : SysuiTestCase() {
@Before
fun setup() {
- qsSquishinessController = QSSquishinessController(qsTileHost, qqsFooterActionsView,
- qsAnimator, quickQsPanelController)
- `when`(qsTileHost.tiles).thenReturn(mutableListOf(qstile))
- `when`(quickQsPanelController.getTileView(any())).thenReturn(qstileView)
+ qsSquishinessController = QSSquishinessController(qqsFooterActionsView, qsAnimator,
+ qsPanelController, quickQsPanelController)
`when`(quickQsPanelController.tileLayout).thenReturn(tileLayout)
+ `when`(qsPanelController.tileLayout).thenReturn(pagedTileLayout)
`when`(qqsFooterActionsView.layoutParams).thenReturn(qqsFooterActionsViewLP)
}
@@ -56,7 +51,7 @@ class QSSquishinessControllerTest : SysuiTestCase() {
@Test
fun setSquishiness_updatesTiles() {
qsSquishinessController.squishiness = 0.5f
- verify(qstileView).squishinessFraction = 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 f32ac849b000..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
@@ -106,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()
@@ -149,7 +152,8 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
qsExpansionPathInterpolator,
batteryMeterViewController,
featureFlags,
- variableDateViewControllerFactory
+ variableDateViewControllerFactory,
+ insetsProvider
)
}
@@ -248,7 +252,7 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
controller.init()
val captor = argumentCaptor<List<String>>()
- verify(view).onAttach(any(), any(), capture(captor), anyBoolean())
+ verify(view).onAttach(any(), any(), capture(captor), anyBoolean(), any())
assertThat(captor.value).containsExactly(
mContext.getString(com.android.internal.R.string.status_bar_mobile)
@@ -261,7 +265,7 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
controller.init()
val captor = argumentCaptor<List<String>>()
- verify(view).onAttach(any(), any(), capture(captor), anyBoolean())
+ 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/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/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 eb03b5ff2a6c..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
@@ -49,8 +49,7 @@ 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;
@@ -104,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
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 5e1fea512d55..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);
@@ -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/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/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/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/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
index 6e1f1487f2e7..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
@@ -176,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;
@@ -308,7 +306,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
private NotificationsQSContainerController mNotificationsQSContainerController;
@Mock
private FeatureFlags mFeatureFlags;
- private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent;
+ private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
private SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController;
private View.AccessibilityDelegate mAccessibiltyDelegate;
@@ -460,7 +458,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
() -> {},
mNotificationShelfController);
mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
- mNotificationPanelViewController.setBar(mPanelBar);
mNotificationPanelViewController.setKeyguardIndicationController(
mKeyguardIndicationController);
ArgumentCaptor<View.OnAttachStateChangeListener> onAttachStateChangeListenerArgumentCaptor =
@@ -526,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/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index eea8eb91675c..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
@@ -52,8 +52,6 @@ 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
@@ -76,8 +74,6 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() {
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)
@@ -85,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)
}
@@ -128,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 300860ca0a49..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,53 +45,28 @@ class PhoneStatusBarViewTest : SysuiTestCase() {
`when`(panelViewController.view).thenReturn(panelView)
view = PhoneStatusBarView(mContext, null)
- view.setScrimController(scrimController)
- view.setBar(statusBar)
- }
-
- @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
@@ -104,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()
}
@@ -115,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()
}
@@ -126,19 +97,18 @@ class PhoneStatusBarViewTest : SysuiTestCase() {
// No assert needed, just testing no crash
}
- private class TestStateChangedListener : PanelBar.PanelStateChangeListener {
- var state: Int = 0
- override fun onStateChanged(state: Int) {
- this.state = state
- }
- }
-
private class TestTouchEventHandler : PhoneStatusBarView.TouchEventHandler {
+ var lastInterceptEvent: MotionEvent? = null
var lastEvent: MotionEvent? = null
- var returnValue: Boolean = false
+ var handleTouchReturnValue: Boolean = false
+
+ override fun onInterceptTouchEvent(event: MotionEvent?) {
+ lastInterceptEvent = event
+ }
+
override fun handleTouchEvent(event: MotionEvent?): Boolean {
lastEvent = event
- return returnValue
+ return handleTouchReturnValue
}
}
}
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 e5158e74759c..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
@@ -467,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"
@@ -475,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)
@@ -492,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"
@@ -507,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/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 7a93d03a5843..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
@@ -279,6 +279,7 @@ public class StatusBarTest extends SysuiTestCase {
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 {
@@ -332,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();
@@ -390,7 +391,7 @@ public class StatusBarTest extends SysuiTestCase {
mNetworkController,
mBatteryController,
mColorExtractor,
- new ScreenLifecycle(mock(DumpManager.class)),
+ new ScreenLifecycle(mDumpManager),
wakefulnessLifecycle,
mStatusBarStateController,
Optional.of(mBubblesManager),
@@ -440,6 +441,7 @@ public class StatusBarTest extends SysuiTestCase {
mAnimationScheduler,
mLocationPublisher,
mIconController,
+ new StatusBarHideIconsForBouncerManager(mCommandQueue, mMainExecutor, mDumpManager),
mLockscreenTransitionController,
mFeatureFlags,
mKeyguardUnlockAnimationController,
@@ -450,7 +452,7 @@ public class StatusBarTest extends SysuiTestCase {
mUnlockedScreenOffAnimationController,
Optional.of(mStartingSurface),
mTunerService,
- mock(DumpManager.class),
+ mDumpManager,
mActivityLaunchAnimator);
when(mKeyguardViewMediator.registerStatusBar(
any(StatusBar.class),
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
index e09cde917285..32bad5c084f5 100644
--- 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
@@ -33,9 +33,9 @@ class PanelExpansionStateManagerTest : SysuiTestCase() {
}
@Test
- fun onPanelExpansionChanged_listenersNotified() {
+ fun onPanelExpansionChanged_listenerNotified() {
val listener = TestPanelExpansionListener()
- panelExpansionStateManager.addListener(listener)
+ panelExpansionStateManager.addExpansionListener(listener)
val fraction = 0.6f
val expanded = true
val tracking = true
@@ -48,20 +48,143 @@ class PanelExpansionStateManagerTest : SysuiTestCase() {
}
@Test
- fun addPanelExpansionListener_listenerNotifiedOfCurrentValues() {
+ fun addExpansionListener_listenerNotifiedOfCurrentValues() {
val fraction = 0.6f
val expanded = true
val tracking = true
panelExpansionStateManager.onPanelExpansionChanged(fraction, expanded, tracking)
val listener = TestPanelExpansionListener()
- panelExpansionStateManager.addListener(listener)
+ 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
@@ -77,4 +200,14 @@ class PanelExpansionStateManagerTest : SysuiTestCase() {
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/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/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 cd743f9524e6..b5f3389c50e0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -31,7 +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.StopBgUsersOnSwitch;
+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;
@@ -15099,8 +15099,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public void setStopBackgroundUsersOnSwitch(@StopBgUsersOnSwitch int value) {
- mUserController.setStopBackgroundUsersOnSwitch(value);
+ public void setStopUserOnSwitch(@StopUserOnSwitch int value) {
+ mUserController.setStopUserOnSwitch(value);
}
@Override
@@ -16402,8 +16402,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public void setStopBackgroundUsersOnSwitch(int value) {
- ActivityManagerService.this.setStopBackgroundUsersOnSwitch(value);
+ public void setStopUserOnSwitch(int value) {
+ ActivityManagerService.this.setStopUserOnSwitch(value);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 60b2149b1f14..31e48fb0837f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -331,7 +331,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
case "get-isolated-pids":
return runGetIsolatedProcesses(pw);
case "set-stop-user-on-switch":
- return runSetStopBackgroundUsersOnSwitch(pw);
+ return runSetStopUserOnSwitch(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -3166,25 +3166,24 @@ final class ActivityManagerShellCommand extends ShellCommand {
return 0;
}
- private int runSetStopBackgroundUsersOnSwitch(PrintWriter pw) throws RemoteException {
+ private int runSetStopUserOnSwitch(PrintWriter pw) throws RemoteException {
mInternal.enforceCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- "setStopBackgroundUsersOnSwitch()");
+ "setStopUserOnSwitch()");
String arg = getNextArg();
if (arg == null) {
- Slogf.i(TAG, "runSetStopBackgroundUsersOnSwitch(): resetting to default value");
- mInternal.setStopBackgroundUsersOnSwitch(
- ActivityManager.STOP_BG_USERS_ON_SWITCH_DEFAULT);
+ 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_BG_USERS_ON_SWITCH_TRUE
- : ActivityManager.STOP_BG_USERS_ON_SWITCH_FALSE;
+ ? ActivityManager.STOP_USER_ON_SWITCH_TRUE
+ : ActivityManager.STOP_USER_ON_SWITCH_FALSE;
- Slogf.i(TAG, "runSetStopBackgroundUsersOnSwitch(): setting to %d (%b)", value, stop);
- mInternal.setStopBackgroundUsersOnSwitch(value);
+ Slogf.i(TAG, "runSetStopUserOnSwitch(): setting to %d (%b)", value, stop);
+ mInternal.setStopUserOnSwitch(value);
pw.println("Set to " + stop);
return 0;
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index b8be6c5f83dd..319fa94058dd 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -19,9 +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_BG_USERS_ON_SWITCH_DEFAULT;
-import static android.app.ActivityManager.STOP_BG_USERS_ON_SWITCH_TRUE;
-import static android.app.ActivityManager.StopBgUsersOnSwitch;
+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;
@@ -376,7 +376,7 @@ class UserController implements Handler.Callback {
* user is switched.
*/
@GuardedBy("mLock")
- private @StopBgUsersOnSwitch int mStopBgUsersOnSwitch = STOP_BG_USERS_ON_SWITCH_DEFAULT;
+ private @StopUserOnSwitch int mStopUserOnSwitch = STOP_USER_ON_SWITCH_DEFAULT;
UserController(ActivityManagerService service) {
this(new Injector(service));
@@ -418,29 +418,27 @@ class UserController implements Handler.Callback {
}
}
- void setStopBackgroundUsersOnSwitch(@StopBgUsersOnSwitch int value) {
+ void setStopUserOnSwitch(@StopUserOnSwitch int value) {
if (mInjector.checkCallingPermission(android.Manifest.permission.MANAGE_USERS)
== PackageManager.PERMISSION_DENIED && mInjector.checkCallingPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
== PackageManager.PERMISSION_DENIED) {
throw new SecurityException(
"You either need MANAGE_USERS or INTERACT_ACROSS_USERS_FULL permission to "
- + "call setStopBackgroundUsersOnSwitch()");
+ + "call setStopUserOnSwitch()");
}
synchronized (mLock) {
- Slogf.i(TAG, "setStopBackgroundUsersOnSwitch(): %d -> %d",
- mStopBgUsersOnSwitch, value);
- mStopBgUsersOnSwitch = value;
+ Slogf.i(TAG, "setStopUserOnSwitch(): %d -> %d", mStopUserOnSwitch, value);
+ mStopUserOnSwitch = value;
}
}
- private boolean shouldStopBackgroundUsersOnSwitch() {
+ private boolean shouldStopUserOnSwitch() {
synchronized (mLock) {
- if (mStopBgUsersOnSwitch != STOP_BG_USERS_ON_SWITCH_DEFAULT) {
- final boolean value = mStopBgUsersOnSwitch == STOP_BG_USERS_ON_SWITCH_TRUE;
- Slogf.i(TAG, "isStopBackgroundUsersOnSwitch(): returning overridden value (%b)",
- value);
+ 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;
}
}
@@ -1834,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;
@@ -1842,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,
@@ -1956,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) {
@@ -2646,9 +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(" mStopBgUsersOnSwitch:" + mStopBgUsersOnSwitch);
+ 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/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/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/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/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/inputmethod/InputMethodMenuController.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
index 73baf79ea4b1..82b34c35cfd2 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
@@ -223,7 +223,7 @@ public class InputMethodMenuController {
public Context getSettingsContext(int displayId) {
if (mSettingsContext == null || mSettingsContext.getDisplayId() != displayId) {
final Context systemUiContext = ActivityThread.currentActivityThread()
- .createSystemUiContext(displayId);
+ .getSystemUiContext(displayId);
final Context windowContext = systemUiContext.createWindowContext(
WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG, null /* options */);
mSettingsContext = new ContextThemeWrapper(
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/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/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 d1374362505f..f87856255b3e 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -770,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);
- }
}
/**
@@ -1269,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.
@@ -1311,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.
@@ -1332,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 9133d8403ed6..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;
@@ -7287,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
@@ -7657,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;
}
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 cb376520e000..9ef3ef2c0705 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -34,6 +34,7 @@ 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.Build.VERSION_CODES.N;
+import static android.os.Process.SYSTEM_UID;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.util.DisplayMetrics.DENSITY_DEFAULT;
import static android.util.RotationUtils.deltaRotation;
@@ -62,6 +63,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN;
@@ -4996,6 +4998,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
reconfigureDisplayLocked();
onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration());
mWmService.mDisplayNotificationController.dispatchDisplayAdded(this);
+ // Attach the SystemUiContext to this DisplayContent the get latest configuration.
+ // Note that the SystemUiContext will be removed automatically if this DisplayContent
+ // is detached.
+ mWmService.mWindowContextListenerController.registerWindowContainerListener(
+ getDisplayUiContext().getWindowContextToken(), this, SYSTEM_UID,
+ INVALID_WINDOW_TYPE, null /* options */);
}
}
@@ -6162,7 +6170,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;
@@ -6192,7 +6201,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 eab1aaf0d9fb..1d3c56efaf24 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;
@@ -111,9 +112,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Px;
import android.app.ActivityManager;
-import android.app.ActivityThread;
-import android.app.LoadedApk;
-import android.app.ResourcesManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -450,7 +448,7 @@ public class DisplayPolicy {
: service.mContext.createDisplayContext(displayContent.getDisplay());
mUiContext = displayContent.isDefaultDisplay ? service.mAtmService.mUiContext
: service.mAtmService.mSystemThread
- .createSystemUiContext(displayContent.getDisplayId());
+ .getSystemUiContext(displayContent.getDisplayId());
mDisplayContent = displayContent;
mLock = service.getWindowManagerLock();
@@ -880,6 +878,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.
@@ -950,6 +962,8 @@ public class DisplayPolicy {
if (mExtraNavBarAlt == win) {
mExtraNavBarAltPosition = getAltBarPosition(attrs);
}
+
+ attrs.flags = sanitizeFlagSlippery(attrs.flags, attrs.privateFlags, win.getName());
}
/**
@@ -2240,19 +2254,8 @@ public class DisplayPolicy {
// For non-system users, ensure that the resources are loaded from the current
// user's package info (see ContextImpl.createDisplayContext)
- final LoadedApk pi = ActivityThread.currentActivityThread().getPackageInfo(
- uiContext.getPackageName(), null, 0, userId);
- mCurrentUserResources = ResourcesManager.getInstance().getResources(null,
- pi.getResDir(),
- null /* splitResDirs */,
- pi.getOverlayDirs(),
- pi.getOverlayPaths(),
- pi.getApplicationInfo().sharedLibraryFiles,
- mDisplayContent.getDisplayId(),
- null /* overrideConfig */,
- uiContext.getResources().getCompatibilityInfo(),
- null /* classLoader */,
- null /* loaders */);
+ mCurrentUserResources = uiContext.createContextAsUser(UserHandle.of(userId), 0 /* flags*/)
+ .getResources();
}
@VisibleForTesting
@@ -2665,10 +2668,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/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/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 2057b1cdf24b..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 {
@@ -995,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);
@@ -1224,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()
@@ -1238,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 b1eca9d5d4e4..3ffa62dbbe7e 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2585,7 +2585,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// starts. Instead, we expect home activities to be launched when the system is ready
// (ActivityManagerService#systemReady).
if (mService.isBooted() || mService.isBooting()) {
- startSystemDecorations(display.mDisplayContent);
+ startSystemDecorations(display);
}
// Drop any cached DisplayInfos associated with this display id - the values are now
// out of date given this display added event.
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index a799e7c18703..4190ff0b9bc7 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2377,6 +2377,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]++; },
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index bdcda825860f..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}. */
@@ -2180,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/WindowContextListenerController.java b/services/core/java/com/android/server/wm/WindowContextListenerController.java
index bc530416c8cd..86e356a876b5 100644
--- a/services/core/java/com/android/server/wm/WindowContextListenerController.java
+++ b/services/core/java/com/android/server/wm/WindowContextListenerController.java
@@ -45,7 +45,7 @@ import java.util.Objects;
*
* <ul>
* <li>When a {@link WindowContext} is created, it registers the listener via
- * {@link WindowManagerService#registerWindowContextListener(IBinder, int, int, Bundle)}
+ * {@link WindowManagerService#attachWindowContextToDisplayArea(IBinder, int, int, Bundle)}
* automatically.</li>
* <li>When the {@link WindowContext} adds the first window to the screen via
* {@link android.view.WindowManager#addView(View, android.view.ViewGroup.LayoutParams)},
@@ -53,7 +53,7 @@ import java.util.Objects;
* to corresponding {@link WindowToken} via this controller.</li>
* <li>When the {@link WindowContext} is GCed, it unregisters the previously
* registered listener via
- * {@link WindowManagerService#unregisterWindowContextListener(IBinder)}.
+ * {@link WindowManagerService#detachWindowContextFromWindowContainer(IBinder)}.
* {@link WindowManagerService} is also responsible for removing the
* {@link WindowContext} created {@link WindowToken}.</li>
* </ul>
@@ -68,7 +68,7 @@ class WindowContextListenerController {
/**
* Registers the listener to a {@code container} which is associated with
- * a {@code clientToken}, which is a {@link android.app.WindowContext} representation. If the
+ * a {@code clientToken}, which is a {@link android.window.WindowContext} representation. If the
* listener associated with {@code clientToken} hasn't been initialized yet, create one
* {@link WindowContextListenerImpl}. Otherwise, the listener associated with
* {@code clientToken} switches to listen to the {@code container}.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d17c9dd8de3c..3edcd5cdf013 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -58,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;
@@ -2740,6 +2741,9 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public Configuration attachWindowContextToDisplayArea(IBinder clientToken, int
type, int displayId, Bundle options) {
+ if (clientToken == null) {
+ throw new IllegalArgumentException("clientToken must not be null!");
+ }
final boolean callerCanManageAppTokens = checkCallingPermission(MANAGE_APP_TOKENS,
"attachWindowContextToDisplayArea", false /* printLog */);
final int callingUid = Binder.getCallingUid();
@@ -2830,6 +2834,39 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ @Override
+ public Configuration attachToDisplayContent(IBinder clientToken, int displayId) {
+ if (clientToken == null) {
+ throw new IllegalArgumentException("clientToken must not be null!");
+ }
+ final int callingUid = Binder.getCallingUid();
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ // We use "getDisplayContent" instead of "getDisplayContentOrCreate" because
+ // this method may be called in DisplayPolicy's constructor and may cause
+ // infinite loop. In this scenario, we early return here and switch to do the
+ // registration in DisplayContent#onParentChanged at DisplayContent initialization.
+ final DisplayContent dc = mRoot.getDisplayContent(displayId);
+ if (dc == null) {
+ if (Binder.getCallingPid() != myPid()) {
+ throw new WindowManager.InvalidDisplayException("attachToDisplayContent: "
+ + "trying to attach to a non-existing display:" + displayId);
+ }
+ // Early return if this method is invoked from system process.
+ // See above comments for more detail.
+ return null;
+ }
+
+ mWindowContextListenerController.registerWindowContainerListener(clientToken, dc,
+ callingUid, INVALID_WINDOW_TYPE, null /* options */);
+ return dc.getConfiguration();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
/** Returns {@code true} if this binder is a registered window token. */
@Override
public boolean isWindowToken(IBinder binder) {
@@ -8337,8 +8374,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;
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 43a4f977e73a..bd8d1164ebef 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -581,27 +581,130 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
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;
@@ -630,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();
@@ -639,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 {
@@ -660,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;
@@ -683,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())
@@ -746,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;
}
@@ -1205,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/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 8042841f45ca..db13ae275965 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -12752,6 +12752,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));
}
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/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 128bfa8a28f3..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;
@@ -560,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);
@@ -602,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.
@@ -623,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);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java
index a8ede13e5de6..d7daa57cc9da 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java
@@ -29,7 +29,9 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import android.app.ActivityThread;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
@@ -44,6 +46,7 @@ import android.view.WindowManagerGlobal;
import com.android.server.inputmethod.InputMethodManagerService;
import com.android.server.inputmethod.InputMethodMenuController;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -62,6 +65,9 @@ public class InputMethodMenuControllerTest extends WindowTestsBase {
private InputMethodMenuController mController;
private DualDisplayAreaGroupPolicyTest.DualDisplayContent mSecondaryDisplay;
+ private IWindowManager mIWindowManager;
+ private DisplayManagerGlobal mDisplayManagerGlobal;
+
@Before
public void setUp() throws Exception {
// Let the Display to be created with the DualDisplay policy.
@@ -70,10 +76,12 @@ public class InputMethodMenuControllerTest extends WindowTestsBase {
Mockito.doReturn(policyProvider).when(mWm).getDisplayAreaPolicyProvider();
mController = new InputMethodMenuController(mock(InputMethodManagerService.class));
+ mSecondaryDisplay = new DualDisplayAreaGroupPolicyTest.DualDisplayContent
+ .Builder(mAtm, 1000, 1000).build();
// Mock addWindowTokenWithOptions to create a test window token.
- IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
- spyOn(wms);
+ mIWindowManager = WindowManagerGlobal.getWindowManagerService();
+ spyOn(mIWindowManager);
doAnswer(invocation -> {
Object[] args = invocation.getArguments();
IBinder clientToken = (IBinder) args[0];
@@ -83,19 +91,24 @@ public class InputMethodMenuControllerTest extends WindowTestsBase {
dc.getImeContainer(), 1000 /* ownerUid */, TYPE_INPUT_METHOD_DIALOG,
null /* options */);
return dc.getImeContainer().getConfiguration();
- }).when(wms).attachWindowContextToDisplayArea(any(), eq(TYPE_INPUT_METHOD_DIALOG),
- anyInt(), any());
-
- mSecondaryDisplay = new DualDisplayAreaGroupPolicyTest.DualDisplayContent
- .Builder(mAtm, 1000, 1000).build();
-
- // Mock DisplayManagerGlobal to return test display when obtaining Display instance.
+ }).when(mIWindowManager).attachWindowContextToDisplayArea(any(),
+ eq(TYPE_INPUT_METHOD_DIALOG), anyInt(), any());
+ mDisplayManagerGlobal = DisplayManagerGlobal.getInstance();
+ spyOn(mDisplayManagerGlobal);
final int displayId = mSecondaryDisplay.getDisplayId();
final Display display = mSecondaryDisplay.getDisplay();
- DisplayManagerGlobal displayManagerGlobal = DisplayManagerGlobal.getInstance();
- spyOn(displayManagerGlobal);
- doReturn(display).when(displayManagerGlobal).getCompatibleDisplay(eq(displayId),
+ doReturn(display).when(mDisplayManagerGlobal).getCompatibleDisplay(eq(displayId),
(Resources) any());
+ Context systemUiContext = ActivityThread.currentActivityThread()
+ .getSystemUiContext(displayId);
+ spyOn(systemUiContext);
+ doReturn(display).when(systemUiContext).getDisplay();
+ }
+
+ @After
+ public void tearDown() {
+ reset(mIWindowManager);
+ reset(mDisplayManagerGlobal);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index feb656cc6498..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
@@ -2318,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 42f4d583f5ff..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);
@@ -103,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/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 2a0aa96a00ee..88d8ba308b45 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -128,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";
@@ -1243,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;
}
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);
}
}