summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java180
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING8
-rw-r--r--cmds/idmap2/idmap2d/Idmap2Service.cpp3
-rw-r--r--cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl2
-rw-r--r--cmds/idmap2/include/idmap2/FabricatedOverlay.h14
-rw-r--r--cmds/idmap2/include/idmap2/ResourceUtils.h2
-rw-r--r--cmds/idmap2/libidmap2/FabricatedOverlay.cpp34
-rw-r--r--cmds/idmap2/self_targeting/SelfTargeting.cpp1
-rw-r--r--cmds/idmap2/tests/FabricatedOverlayTests.cpp2
-rw-r--r--cmds/idmap2/tests/IdmapTests.cpp2
-rw-r--r--cmds/idmap2/tests/ResourceMappingTests.cpp2
-rw-r--r--core/api/current.txt7
-rw-r--r--core/api/system-current.txt2
-rw-r--r--core/api/test-current.txt3
-rw-r--r--core/java/android/app/IWindowToken.aidl35
-rw-r--r--core/java/android/app/SystemServiceRegistry.java13
-rw-r--r--core/java/android/app/assist/AssistStructure.java18
-rw-r--r--core/java/android/companion/AssociationInfo.java39
-rw-r--r--core/java/android/companion/CompanionDeviceManager.java44
-rw-r--r--core/java/android/companion/ICompanionDeviceManager.aidl4
-rw-r--r--core/java/android/content/AttributionSource.java6
-rw-r--r--core/java/android/content/om/FabricatedOverlay.java61
-rw-r--r--core/java/android/content/pm/PackageInstaller.java2
-rw-r--r--core/java/android/content/pm/TEST_MAPPING21
-rw-r--r--core/java/android/content/res/Element.java37
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java9
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java9
-rw-r--r--core/java/android/net/VpnService.java11
-rw-r--r--core/java/android/os/BatteryStats.java39
-rw-r--r--core/java/android/os/GraphicsEnvironment.java34
-rw-r--r--core/java/android/os/PerformanceHintManager.java25
-rw-r--r--core/java/android/os/PowerManager.java9
-rw-r--r--core/java/android/os/TEST_MAPPING7
-rw-r--r--core/java/android/os/UserHandle.java3
-rw-r--r--core/java/android/provider/Settings.java8
-rw-r--r--core/java/android/service/selectiontoolbar/DefaultSelectionToolbarRenderService.java153
-rw-r--r--core/java/android/service/selectiontoolbar/FloatingToolbarRoot.java89
-rw-r--r--core/java/android/service/selectiontoolbar/ISelectionToolbarRenderService.aidl32
-rw-r--r--core/java/android/service/selectiontoolbar/OWNERS10
-rw-r--r--core/java/android/service/selectiontoolbar/RemoteSelectionToolbar.java1398
-rw-r--r--core/java/android/service/selectiontoolbar/SelectionToolbarRenderCallback.java49
-rw-r--r--core/java/android/service/selectiontoolbar/SelectionToolbarRenderService.java257
-rw-r--r--core/java/android/util/apk/TEST_MAPPING4
-rw-r--r--core/java/android/view/Display.java8
-rw-r--r--core/java/android/view/ViewRootImpl.java9
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java36
-rw-r--r--core/java/android/view/inputmethod/RemoteInputConnectionImpl.java12
-rw-r--r--core/java/android/view/selectiontoolbar/ISelectionToolbarCallback.aidl32
-rw-r--r--core/java/android/view/selectiontoolbar/ISelectionToolbarManager.aidl31
-rw-r--r--core/java/android/view/selectiontoolbar/OWNERS10
-rw-r--r--core/java/android/view/selectiontoolbar/SelectionToolbarManager.java122
-rw-r--r--core/java/android/view/selectiontoolbar/ShowInfo.java361
-rw-r--r--core/java/android/view/selectiontoolbar/ToolbarMenuItem.java543
-rw-r--r--core/java/android/view/selectiontoolbar/WidgetInfo.java228
-rw-r--r--core/java/android/widget/HorizontalScrollView.java5
-rw-r--r--core/java/android/widget/ScrollView.java5
-rw-r--r--core/java/android/widget/TextView.java3
-rw-r--r--core/java/android/window/IWindowOrganizerController.aidl7
-rw-r--r--core/java/android/window/WindowOrganizer.java10
-rw-r--r--core/java/android/window/WindowTokenClient.java30
-rw-r--r--core/java/android/window/WindowTokenClientController.java4
-rw-r--r--core/java/com/android/internal/accessibility/AccessibilityShortcutController.java31
-rw-r--r--core/java/com/android/internal/app/IBatteryStats.aidl3
-rw-r--r--core/java/com/android/internal/app/NetInitiatedActivity.java130
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java48
-rw-r--r--core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java6
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHistory.java14
-rw-r--r--core/java/com/android/internal/os/TEST_MAPPING11
-rw-r--r--core/java/com/android/internal/power/TEST_MAPPING6
-rw-r--r--core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbarPopup.java9
-rw-r--r--core/java/com/android/internal/widget/floatingtoolbar/RemoteFloatingToolbarPopup.java572
-rw-r--r--core/jni/android_media_AudioSystem.cpp9
-rw-r--r--core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp15
-rw-r--r--core/res/AndroidManifest.xml1
-rw-r--r--core/res/res/values/config_device_idle.xml4
-rw-r--r--core/res/res/values/config_telephony.xml1
-rw-r--r--core/res/res/values/strings.xml4
-rw-r--r--core/res/res/values/symbols.xml4
-rw-r--r--core/tests/coretests/Android.bp1
-rw-r--r--core/tests/coretests/AndroidManifest.xml22
-rw-r--r--core/tests/coretests/AndroidTest.xml1
-rw-r--r--core/tests/coretests/BstatsTestApp/OWNERS1
-rw-r--r--core/tests/coretests/res/layout/activity_horizontal_scroll_view.xml118
-rw-r--r--core/tests/coretests/res/layout/activity_scroll_view.xml118
-rw-r--r--core/tests/coretests/src/android/os/PerformanceHintManagerTest.java18
-rw-r--r--core/tests/coretests/src/android/widget/HorizontalScrollViewActivity.java34
-rw-r--r--core/tests/coretests/src/android/widget/HorizontalScrollViewFunctionalTest.java71
-rw-r--r--core/tests/coretests/src/android/widget/ScrollViewActivity.java (renamed from core/java/android/view/selectiontoolbar/ShowInfo.aidl)20
-rw-r--r--core/tests/coretests/src/android/widget/ScrollViewFunctionalTest.java71
-rw-r--r--core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java17
-rw-r--r--core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java11
-rw-r--r--core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java195
-rw-r--r--core/tests/coretests/src/com/android/internal/content/OWNERS2
-rw-r--r--core/tests/packagemonitortests/Android.bp41
-rw-r--r--core/tests/packagemonitortests/AndroidManifest.xml30
-rw-r--r--core/tests/packagemonitortests/AndroidTest.xml44
-rw-r--r--core/tests/packagemonitortests/OWNERS1
-rw-r--r--core/tests/packagemonitortests/src/com/android/internal/content/PackageMonitorTest.java (renamed from core/tests/coretests/src/com/android/internal/content/PackageMonitorTest.java)2
-rw-r--r--core/tests/packagemonitortests/src/com/android/internal/content/PackageMonitorVisibilityTest.java121
-rw-r--r--core/tests/packagemonitortests/testapp/TestVisibilityApp/Android.bp27
-rw-r--r--core/tests/packagemonitortests/testapp/TestVisibilityApp/AndroidManifest.xml27
-rw-r--r--core/tests/packagemonitortests/testapp/TestVisibilityApp/res/layout/dummy_activity.xml25
-rw-r--r--core/tests/packagemonitortests/testapp/TestVisibilityApp/res/values/strings.xml21
-rw-r--r--core/tests/packagemonitortests/testapp/TestVisibilityApp/src/com/example/android/testvisibilityapp/DummyActivity.java31
-rw-r--r--data/etc/com.android.systemui.xml1
-rw-r--r--graphics/java/android/graphics/ColorSpace.java19
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java20
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java18
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java18
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java49
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java28
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java33
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java28
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/LegacySizeSpecSource.kt202
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PhoneSizeSpecSource.kt252
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/SizeSpecSource.kt51
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java32
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java20
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipDisplayLayoutState.java47
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java19
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java536
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java23
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java29
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java40
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/SleepHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java25
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java12
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java281
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java15
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java8
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java11
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhoneSizeSpecSourceTest.java (renamed from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java)40
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java11
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java16
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipGravityTest.java11
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java41
-rw-r--r--libs/androidfw/include/androidfw/ResourceTypes.h2
-rw-r--r--libs/hwui/OWNERS2
-rw-r--r--libs/hwui/Tonemapper.cpp12
-rw-r--r--location/TEST_MAPPING10
-rw-r--r--location/java/android/location/LocationManagerInternal.java6
-rw-r--r--location/java/com/android/internal/location/GpsNetInitiatedHandler.java483
-rw-r--r--media/java/android/media/AudioManager.java108
-rw-r--r--media/java/android/media/IAudioService.aidl6
-rw-r--r--media/java/android/media/session/MediaSession.java1
-rw-r--r--media/tests/mediatestutils/Android.bp53
-rw-r--r--media/tests/mediatestutils/OWNERS4
-rw-r--r--media/tests/mediatestutils/TEST_MAPPING7
-rw-r--r--media/tests/mediatestutils/java/com/android/media/mediatestutils/CancelAllFuturesRule.java51
-rw-r--r--media/tests/mediatestutils/java/com/android/media/mediatestutils/TestUtils.java119
-rw-r--r--media/tests/mediatestutils/javatests/com/android/media/mediatestutils/CancelAllFuturesRuleTest.java120
-rw-r--r--media/tests/mediatestutils/tests/Android.bp22
-rw-r--r--media/tests/mediatestutils/tests/AndroidManifest.xml30
-rw-r--r--media/tests/mediatestutils/tests/src/java/com/android/media/mediatestutils/GetFutureForIntentTest.java156
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java10
-rw-r--r--packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt2
-rw-r--r--packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppInfoTest.kt4
-rw-r--r--packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt76
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java1
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java3
-rw-r--r--packages/SystemUI/Android.bp17
-rw-r--r--packages/SystemUI/AndroidManifest.xml2
-rw-r--r--packages/SystemUI/compose/core/OWNERS12
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/activity/EdgeToEdgeActivitContent.kt61
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/ExampleFeature.kt94
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt12
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt12
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt6
-rw-r--r--packages/SystemUI/compose/features/tests/src/com/android/systemui/ExampleFeatureTest.kt46
-rw-r--r--packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml10
-rw-r--r--packages/SystemUI/res/layout/combined_qs_header.xml3
-rw-r--r--packages/SystemUI/res/layout/keyguard_bottom_area.xml36
-rw-r--r--packages/SystemUI/res/layout/log_access_user_consent_dialog_permission.xml96
-rw-r--r--packages/SystemUI/res/layout/media_projection_app_selector.xml6
-rw-r--r--packages/SystemUI/res/layout/status_bar.xml9
-rw-r--r--packages/SystemUI/res/values/dimens.xml23
-rw-r--r--packages/SystemUI/res/values/flags.xml2
-rw-r--r--packages/SystemUI/res/values/ids.xml1
-rw-r--r--packages/SystemUI/res/values/strings.xml7
-rw-r--r--packages/SystemUI/res/values/styles.xml5
-rw-r--r--packages/SystemUI/res/xml/qs_header.xml1
-rw-r--r--packages/SystemUI/shared/res/values-my/bools.xml25
-rw-r--r--packages/SystemUI/shared/res/values/bools.xml25
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt86
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt12
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/flags/FlagSettingsHelper.kt1
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java8
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextClock.kt64
-rw-r--r--packages/SystemUI/src-debug/com/android/systemui/flags/FlagsFactory.kt12
-rw-r--r--packages/SystemUI/src-release/com/android/systemui/flags/FlagsFactory.kt12
-rw-r--r--packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt5
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java1
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java57
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt10
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java17
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java33
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java34
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java37
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/aconfig/AConfigModule.kt (renamed from core/java/android/view/selectiontoolbar/ToolbarMenuItem.aidl)23
-rw-r--r--packages/SystemUI/src/com/android/systemui/aconfig/systemui.aconfig8
-rw-r--r--packages/SystemUI/src/com/android/systemui/authentication/data/model/AuthenticationMethodModel.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt99
-rw-r--r--packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt100
-rw-r--r--packages/SystemUI/src/com/android/systemui/authentication/domain/model/AuthenticationMethodModel.kt (renamed from packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt)9
-rw-r--r--packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationPatternCoordinate.kt (renamed from core/java/android/view/selectiontoolbar/WidgetInfo.aidl)12
-rw-r--r--packages/SystemUI/src/com/android/systemui/battery/AccessorizedBatteryDrawable.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/controller/UdfpsKeyguardViewController.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt85
-rw-r--r--packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java83
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt329
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt44
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt42
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt68
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt46
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeGuidelines.kt45
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt48
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt51
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionBlockerEmptyStateProvider.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java98
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.kt99
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/ui/view/PeopleViewBinder.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt70
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt141
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt103
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneTransitionModel.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt42
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt33
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/DisplayTracker.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/DisplayTrackerImpl.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java68
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeQsExpansionFractionListener.kt (renamed from core/java/android/service/selectiontoolbar/ISelectionToolbarRenderServiceCallback.aidl)17
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImpl.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/DebugModeFilterProvider.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSettingsController.java180
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoModeWifiDataSource.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/model/FakeWifiEventModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryHelper.kt80
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt46
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLib.kt115
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModel.kt55
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateView.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateViewController.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/IListenerSet.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/ListenerSet.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/NamedListenerSet.kt96
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/Utils.java4
-rw-r--r--packages/SystemUI/tests/src/android/animation/AnimatorTestRuleIsolationTest.kt2
-rw-r--r--packages/SystemUI/tests/src/android/animation/AnimatorTestRulePrecisionTest.kt2
-rw-r--r--packages/SystemUI/tests/src/androidx/core/animation/AnimatorTestRuleIsolationTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt89
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java105
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java59
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/AnimatorTestRuleOrderTest.kt183
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt49
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt137
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt33
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt52
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt28
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt28
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt63
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt111
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt172
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSectionTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt28
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerControllerTest.java47
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt135
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt192
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt226
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt158
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt41
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt41
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt88
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt89
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java71
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSettingsControllerTest.kt248
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/MultiSourceMinAlphaControllerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLibTest.kt431
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java44
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/VariableDateViewControllerTest.kt50
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/ListenerSetTest.kt133
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/NamedListenerSetTest.kt104
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java12
-rw-r--r--packages/SystemUI/tests/utils/src/android/animation/AnimatorTestRule.java32
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/animation/AnimatorTestRule.kt58
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt23
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt76
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt10
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt18
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeDisplayTracker.kt10
-rw-r--r--services/Android.bp2
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java10
-rw-r--r--services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java6
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java13
-rw-r--r--services/companion/java/com/android/server/companion/PersistentDataStore.java22
-rw-r--r--services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java27
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java9
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java7
-rw-r--r--services/core/java/com/android/server/TEST_MAPPING8
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java20
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java30
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java34
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java6
-rw-r--r--services/core/java/com/android/server/am/BroadcastConstants.java6
-rw-r--r--services/core/java/com/android/server/am/ContentProviderHelper.java5
-rw-r--r--services/core/java/com/android/server/am/DataConnectionStats.java7
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java1272
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.md25
-rw-r--r--services/core/java/com/android/server/am/OomAdjusterModernImpl.java1125
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java10
-rw-r--r--services/core/java/com/android/server/am/ProcessServiceRecord.java44
-rw-r--r--services/core/java/com/android/server/am/ProcessStateRecord.java31
-rw-r--r--services/core/java/com/android/server/am/TEST_MAPPING26
-rw-r--r--services/core/java/com/android/server/audio/AdiDeviceState.java51
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java29
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceInventory.java116
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java71
-rw-r--r--services/core/java/com/android/server/audio/SoundDoseHelper.java54
-rw-r--r--services/core/java/com/android/server/audio/SpatializerHelper.java4
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java7
-rw-r--r--services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java4
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java15
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceConfig.java45
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java3
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController2.java14
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java3
-rw-r--r--services/core/java/com/android/server/input/KeyboardLayoutManager.java17
-rw-r--r--services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java23
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodBindingController.java6
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java9
-rw-r--r--services/core/java/com/android/server/location/LocationManagerService.java7
-rw-r--r--services/core/java/com/android/server/location/TEST_MAPPING10
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssLocationProvider.java102
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssManagerService.java12
-rw-r--r--services/core/java/com/android/server/location/gnss/hal/GnssNative.java27
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java2
-rw-r--r--services/core/java/com/android/server/notification/NotificationComparator.java12
-rw-r--r--services/core/java/com/android/server/pm/ComputerEngine.java1
-rw-r--r--services/core/java/com/android/server/pm/DeletePackageHelper.java1
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java5
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java133
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerInternalBase.java7
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java7
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java111
-rw-r--r--services/core/java/com/android/server/pm/RemovePackageHelper.java8
-rw-r--r--services/core/java/com/android/server/pm/ScanPackageUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/Settings.java51
-rw-r--r--services/core/java/com/android/server/pm/TEST_MAPPING15
-rw-r--r--services/core/java/com/android/server/pm/dex/ArtManagerService.java8
-rw-r--r--services/core/java/com/android/server/pm/dex/ViewCompiler.java11
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java14
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java54
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java40
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java69
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java56
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java62
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java37
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageState.java11
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageStateImpl.java759
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java151
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java3
-rw-r--r--services/core/java/com/android/server/power/TEST_MAPPING13
-rw-r--r--services/core/java/com/android/server/power/batterysaver/TEST_MAPPING8
-rw-r--r--services/core/java/com/android/server/power/hint/HintManagerService.java30
-rw-r--r--services/core/java/com/android/server/power/stats/BatteryStatsImpl.java77
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java7
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java3
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java43
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java14
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java9
-rw-r--r--services/core/java/com/android/server/wm/Transition.java29
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowContextListenerController.java44
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java32
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java36
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp68
-rw-r--r--services/incremental/TEST_MAPPING4
-rw-r--r--services/java/com/android/server/SystemServer.java9
-rw-r--r--services/permission/java/com/android/server/permission/access/AccessPolicy.kt2
-rw-r--r--services/permission/java/com/android/server/permission/access/AccessState.kt23
-rw-r--r--services/permission/java/com/android/server/permission/access/AccessUri.kt11
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/DevicePermissionPersistence.kt169
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt276
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/PermissionService.kt179
-rw-r--r--services/selectiontoolbar/Android.bp22
-rw-r--r--services/selectiontoolbar/OWNERS1
-rw-r--r--services/selectiontoolbar/java/com/android/server/selectiontoolbar/RemoteSelectionToolbarRenderService.java84
-rw-r--r--services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarManagerService.java104
-rw-r--r--services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarManagerServiceImpl.java151
-rw-r--r--services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarServiceNameResolver.java45
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java25
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt3
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java460
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java35
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java13
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java71
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java65
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java3
-rw-r--r--services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java18
-rw-r--r--services/tests/powerstatstests/Android.bp52
-rw-r--r--services/tests/powerstatstests/AndroidManifest.xml32
-rw-r--r--services/tests/powerstatstests/AndroidTest.xml35
-rw-r--r--services/tests/powerstatstests/BstatsTestApp/Android.bp (renamed from core/tests/coretests/BstatsTestApp/Android.bp)0
-rw-r--r--services/tests/powerstatstests/BstatsTestApp/AndroidManifest.xml (renamed from core/tests/coretests/BstatsTestApp/AndroidManifest.xml)0
-rw-r--r--services/tests/powerstatstests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/BaseCmdReceiver.java (renamed from core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/BaseCmdReceiver.java)0
-rw-r--r--services/tests/powerstatstests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/Common.java (renamed from core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/Common.java)4
-rw-r--r--services/tests/powerstatstests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/IsolatedTestService.java (renamed from core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/IsolatedTestService.java)0
-rw-r--r--services/tests/powerstatstests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestActivity.java (renamed from core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestActivity.java)0
-rw-r--r--services/tests/powerstatstests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java (renamed from core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java)0
-rw-r--r--services/tests/powerstatstests/OWNERS (renamed from services/tests/servicestests/src/com/android/server/powerstats/OWNERS)3
-rw-r--r--services/tests/powerstatstests/TEST_MAPPING22
-rw-r--r--services/tests/powerstatstests/res/xml/irq_device_map_1.xml (renamed from services/tests/servicestests/res/xml/irq_device_map_1.xml)0
-rw-r--r--services/tests/powerstatstests/res/xml/irq_device_map_2.xml (renamed from services/tests/servicestests/res/xml/irq_device_map_2.xml)0
-rw-r--r--services/tests/powerstatstests/res/xml/irq_device_map_3.xml (renamed from services/tests/servicestests/res/xml/irq_device_map_3.xml)0
-rw-r--r--services/tests/powerstatstests/res/xml/power_profile_test_legacy_modem.xml (renamed from services/tests/servicestests/res/xml/power_profile_test_legacy_modem.xml)0
-rw-r--r--services/tests/powerstatstests/res/xml/power_profile_test_modem_calculator.xml (renamed from services/tests/servicestests/res/xml/power_profile_test_modem_calculator.xml)0
-rw-r--r--services/tests/powerstatstests/res/xml/power_profile_test_modem_calculator_multiactive.xml (renamed from services/tests/servicestests/res/xml/power_profile_test_modem_calculator_multiactive.xml)0
-rw-r--r--services/tests/powerstatstests/res/xml/power_profile_test_modem_default.xml (renamed from services/tests/servicestests/res/xml/power_profile_test_modem_default.xml)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/AmbientDisplayPowerCalculatorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/AmbientDisplayPowerCalculatorTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/AudioPowerCalculatorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/AudioPowerCalculatorTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryChargeCalculatorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryChargeCalculatorTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsBackgroundStatsTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsBackgroundStatsTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsBinderCallStatsTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsBinderCallStatsTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsCounterTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsCounterTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsCpuTimesTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsCpuTimesTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsDualTimerTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsDualTimerTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsDurationTimerTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsDurationTimerTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java)110
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsImplTest.java)2
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsManagerTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsManagerTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsNoteTest.java)17
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsResetTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsSamplingTimerTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsSamplingTimerTest.java)16
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsSensorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsSensorTest.java)16
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsServTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsServTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsStopwatchTimerTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsStopwatchTimerTest.java)16
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsTimeBaseTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsTimeBaseTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsTimerTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsTimerTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsUserLifecycleTests.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsUserLifecycleTests.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryUsageStatsRule.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsStoreTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryUsageStatsStoreTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BatteryUsageStatsTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BluetoothPowerCalculatorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BluetoothPowerCalculatorTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/BstatsCpuTimesValidationTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/BstatsCpuTimesValidationTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/CameraPowerCalculatorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/CameraPowerCalculatorTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerCalculatorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/CpuPowerCalculatorTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/CustomEnergyConsumerPowerCalculatorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/CustomEnergyConsumerPowerCalculatorTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/EnergyConsumerSnapshotTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/EnergyConsumerSnapshotTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/FlashlightPowerCalculatorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/FlashlightPowerCalculatorTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/GnssPowerCalculatorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/GnssPowerCalculatorTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/IdlePowerCalculatorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/IdlePowerCalculatorTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/KernelWakelockReaderTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/KernelWakelockReaderTest.java)16
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/LongSamplingCounterArrayTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/LongSamplingCounterArrayTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/LongSamplingCounterTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/LongSamplingCounterTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/MemoryPowerCalculatorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/MemoryPowerCalculatorTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java)2
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/MockBatteryStatsImpl.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/MockClock.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/MockClock.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/OWNERS (renamed from services/tests/servicestests/src/com/android/server/power/stats/OWNERS)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/ScreenPowerCalculatorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/ScreenPowerCalculatorTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/SensorPowerCalculatorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/SensorPowerCalculatorTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/SystemServerCpuThreadReaderTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/SystemServerCpuThreadReaderTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/UserPowerCalculatorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/UserPowerCalculatorTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/VideoPowerCalculatorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/VideoPowerCalculatorTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerCalculatorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/WakelockPowerCalculatorTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerCalculatorTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/WifiPowerCalculatorTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/wakeups/CpuWakeupStatsTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/wakeups/CpuWakeupStatsTest.java)2
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/wakeups/IrqDeviceMapTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/wakeups/IrqDeviceMapTest.java)2
-rw-r--r--services/tests/powerstatstests/src/com/android/server/power/stats/wakeups/WakingActivityHistoryTest.java (renamed from services/tests/servicestests/src/com/android/server/power/stats/wakeups/WakingActivityHistoryTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/powerstats/IntervalRandomNoiseGeneratorTest.java (renamed from services/tests/servicestests/src/com/android/server/powerstats/IntervalRandomNoiseGeneratorTest.java)0
-rw-r--r--services/tests/powerstatstests/src/com/android/server/powerstats/PowerStatsServiceTest.java (renamed from services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java)0
-rw-r--r--services/tests/servicestests/Android.bp2
-rw-r--r--services/tests/servicestests/AndroidTest.xml1
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java132
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/display/TestUtils.java94
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt33
-rw-r--r--services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsTests.java72
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java37
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java9
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java44
-rw-r--r--services/usage/java/com/android/server/usage/TEST_MAPPING13
-rw-r--r--telecomm/java/android/telecom/Call.java4
-rw-r--r--telecomm/java/android/telecom/Phone.java3
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java1
-rw-r--r--telephony/java/android/telephony/NetworkRegistrationInfo.java10
-rw-r--r--tests/CompanionDeviceMultiDeviceTests/host/Android.bp1
-rw-r--r--tests/CompanionDeviceMultiDeviceTests/host/cdm_transport_test.py8
-rw-r--r--tests/CompanionDeviceMultiDeviceTests/host/requirements.txt1
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt32
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt88
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt2
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt2
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt2
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt2
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/Android.bp3
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml11
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/drawable/avd_anim.xml94
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml7
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java6
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/TransferSplashscreenActivity.java52
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java38
-rw-r--r--tests/testables/src/android/testing/TestableResources.java12
641 files changed, 13961 insertions, 12041 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 76d1935be563..1be07fdfcceb 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -79,6 +79,7 @@ import android.os.ShellCommand;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
+import android.os.WearModeManagerInternal;
import android.provider.DeviceConfig;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
@@ -126,6 +127,7 @@ import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
@@ -373,10 +375,9 @@ public class DeviceIdleController extends SystemService
@GuardedBy("this")
private boolean mBatterySaverEnabled;
@GuardedBy("this")
- private boolean mIsOffBody;
+ private boolean mModeManagerRequestedQuickDoze;
@GuardedBy("this")
- private boolean mForceBodyState;
- private Sensor mOffBodySensor;
+ private boolean mForceModeManagerQuickDozeRequest;
/** Time in the elapsed realtime timebase when this listener last received a motion event. */
@GuardedBy("this")
@@ -435,7 +436,7 @@ public class DeviceIdleController extends SystemService
private static final int ACTIVE_REASON_FORCED = 6;
private static final int ACTIVE_REASON_ALARM = 7;
private static final int ACTIVE_REASON_EMERGENCY_CALL = 8;
- private static final int ACTIVE_REASON_ONBODY = 9;
+ private static final int ACTIVE_REASON_MODE_MANAGER = 9;
@VisibleForTesting
static String stateToString(int state) {
@@ -832,64 +833,35 @@ public class DeviceIdleController extends SystemService
}
}
- /**
- * LowLatencyOffBodyListener monitors if a device is on body or off body.
- */
@VisibleForTesting
- final class LowLatencyOffBodyListener implements SensorEventListener {
+ class ModeManagerQuickDozeRequestConsumer implements Consumer<Boolean> {
@Override
- public void onSensorChanged(SensorEvent event) {
- if (DEBUG) {
- Slog.d(TAG, "LowLatencyOffBodyListener detects onSensorChanged event, values are: "
- + Arrays.toString(event.values));
- }
- if (event.values == null || event.values.length == 0) {
- // The event returned should contain a single value to indicate off-body state.
- // No value indicates something went wrong. Take no action and log an error.
- Slog.e(TAG,
- "LowLatencyOffBodyListener detects onSensorChanged event but no event "
- + "value returns.");
- return;
- }
+ public void accept(Boolean enabled) {
+ Slog.d(TAG, "Mode manager quick doze request: " + enabled);
synchronized (DeviceIdleController.this) {
- final boolean isOffBody = (event.values[0] == 0);
- if (!mForceBodyState && mIsOffBody != isOffBody) {
- // Only consider the sensor value change when mForceBodyState is false, which
- // is used to enforce the mIsOffBody to be set by the adb shell command.
- mIsOffBody = isOffBody;
- onOffBodyChangedLocked();
+ if (!mForceModeManagerQuickDozeRequest
+ && mModeManagerRequestedQuickDoze != enabled) {
+ mModeManagerRequestedQuickDoze = enabled;
+ onModeManagerRequestChangedLocked();
}
}
}
@GuardedBy("DeviceIdleController.this")
- public void onOffBodyChangedLocked() {
- // Get into quick doze faster when the device is off body instead of taking
+ public void onModeManagerRequestChangedLocked() {
+ // Get into quick doze faster when mode manager requests instead of taking
// traditional multi-stage approach.
updateQuickDozeFlagLocked();
- if (!mIsOffBody && !mBatterySaverEnabled) {
- mActiveReason = ACTIVE_REASON_ONBODY;
- becomeActiveLocked("onbody", Process.myUid());
+ if (!mModeManagerRequestedQuickDoze && !mBatterySaverEnabled) {
+ mActiveReason = ACTIVE_REASON_MODE_MANAGER;
+ becomeActiveLocked("mode_manager", Process.myUid());
}
}
-
- @Override
- public void onAccuracyChanged(Sensor sensor, int accuracy) {}
-
- public void registerLocked() {
- mOffBodySensor =
- mSensorManager.getDefaultSensor(Sensor.TYPE_LOW_LATENCY_OFFBODY_DETECT, true);
- if (mOffBodySensor == null) {
- Slog.w(TAG, "Body sensor is NULL, unable to register mOffBodySensor.");
- return;
- }
- mSensorManager.registerListener(this, mOffBodySensor,
- SensorManager.SENSOR_DELAY_NORMAL);
- }
}
@VisibleForTesting
- final LowLatencyOffBodyListener mLowLatencyOffBodyListener = new LowLatencyOffBodyListener();
+ final ModeManagerQuickDozeRequestConsumer mModeManagerQuickDozeRequestConsumer =
+ new ModeManagerQuickDozeRequestConsumer();
@VisibleForTesting
final class MotionListener extends TriggerEventListener
@@ -1052,7 +1024,7 @@ public class DeviceIdleController extends SystemService
*/
private static final String KEY_WAIT_FOR_UNLOCK = "wait_for_unlock";
private static final String KEY_USE_WINDOW_ALARMS = "use_window_alarms";
- private static final String KEY_USE_BODY_SENSOR = "use_body_sensor";
+ private static final String KEY_USE_MODE_MANAGER = "use_mode_manager";
private long mDefaultFlexTimeShort =
!COMPRESS_TIME ? 60 * 1000L : 5 * 1000L;
@@ -1112,7 +1084,7 @@ public class DeviceIdleController extends SystemService
private long mDefaultNotificationAllowlistDurationMs = 30 * 1000L;
private boolean mDefaultWaitForUnlock = true;
private boolean mDefaultUseWindowAlarms = true;
- private boolean mDefaultUseBodySensor = false;
+ private boolean mDefaultUseModeManager = false;
/**
* A somewhat short alarm window size that we will tolerate for various alarm timings.
@@ -1356,7 +1328,7 @@ public class DeviceIdleController extends SystemService
/**
* Whether to use an on/off body signal to affect state transition policy.
*/
- public boolean USE_BODY_SENSOR = mDefaultUseBodySensor;
+ public boolean USE_MODE_MANAGER = mDefaultUseModeManager;
private final boolean mSmallBatteryDevice;
@@ -1464,8 +1436,8 @@ public class DeviceIdleController extends SystemService
com.android.internal.R.bool.device_idle_wait_for_unlock);
mDefaultUseWindowAlarms = res.getBoolean(
com.android.internal.R.bool.device_idle_use_window_alarms);
- mDefaultUseBodySensor = res.getBoolean(
- com.android.internal.R.bool.device_idle_use_body_sensor);
+ mDefaultUseModeManager = res.getBoolean(
+ com.android.internal.R.bool.device_idle_use_mode_manager);
FLEX_TIME_SHORT = mDefaultFlexTimeShort;
LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = mDefaultLightIdleAfterInactiveTimeout;
@@ -1499,7 +1471,7 @@ public class DeviceIdleController extends SystemService
NOTIFICATION_ALLOWLIST_DURATION_MS = mDefaultNotificationAllowlistDurationMs;
WAIT_FOR_UNLOCK = mDefaultWaitForUnlock;
USE_WINDOW_ALARMS = mDefaultUseWindowAlarms;
- USE_BODY_SENSOR = mDefaultUseBodySensor;
+ USE_MODE_MANAGER = mDefaultUseModeManager;
}
private long getTimeout(long defTimeout, long compTimeout) {
@@ -1661,9 +1633,9 @@ public class DeviceIdleController extends SystemService
USE_WINDOW_ALARMS = properties.getBoolean(
KEY_USE_WINDOW_ALARMS, mDefaultUseWindowAlarms);
break;
- case KEY_USE_BODY_SENSOR:
- USE_BODY_SENSOR = properties.getBoolean(
- KEY_USE_BODY_SENSOR, mDefaultUseBodySensor);
+ case KEY_USE_MODE_MANAGER:
+ USE_MODE_MANAGER = properties.getBoolean(
+ KEY_USE_MODE_MANAGER, mDefaultUseModeManager);
break;
default:
Slog.e(TAG, "Unknown configuration key: " + name);
@@ -1802,8 +1774,8 @@ public class DeviceIdleController extends SystemService
pw.print(" "); pw.print(KEY_USE_WINDOW_ALARMS); pw.print("=");
pw.println(USE_WINDOW_ALARMS);
- pw.print(" "); pw.print(KEY_USE_BODY_SENSOR); pw.print("=");
- pw.println(USE_BODY_SENSOR);
+ pw.print(" "); pw.print(KEY_USE_MODE_MANAGER); pw.print("=");
+ pw.println(USE_MODE_MANAGER);
}
}
@@ -2668,8 +2640,15 @@ public class DeviceIdleController extends SystemService
mPowerSaveWhitelistAllAppIdArray, mPowerSaveWhitelistExceptIdleAppIdArray);
mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
- if (mConstants.USE_BODY_SENSOR) {
- mLowLatencyOffBodyListener.registerLocked();
+ if (mConstants.USE_MODE_MANAGER) {
+ WearModeManagerInternal modeManagerInternal = LocalServices.getService(
+ WearModeManagerInternal.class);
+ if (modeManagerInternal != null) {
+ modeManagerInternal.addActiveStateChangeListener(
+ WearModeManagerInternal.QUICK_DOZE_REQUEST_IDENTIFIER,
+ AppSchedulingModuleThread.getExecutor(),
+ mModeManagerQuickDozeRequestConsumer);
+ }
}
mLocalPowerManager.registerLowPowerModeObserver(ServiceType.QUICK_DOZE,
state -> {
@@ -3374,9 +3353,10 @@ public class DeviceIdleController extends SystemService
/** Calls to {@link #updateQuickDozeFlagLocked(boolean)} by considering appropriate signals. */
@GuardedBy("this")
private void updateQuickDozeFlagLocked() {
- if (mConstants.USE_BODY_SENSOR) {
- // Only disable the quick doze flag when the device is on body and battery saver is off.
- updateQuickDozeFlagLocked(mIsOffBody || mBatterySaverEnabled);
+ if (mConstants.USE_MODE_MANAGER) {
+ // Only disable the quick doze flag when mode manager request is false and
+ // battery saver is off.
+ updateQuickDozeFlagLocked(mModeManagerRequestedQuickDoze || mBatterySaverEnabled);
} else {
updateQuickDozeFlagLocked(mBatterySaverEnabled);
}
@@ -4482,7 +4462,7 @@ public class DeviceIdleController extends SystemService
pw.println(" unforce");
pw.println(
" Resume normal functioning after force-idle or force-inactive or "
- + "force-offbody or force-onbody.");
+ + "force-modemanager-quickdoze.");
pw.println(" get [light|deep|force|screen|charging|network|offbody|forcebodystate]");
pw.println(" Retrieve the current given state.");
pw.println(" disable [light|deep|all]");
@@ -4517,14 +4497,9 @@ public class DeviceIdleController extends SystemService
+ "and any [-d] is ignored");
pw.println(" motion");
pw.println(" Simulate a motion event to bring the device out of deep doze");
- pw.println(" force-offbody");
- pw.println(
- " Simulate a low latency body sensor detecting a device is offbody. "
- + "mForceBodyState will be set to true to ignore body sensor reading.");
- pw.println(" force-onbody");
- pw.println(
- " Simulate a low latency body sensor detecting a device is onbody. "
- + "mForceBodyState will be set to true to ignore body sensor reading.");
+ pw.println(" force-modemanager-quickdoze [true|false]");
+ pw.println(" Simulate mode manager request to enable (true) or disable (false) "
+ + "quick doze. Mode manager changes will be ignored until unforce is called.");
}
class Shell extends ShellCommand {
@@ -4656,8 +4631,9 @@ public class DeviceIdleController extends SystemService
pw.print(lightStateToString(mLightState));
pw.print(", deep state: ");
pw.println(stateToString(mState));
- mForceBodyState = false;
- pw.println("mForceBodyState: " + mForceBodyState);
+ mForceModeManagerQuickDozeRequest = false;
+ pw.println("mForceModeManagerQuickDozeRequest: "
+ + mForceModeManagerQuickDozeRequest);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -4678,8 +4654,12 @@ public class DeviceIdleController extends SystemService
case "screen": pw.println(mScreenOn); break;
case "charging": pw.println(mCharging); break;
case "network": pw.println(mNetworkConnected); break;
- case "offbody": pw.println(mIsOffBody); break;
- case "forcebodystate": pw.println(mForceBodyState); break;
+ case "modemanagerquick":
+ pw.println(mModeManagerRequestedQuickDoze);
+ break;
+ case "forcemodemanagerquick":
+ pw.println(mForceModeManagerQuickDozeRequest);
+ break;
default: pw.println("Unknown get option: " + arg); break;
}
} finally {
@@ -4976,35 +4956,31 @@ public class DeviceIdleController extends SystemService
Binder.restoreCallingIdentity(token);
}
}
- } else if ("force-offbody".equals(cmd)) {
- getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
- null);
- synchronized (DeviceIdleController.this) {
- final long token = Binder.clearCallingIdentity();
- try {
- mForceBodyState = true;
- pw.println("mForceBodyState: " + mForceBodyState);
- mIsOffBody = true;
- pw.println("mIsOffBody: " + mIsOffBody);
- mLowLatencyOffBodyListener.onOffBodyChangedLocked();
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
- } else if ("force-onbody".equals(cmd)) {
+ } else if ("force-modemanager-quickdoze".equals(cmd)) {
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
null);
- synchronized (DeviceIdleController.this) {
- final long token = Binder.clearCallingIdentity();
- try {
- mForceBodyState = true;
- pw.println("mForceBodyState: " + mForceBodyState);
- mIsOffBody = false;
- pw.println("mIsOffBody: " + mIsOffBody);
- mLowLatencyOffBodyListener.onOffBodyChangedLocked();
- } finally {
- Binder.restoreCallingIdentity(token);
+ String arg = shell.getNextArg();
+
+ if ("true".equalsIgnoreCase(arg) || "false".equalsIgnoreCase(arg)) {
+ boolean enabled = Boolean.parseBoolean(arg);
+
+ synchronized (DeviceIdleController.this) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mForceModeManagerQuickDozeRequest = true;
+ pw.println("mForceModeManagerQuickDozeRequest: "
+ + mForceModeManagerQuickDozeRequest);
+ mModeManagerRequestedQuickDoze = enabled;
+ pw.println("mModeManagerRequestedQuickDoze: "
+ + mModeManagerRequestedQuickDoze);
+ mModeManagerQuickDozeRequestConsumer.onModeManagerRequestChangedLocked();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
+ } else {
+ pw.println("Provide true or false argument after force-modemanager-quickdoze");
+ return -1;
}
} else {
return shell.handleDefaultCommands(cmd);
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
index 6a4a52a5658b..9ec799f73b41 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
@@ -4,7 +4,6 @@
"name": "CtsUsageStatsTestCases",
"options": [
{"include-filter": "android.app.usage.cts.UsageStatsTest"},
- {"include-filter": "android.app.usage.cts.BroadcastResponseStatsTest"},
{"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
{"exclude-annotation": "androidx.test.filters.FlakyTest"},
{"exclude-annotation": "androidx.test.filters.MediumTest"},
@@ -12,6 +11,13 @@
]
},
{
+ "name": "CtsBRSTestCases",
+ "options": [
+ {"exclude-annotation": "androidx.test.filters.FlakyTest"},
+ {"exclude-annotation": "org.junit.Ignore"}
+ ]
+ },
+ {
"name": "FrameworksServicesTests",
"options": [
{"include-filter": "com.android.server.usage"},
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index b94b3b458065..d76ca5bdce42 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -265,7 +265,8 @@ Status Idmap2Service::createFabricatedOverlay(
res.configuration.value_or(std::string()));
} else if (res.binaryData.has_value()) {
builder.SetResourceValue(res.resourceName, res.binaryData->get(),
- res.configuration.value_or(std::string()));
+ res.binaryDataOffset, res.binaryDataSize,
+ res.configuration.value_or(std::string()));
} else {
builder.SetResourceValue(res.resourceName, res.dataType, res.data,
res.configuration.value_or(std::string()));
diff --git a/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl b/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl
index 3ad6d58e8253..8ebd454705f0 100644
--- a/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl
+++ b/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl
@@ -26,4 +26,6 @@ parcelable FabricatedOverlayInternalEntry {
@nullable @utf8InCpp String stringData;
@nullable ParcelFileDescriptor binaryData;
@nullable @utf8InCpp String configuration;
+ long binaryDataOffset;
+ long binaryDataSize;
} \ No newline at end of file
diff --git a/cmds/idmap2/include/idmap2/FabricatedOverlay.h b/cmds/idmap2/include/idmap2/FabricatedOverlay.h
index a29fa8f3e1ab..1e7d4c28f45c 100644
--- a/cmds/idmap2/include/idmap2/FabricatedOverlay.h
+++ b/cmds/idmap2/include/idmap2/FabricatedOverlay.h
@@ -49,6 +49,8 @@ struct FabricatedOverlay {
Builder& SetResourceValue(const std::string& resource_name,
std::optional<android::base::borrowed_fd>&& binary_value,
+ off64_t data_binary_offset,
+ size_t data_binary_size,
const std::string& configuration);
inline Builder& setFrroPath(std::string frro_path) {
@@ -65,6 +67,8 @@ struct FabricatedOverlay {
DataValue data_value;
std::string data_string_value;
std::optional<android::base::borrowed_fd> data_binary_value;
+ off64_t data_binary_offset;
+ size_t data_binary_size;
std::string configuration;
};
@@ -76,6 +80,12 @@ struct FabricatedOverlay {
std::vector<Entry> entries_;
};
+ struct BinaryData {
+ android::base::borrowed_fd file_descriptor;
+ off64_t offset;
+ size_t size;
+ };
+
Result<Unit> ToBinaryStream(std::ostream& stream) const;
static Result<FabricatedOverlay> FromBinaryStream(std::istream& stream);
@@ -92,13 +102,13 @@ struct FabricatedOverlay {
explicit FabricatedOverlay(pb::FabricatedOverlay&& overlay,
std::string&& string_pool_data_,
- std::vector<android::base::borrowed_fd> binary_files_,
+ std::vector<FabricatedOverlay::BinaryData> binary_files_,
off_t total_binary_bytes_,
std::optional<uint32_t> crc_from_disk = {});
pb::FabricatedOverlay overlay_pb_;
std::string string_pool_data_;
- std::vector<android::base::borrowed_fd> binary_files_;
+ std::vector<FabricatedOverlay::BinaryData> binary_files_;
uint32_t total_binary_bytes_;
std::optional<uint32_t> crc_from_disk_;
mutable std::optional<SerializedData> data_;
diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h
index c2b0abed442c..d4490ef47b25 100644
--- a/cmds/idmap2/include/idmap2/ResourceUtils.h
+++ b/cmds/idmap2/include/idmap2/ResourceUtils.h
@@ -43,6 +43,8 @@ struct TargetValue {
DataValue data_value;
std::string data_string_value;
std::optional<android::base::borrowed_fd> data_binary_value;
+ off64_t data_binary_offset;
+ size_t data_binary_size;
};
struct TargetValueWithConfig {
diff --git a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
index dd5be21cd164..47daf23c6381 100644
--- a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
+++ b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
@@ -55,7 +55,7 @@ void Write32(std::ostream& stream, uint32_t value) {
FabricatedOverlay::FabricatedOverlay(pb::FabricatedOverlay&& overlay,
std::string&& string_pool_data,
- std::vector<android::base::borrowed_fd> binary_files,
+ std::vector<FabricatedOverlay::BinaryData> binary_files,
off_t total_binary_bytes,
std::optional<uint32_t> crc_from_disk)
: overlay_pb_(std::forward<pb::FabricatedOverlay>(overlay)),
@@ -81,7 +81,7 @@ FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue(
const std::string& resource_name, uint8_t data_type, uint32_t data_value,
const std::string& configuration) {
entries_.emplace_back(
- Entry{resource_name, data_type, data_value, "", std::nullopt, configuration});
+ Entry{resource_name, data_type, data_value, "", std::nullopt, 0, 0, configuration});
return *this;
}
@@ -89,14 +89,15 @@ FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue(
const std::string& resource_name, uint8_t data_type, const std::string& data_string_value,
const std::string& configuration) {
entries_.emplace_back(
- Entry{resource_name, data_type, 0, data_string_value, std::nullopt, configuration});
+ Entry{resource_name, data_type, 0, data_string_value, std::nullopt, 0, 0, configuration});
return *this;
}
FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue(
const std::string& resource_name, std::optional<android::base::borrowed_fd>&& binary_value,
- const std::string& configuration) {
- entries_.emplace_back(Entry{resource_name, 0, 0, "", binary_value, configuration});
+ off64_t data_binary_offset, size_t data_binary_size, const std::string& configuration) {
+ entries_.emplace_back(Entry{resource_name, 0, 0, "", binary_value,
+ data_binary_offset, data_binary_size, configuration});
return *this;
}
@@ -148,7 +149,8 @@ Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() {
}
value->second = TargetValue{res_entry.data_type, res_entry.data_value,
- res_entry.data_string_value, res_entry.data_binary_value};
+ res_entry.data_string_value, res_entry.data_binary_value,
+ res_entry.data_binary_offset, res_entry.data_binary_size};
}
pb::FabricatedOverlay overlay_pb;
@@ -157,7 +159,7 @@ Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() {
overlay_pb.set_target_package_name(target_package_name_);
overlay_pb.set_target_overlayable(target_overlayable_);
- std::vector<android::base::borrowed_fd> binary_files;
+ std::vector<FabricatedOverlay::BinaryData> binary_files;
size_t total_binary_bytes = 0;
// 16 for the number of bytes in the frro file before the binary data
const size_t FRRO_HEADER_SIZE = 16;
@@ -182,16 +184,15 @@ Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() {
pb_value->set_data_value(ref.index());
} else if (value.second.data_binary_value.has_value()) {
pb_value->set_data_type(Res_value::TYPE_STRING);
- struct stat s;
- if (fstat(value.second.data_binary_value->get(), &s) == -1) {
- return Error("unable to get size of binary file: %d", errno);
- }
std::string uri
= StringPrintf("frro:/%s?offset=%d&size=%d", frro_path_.c_str(),
static_cast<int> (FRRO_HEADER_SIZE + total_binary_bytes),
- static_cast<int> (s.st_size));
- total_binary_bytes += s.st_size;
- binary_files.emplace_back(value.second.data_binary_value->get());
+ static_cast<int> (value.second.data_binary_size));
+ total_binary_bytes += value.second.data_binary_size;
+ binary_files.emplace_back(FabricatedOverlay::BinaryData{
+ value.second.data_binary_value->get(),
+ value.second.data_binary_offset,
+ value.second.data_binary_size});
auto ref = string_pool.MakeRef(std::move(uri));
pb_value->set_data_value(ref.index());
} else {
@@ -310,8 +311,9 @@ Result<Unit> FabricatedOverlay::ToBinaryStream(std::ostream& stream) const {
Write32(stream, (*data)->pb_crc);
Write32(stream, total_binary_bytes_);
std::string file_contents;
- for (const android::base::borrowed_fd fd : binary_files_) {
- if (!ReadFdToString(fd, &file_contents)) {
+ for (const FabricatedOverlay::BinaryData fd : binary_files_) {
+ file_contents.resize(fd.size);
+ if (!ReadFullyAtOffset(fd.file_descriptor, file_contents.data(), fd.size, fd.offset)) {
return Error("Failed to read binary file data.");
}
stream.write(file_contents.data(), file_contents.length());
diff --git a/cmds/idmap2/self_targeting/SelfTargeting.cpp b/cmds/idmap2/self_targeting/SelfTargeting.cpp
index a8aa03309b16..c7f5cf3632c5 100644
--- a/cmds/idmap2/self_targeting/SelfTargeting.cpp
+++ b/cmds/idmap2/self_targeting/SelfTargeting.cpp
@@ -52,6 +52,7 @@ CreateFrroFile(std::string& out_err_result, const std::string& packageName,
const auto dataType = entry_params.data_type;
if (entry_params.data_binary_value.has_value()) {
builder.SetResourceValue(entry_params.resource_name, *entry_params.data_binary_value,
+ entry_params.binary_data_offset, entry_params.binary_data_size,
entry_params.configuration);
} else if (dataType >= Res_value::TYPE_FIRST_INT && dataType <= Res_value::TYPE_LAST_INT) {
builder.SetResourceValue(entry_params.resource_name, dataType,
diff --git a/cmds/idmap2/tests/FabricatedOverlayTests.cpp b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
index e13a0eb5d488..b460bb33f559 100644
--- a/cmds/idmap2/tests/FabricatedOverlayTests.cpp
+++ b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
@@ -59,7 +59,7 @@ TEST(FabricatedOverlayTests, SetResourceValue) {
Res_value::TYPE_STRING,
"foobar",
"en-rUS-normal-xxhdpi-v21")
- .SetResourceValue("com.example.target:drawable/dr1", fd, "port-xxhdpi-v7")
+ .SetResourceValue("com.example.target:drawable/dr1", fd, 0, 8341, "port-xxhdpi-v7")
.setFrroPath("/foo/bar/biz.frro")
.Build();
ASSERT_TRUE(overlay);
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index f6e48ba7a1f4..a3448fda60d9 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -269,7 +269,7 @@ TEST(IdmapTests, FabricatedOverlay) {
.SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U, "land-xxhdpi-v7")
.SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000, "land")
.SetResourceValue("string/str2", Res_value::TYPE_STRING, "foobar", "xxhdpi-v7")
- .SetResourceValue("drawable/dr1", fd, "port-xxhdpi-v7")
+ .SetResourceValue("drawable/dr1", fd, 0, 8341, "port-xxhdpi-v7")
.setFrroPath("/foo/bar/biz.frro")
.Build();
diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp
index 380e462a3aba..40f98c2f351b 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -212,7 +212,7 @@ TEST(ResourceMappingTests, FabricatedOverlay) {
.SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U, "")
.SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000, "")
.SetResourceValue("string/str2", Res_value::TYPE_STRING, "foobar", "")
- .SetResourceValue("drawable/dr1", fd, "")
+ .SetResourceValue("drawable/dr1", fd, 0, 8341, "")
.setFrroPath("/foo/bar/biz.frro")
.Build();
diff --git a/core/api/current.txt b/core/api/current.txt
index 3392d250d426..f40cbb61d4a3 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9530,6 +9530,7 @@ package android.companion {
method @Nullable public CharSequence getDisplayName();
method public int getId();
method public int getSystemDataSyncFlags();
+ method @Nullable public String getTag();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.companion.AssociationInfo> CREATOR;
}
@@ -9599,6 +9600,7 @@ package android.companion {
method @RequiresPermission(android.Manifest.permission.DELIVER_COMPANION_MESSAGES) public void attachSystemDataTransport(int, @NonNull java.io.InputStream, @NonNull java.io.OutputStream) throws android.companion.DeviceNotAssociatedException;
method @Nullable public android.content.IntentSender buildAssociationCancellationIntent();
method @Nullable public android.content.IntentSender buildPermissionTransferUserConsentIntent(int) throws android.companion.DeviceNotAssociatedException;
+ method public void clearAssociationTag(int);
method @RequiresPermission(android.Manifest.permission.DELIVER_COMPANION_MESSAGES) public void detachSystemDataTransport(int) throws android.companion.DeviceNotAssociatedException;
method public void disableSystemDataSyncForTypes(int, int);
method @Deprecated public void disassociate(@NonNull String);
@@ -9608,6 +9610,7 @@ package android.companion {
method @NonNull public java.util.List<android.companion.AssociationInfo> getMyAssociations();
method @Deprecated public boolean hasNotificationAccess(android.content.ComponentName);
method public void requestNotificationAccess(android.content.ComponentName);
+ method public void setAssociationTag(int, @NonNull String);
method @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void startObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException;
method public void startSystemDataTransfer(int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.companion.CompanionException>) throws android.companion.DeviceNotAssociatedException;
method @RequiresPermission(android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE) public void stopObservingDevicePresence(@NonNull String) throws android.companion.DeviceNotAssociatedException;
@@ -11699,6 +11702,7 @@ package android.content.om {
method @NonNull public void setResourceValue(@NonNull String, @IntRange(from=android.util.TypedValue.TYPE_FIRST_INT, to=android.util.TypedValue.TYPE_LAST_INT) int, int, @Nullable String);
method @NonNull public void setResourceValue(@NonNull String, int, @NonNull String, @Nullable String);
method @NonNull public void setResourceValue(@NonNull String, @NonNull android.os.ParcelFileDescriptor, @Nullable String);
+ method @NonNull public void setResourceValue(@NonNull String, @NonNull android.content.res.AssetFileDescriptor, @Nullable String);
method public void setTargetOverlayable(@Nullable String);
}
@@ -33699,7 +33703,7 @@ package android.os {
method public boolean isInteractive();
method public boolean isLowPowerStandbyEnabled();
method public boolean isPowerSaveMode();
- method public boolean isRebootingUserspaceSupported();
+ method @Deprecated public boolean isRebootingUserspaceSupported();
method @Deprecated public boolean isScreenOn();
method public boolean isSustainedPerformanceModeSupported();
method public boolean isWakeLockLevelSupported(int);
@@ -44999,6 +45003,7 @@ package android.telephony {
field public static final int NR_STATE_RESTRICTED = 1; // 0x1
field public static final int SERVICE_TYPE_DATA = 2; // 0x2
field public static final int SERVICE_TYPE_EMERGENCY = 5; // 0x5
+ field public static final int SERVICE_TYPE_MMS = 6; // 0x6
field public static final int SERVICE_TYPE_SMS = 3; // 0x3
field public static final int SERVICE_TYPE_UNKNOWN = 0; // 0x0
field public static final int SERVICE_TYPE_VIDEO = 4; // 0x4
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index a02fd84ce33c..eca2015fa3ed 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -10748,7 +10748,7 @@ package android.os {
field @RequiresPermission(android.Manifest.permission.MANAGE_LOW_POWER_STANDBY) public static final String ACTION_LOW_POWER_STANDBY_PORTS_CHANGED = "android.os.action.LOW_POWER_STANDBY_PORTS_CHANGED";
field public static final int POWER_SAVE_MODE_TRIGGER_DYNAMIC = 1; // 0x1
field public static final int POWER_SAVE_MODE_TRIGGER_PERCENTAGE = 0; // 0x0
- field public static final String REBOOT_USERSPACE = "userspace";
+ field @Deprecated public static final String REBOOT_USERSPACE = "userspace";
field public static final int SOUND_TRIGGER_MODE_ALL_DISABLED = 2; // 0x2
field public static final int SOUND_TRIGGER_MODE_ALL_ENABLED = 0; // 0x0
field public static final int SOUND_TRIGGER_MODE_CRITICAL_ONLY = 1; // 0x1
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 833d9c6d2420..76d4386a1cad 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3864,11 +3864,14 @@ package android.view.inputmethod {
public final class InputMethodManager {
method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public void addVirtualStylusIdForTestSession();
method public int getDisplayId();
+ method @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public java.util.List<android.view.inputmethod.InputMethodInfo> getEnabledInputMethodListAsUser(@NonNull android.os.UserHandle);
+ method @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public java.util.List<android.view.inputmethod.InputMethodSubtype> getEnabledInputMethodSubtypeListAsUser(@NonNull String, boolean, @NonNull android.os.UserHandle);
method @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodListAsUser(int);
method public boolean hasActiveInputConnection(@Nullable android.view.View);
method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean hasPendingImeVisibilityRequests();
method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isCurrentRootView(@NonNull android.view.View);
method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isInputMethodPickerShown();
+ method @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public boolean isStylusHandwritingAvailableAsUser(@NonNull android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public void setStylusWindowIdleTimeoutForTest(long);
field public static final long CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING = 214016041L; // 0xcc1a029L
}
diff --git a/core/java/android/app/IWindowToken.aidl b/core/java/android/app/IWindowToken.aidl
deleted file mode 100644
index 3627b0f13a7f..000000000000
--- a/core/java/android/app/IWindowToken.aidl
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- ** Copyright 2020, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-package android.app;
-
-import android.content.res.Configuration;
-import android.view.IWindow;
-
-/**
- * Callback to receive configuration changes from {@link com.android.server.WindowToken}.
- * WindowToken can be regarded to as a group of {@link android.view.IWindow} added from the same
- * visual context, such as {@link Activity} or one created with
- * {@link android.content.Context#createWindowContext(int)}. When WindowToken receives configuration
- * changes and/or when it is moved between displays, it will propagate the changes to client side
- * via this interface.
- * @see android.content.Context#createWindowContext(int)
- * {@hide}
- */
-oneway interface IWindowToken {
- void onConfigurationChanged(in Configuration newConfig, int newDisplayId);
-
- void onWindowTokenRemoved();
-}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 8647dd29b71a..e57849957f13 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -237,8 +237,6 @@ import android.view.contentcapture.ContentCaptureManager;
import android.view.contentcapture.IContentCaptureManager;
import android.view.displayhash.DisplayHashManager;
import android.view.inputmethod.InputMethodManager;
-import android.view.selectiontoolbar.ISelectionToolbarManager;
-import android.view.selectiontoolbar.SelectionToolbarManager;
import android.view.textclassifier.TextClassificationManager;
import android.view.textservice.TextServicesManager;
import android.view.translation.ITranslationManager;
@@ -379,17 +377,6 @@ public final class SystemServiceRegistry {
return new TextClassificationManager(ctx);
}});
- registerService(Context.SELECTION_TOOLBAR_SERVICE, SelectionToolbarManager.class,
- new CachedServiceFetcher<SelectionToolbarManager>() {
- @Override
- public SelectionToolbarManager createService(ContextImpl ctx)
- throws ServiceNotFoundException {
- IBinder b = ServiceManager.getServiceOrThrow(
- Context.SELECTION_TOOLBAR_SERVICE);
- return new SelectionToolbarManager(ctx.getOuterContext(),
- ISelectionToolbarManager.Stub.asInterface(b));
- }});
-
registerService(Context.FONT_SERVICE, FontManager.class,
new CachedServiceFetcher<FontManager>() {
@Override
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index b7ec7b55d7db..d66fca8945f1 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -22,6 +22,7 @@ import android.os.PooledStringWriter;
import android.os.RemoteException;
import android.os.SystemClock;
import android.service.autofill.FillRequest;
+import android.text.Spanned;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -1557,6 +1558,10 @@ public class AssistStructure implements Parcelable {
/**
* Returns any text associated with the node that is displayed to the user, or null
* if there is none.
+ *
+ * <p> The text will be stripped of any spans that could potentially contain reference to
+ * the activity context, to avoid memory leak. If the text contained a span, a plain
+ * string version of the text will be returned.
*/
@Nullable
public CharSequence getText() {
@@ -1996,14 +2001,16 @@ public class AssistStructure implements Parcelable {
@Override
public void setText(CharSequence text) {
ViewNodeText t = getNodeText();
- t.mText = TextUtils.trimNoCopySpans(text);
+ // Strip spans from the text to avoid memory leak
+ t.mText = TextUtils.trimToParcelableSize(stripAllSpansFromText(text));
t.mTextSelectionStart = t.mTextSelectionEnd = -1;
}
@Override
public void setText(CharSequence text, int selectionStart, int selectionEnd) {
ViewNodeText t = getNodeText();
- t.mText = TextUtils.trimNoCopySpans(text);
+ // Strip spans from the text to avoid memory leak
+ t.mText = stripAllSpansFromText(text);
t.mTextSelectionStart = selectionStart;
t.mTextSelectionEnd = selectionEnd;
}
@@ -2222,6 +2229,13 @@ public class AssistStructure implements Parcelable {
public void setHtmlInfo(@NonNull HtmlInfo htmlInfo) {
mNode.mHtmlInfo = htmlInfo;
}
+
+ private CharSequence stripAllSpansFromText(CharSequence text) {
+ if (text instanceof Spanned) {
+ return text.toString();
+ }
+ return text;
+ }
}
private static final class HtmlInfoNode extends HtmlInfo implements Parcelable {
diff --git a/core/java/android/companion/AssociationInfo.java b/core/java/android/companion/AssociationInfo.java
index 0958a806a5ff..7d62c79e7519 100644
--- a/core/java/android/companion/AssociationInfo.java
+++ b/core/java/android/companion/AssociationInfo.java
@@ -57,6 +57,7 @@ public final class AssociationInfo implements Parcelable {
private final boolean mSelfManaged;
private final boolean mNotifyOnDeviceNearby;
private final int mSystemDataSyncFlags;
+ private final String mTag;
/**
* Indicates that the association has been revoked (removed), but we keep the association
@@ -78,10 +79,11 @@ public final class AssociationInfo implements Parcelable {
* @hide
*/
public AssociationInfo(int id, @UserIdInt int userId, @NonNull String packageName,
- @Nullable MacAddress macAddress, @Nullable CharSequence displayName,
- @Nullable String deviceProfile, @Nullable AssociatedDevice associatedDevice,
- boolean selfManaged, boolean notifyOnDeviceNearby, boolean revoked,
- long timeApprovedMs, long lastTimeConnectedMs, int systemDataSyncFlags) {
+ @Nullable String tag, @Nullable MacAddress macAddress,
+ @Nullable CharSequence displayName, @Nullable String deviceProfile,
+ @Nullable AssociatedDevice associatedDevice, boolean selfManaged,
+ boolean notifyOnDeviceNearby, boolean revoked, long timeApprovedMs,
+ long lastTimeConnectedMs, int systemDataSyncFlags) {
if (id <= 0) {
throw new IllegalArgumentException("Association ID should be greater than 0");
}
@@ -97,6 +99,7 @@ public final class AssociationInfo implements Parcelable {
mDeviceMacAddress = macAddress;
mDisplayName = displayName;
+ mTag = tag;
mDeviceProfile = deviceProfile;
mAssociatedDevice = associatedDevice;
@@ -116,6 +119,14 @@ public final class AssociationInfo implements Parcelable {
}
/**
+ * @return the tag of this association.
+ * @see CompanionDeviceManager#setAssociationTag(int, String)
+ */
+ public @Nullable String getTag() {
+ return mTag;
+ }
+
+ /**
* @return the ID of the user who "owns" this association.
* @hide
*/
@@ -287,6 +298,7 @@ public final class AssociationInfo implements Parcelable {
+ "mId=" + mId
+ ", mUserId=" + mUserId
+ ", mPackageName='" + mPackageName + '\''
+ + ", mTag='" + mTag + '\''
+ ", mDeviceMacAddress=" + mDeviceMacAddress
+ ", mDisplayName='" + mDisplayName + '\''
+ ", mDeviceProfile='" + mDeviceProfile + '\''
@@ -315,6 +327,7 @@ public final class AssociationInfo implements Parcelable {
&& mTimeApprovedMs == that.mTimeApprovedMs
&& mLastTimeConnectedMs == that.mLastTimeConnectedMs
&& Objects.equals(mPackageName, that.mPackageName)
+ && Objects.equals(mTag, that.mTag)
&& Objects.equals(mDeviceMacAddress, that.mDeviceMacAddress)
&& Objects.equals(mDisplayName, that.mDisplayName)
&& Objects.equals(mDeviceProfile, that.mDeviceProfile)
@@ -324,7 +337,7 @@ public final class AssociationInfo implements Parcelable {
@Override
public int hashCode() {
- return Objects.hash(mId, mUserId, mPackageName, mDeviceMacAddress, mDisplayName,
+ return Objects.hash(mId, mUserId, mPackageName, mTag, mDeviceMacAddress, mDisplayName,
mDeviceProfile, mAssociatedDevice, mSelfManaged, mNotifyOnDeviceNearby, mRevoked,
mTimeApprovedMs, mLastTimeConnectedMs, mSystemDataSyncFlags);
}
@@ -340,6 +353,7 @@ public final class AssociationInfo implements Parcelable {
dest.writeInt(mUserId);
dest.writeString(mPackageName);
+ dest.writeString(mTag);
dest.writeTypedObject(mDeviceMacAddress, 0);
dest.writeCharSequence(mDisplayName);
@@ -359,6 +373,7 @@ public final class AssociationInfo implements Parcelable {
mUserId = in.readInt();
mPackageName = in.readString();
+ mTag = in.readString();
mDeviceMacAddress = in.readTypedObject(MacAddress.CREATOR);
mDisplayName = in.readCharSequence();
@@ -413,9 +428,11 @@ public final class AssociationInfo implements Parcelable {
private boolean mRevoked;
private long mLastTimeConnectedMs;
private int mSystemDataSyncFlags;
+ private String mTag;
private Builder(@NonNull AssociationInfo info) {
mOriginalInfo = info;
+ mTag = info.mTag;
mNotifyOnDeviceNearby = info.mNotifyOnDeviceNearby;
mRevoked = info.mRevoked;
mLastTimeConnectedMs = info.mLastTimeConnectedMs;
@@ -460,12 +477,21 @@ public final class AssociationInfo implements Parcelable {
}
/** @hide */
+ @Override
+ @NonNull
+ public Builder setTag(String tag) {
+ mTag = tag;
+ return this;
+ }
+
+ /** @hide */
@NonNull
public AssociationInfo build() {
return new AssociationInfo(
mOriginalInfo.mId,
mOriginalInfo.mUserId,
mOriginalInfo.mPackageName,
+ mTag,
mOriginalInfo.mDeviceMacAddress,
mOriginalInfo.mDisplayName,
mOriginalInfo.mDeviceProfile,
@@ -508,5 +534,8 @@ public final class AssociationInfo implements Parcelable {
/** @hide */
@NonNull
Builder setSystemDataSyncFlags(int flags);
+
+ /** @hide */
+ Builder setTag(String tag);
}
}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 69e1653eb8ed..3aa287724263 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -1372,6 +1372,50 @@ public final class CompanionDeviceManager {
}
}
+ /**
+ * Sets the {@link AssociationInfo#getTag() tag} for this association.
+ *
+ * <p>The length of the tag must be at most 20 characters.
+ *
+ * <p>This allows to store useful information about the associated devices.
+ *
+ * @param associationId The unique {@link AssociationInfo#getId ID} assigned to the Association
+ * of the companion device recorded by CompanionDeviceManager
+ * @param tag the tag of this association
+ */
+ @UserHandleAware
+ public void setAssociationTag(int associationId, @NonNull String tag) {
+ Objects.requireNonNull(tag, "tag cannot be null");
+
+ if (tag.length() > 20) {
+ throw new IllegalArgumentException("Length of the tag must be at most 20 characters");
+ }
+
+ try {
+ mService.setAssociationTag(associationId, tag);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Clears the {@link AssociationInfo#getTag() tag} for this association.
+ *
+ * <p>The tag will be set to null for this association when calling this API.
+ *
+ * @param associationId The unique {@link AssociationInfo#getId ID} assigned to the Association
+ * of the companion device recorded by CompanionDeviceManager
+ * @see CompanionDeviceManager#setAssociationTag(int, String)
+ */
+ @UserHandleAware
+ public void clearAssociationTag(int associationId) {
+ try {
+ mService.clearAssociationTag(associationId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private boolean checkFeaturePresent() {
boolean featurePresent = mService != null;
if (!featurePresent && DEBUG) {
diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl
index 463dba24fb5a..e01543d50e55 100644
--- a/core/java/android/companion/ICompanionDeviceManager.aidl
+++ b/core/java/android/companion/ICompanionDeviceManager.aidl
@@ -115,4 +115,8 @@ interface ICompanionDeviceManager {
@EnforcePermission("MANAGE_COMPANION_DEVICES")
void enableSecureTransport(boolean enabled);
+
+ void setAssociationTag(int associationId, String tag);
+
+ void clearAssociationTag(int associationId);
}
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
index d0bb2b9b6eeb..8f35ca25ab22 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -517,7 +517,11 @@ public final class AttributionSource implements Parcelable {
}
/**
- * The device ID for which permissions are checked.
+ * Gets the device ID for this attribution source. Attribution source can set the device ID
+ * using {@link Builder#setDeviceId(int)}, the default device ID is
+ * {@link Context#DEVICE_ID_DEFAULT}.
+ * <p>
+ * This device ID is used for permissions checking during attribution source validation.
*/
public int getDeviceId() {
return mAttributionSourceState.deviceId;
diff --git a/core/java/android/content/om/FabricatedOverlay.java b/core/java/android/content/om/FabricatedOverlay.java
index 7e787c9c3a8c..c4547b8acc2b 100644
--- a/core/java/android/content/om/FabricatedOverlay.java
+++ b/core/java/android/content/om/FabricatedOverlay.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.res.AssetFileDescriptor;
import android.os.FabricatedOverlayInternal;
import android.os.FabricatedOverlayInternalEntry;
import android.os.ParcelFileDescriptor;
@@ -269,7 +270,7 @@ public class FabricatedOverlay {
* @param configuration The string representation of the config this overlay is enabled for
* @return the builder itself
* @deprecated Framework should use {@link FabricatedOverlay#setResourceValue(String,
- ParcelFileDescriptor, String)} instead.
+ ParcelFileDescriptor, String)} instead.
* @hide
*/
@Deprecated(since = "Please use FabricatedOverlay#setResourceValue instead")
@@ -285,6 +286,30 @@ public class FabricatedOverlay {
}
/**
+ * Sets the value of the fabricated overlay for the file descriptor type.
+ *
+ * @param resourceName name of the target resource to overlay (in the form
+ * [package]:type/entry)
+ * @param value the file descriptor whose contents are the value of the frro
+ * @param configuration The string representation of the config this overlay is enabled for
+ * @return the builder itself
+ * @deprecated Framework should use {@link FabricatedOverlay#setResourceValue(String,
+ ParcelFileDescriptor, String)} instead.
+ * @hide
+ */
+ @Deprecated(since = "Please use FabricatedOverlay#setResourceValue instead")
+ @NonNull
+ public Builder setResourceValue(
+ @NonNull String resourceName,
+ @NonNull AssetFileDescriptor value,
+ @Nullable String configuration) {
+ ensureValidResourceName(resourceName);
+ mEntries.add(
+ generateFabricatedOverlayInternalEntry(resourceName, value, configuration));
+ return this;
+ }
+
+ /**
* Builds an immutable fabricated overlay.
*
* @return the fabricated overlay
@@ -421,6 +446,21 @@ public class FabricatedOverlay {
entry.resourceName = resourceName;
entry.binaryData = Objects.requireNonNull(parcelFileDescriptor);
entry.configuration = configuration;
+ entry.binaryDataOffset = 0;
+ entry.binaryDataSize = parcelFileDescriptor.getStatSize();
+ return entry;
+ }
+
+ @NonNull
+ private static FabricatedOverlayInternalEntry generateFabricatedOverlayInternalEntry(
+ @NonNull String resourceName, @NonNull AssetFileDescriptor assetFileDescriptor,
+ @Nullable String configuration) {
+ final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry();
+ entry.resourceName = resourceName;
+ entry.binaryData = Objects.requireNonNull(assetFileDescriptor.getParcelFileDescriptor());
+ entry.binaryDataOffset = assetFileDescriptor.getStartOffset();
+ entry.binaryDataSize = assetFileDescriptor.getLength();
+ entry.configuration = configuration;
return entry;
}
@@ -495,4 +535,23 @@ public class FabricatedOverlay {
mOverlay.entries.add(
generateFabricatedOverlayInternalEntry(resourceName, value, configuration));
}
+
+ /**
+ * Sets the resource value in the fabricated overlay for the file descriptor type with the
+ * configuration.
+ *
+ * @param resourceName name of the target resource to overlay (in the form
+ * [package]:type/entry)
+ * @param value the file descriptor whose contents are the value of the frro
+ * @param configuration The string representation of the config this overlay is enabled for
+ */
+ @NonNull
+ public void setResourceValue(
+ @NonNull String resourceName,
+ @NonNull AssetFileDescriptor value,
+ @Nullable String configuration) {
+ ensureValidResourceName(resourceName);
+ mOverlay.entries.add(
+ generateFabricatedOverlayInternalEntry(resourceName, value, configuration));
+ }
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 19539c25dcb0..8cb96ba09748 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -3028,6 +3028,8 @@ public class PackageInstaller {
* <li>{@code requireUserAction} is set to {@link #USER_ACTION_NOT_REQUIRED}.</li>
* <li>The app being installed targets:
* <ul>
+ * <li>{@link android.os.Build.VERSION_CODES#Q API 29} or higher on
+ * Android S ({@link android.os.Build.VERSION_CODES#S API 31})</li>
* <li>{@link android.os.Build.VERSION_CODES#R API 30} or higher on
* Android T ({@link android.os.Build.VERSION_CODES#TIRAMISU API 33})</li>
* <li>{@link android.os.Build.VERSION_CODES#S API 31} or higher <b>after</b>
diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING
index 6419f8c6f0d9..ea21d51b0e9e 100644
--- a/core/java/android/content/pm/TEST_MAPPING
+++ b/core/java/android/content/pm/TEST_MAPPING
@@ -114,7 +114,9 @@
"exclude-annotation":"org.junit.Ignore"
}
]
- },
+ }
+ ],
+ "presubmit-large":[
{
"name":"CtsPackageManagerTestCases",
"options":[
@@ -123,11 +125,12 @@
},
{
"exclude-annotation":"org.junit.Ignore"
+ },
+ {
+ "exclude-filter": "android.content.pm.cts.PackageManagerShellCommandMultiUserTest"
}
]
- }
- ],
- "presubmit-large":[
+ },
{
"name":"CtsUsesNativeLibraryTest",
"options":[
@@ -162,6 +165,14 @@
},
{
"name":"CtsInstallHostTestCases"
+ },
+ {
+ "name": "CtsPackageManagerTestCases",
+ "options": [
+ {
+ "include-filter": "android.content.pm.cts.PackageManagerShellCommandMultiUserTest"
+ }
+ ]
}
]
-} \ No newline at end of file
+}
diff --git a/core/java/android/content/res/Element.java b/core/java/android/content/res/Element.java
index a86c0c9a4463..e931fe8526f1 100644
--- a/core/java/android/content/res/Element.java
+++ b/core/java/android/content/res/Element.java
@@ -42,6 +42,8 @@ public class Element {
public static final int MAX_ATTR_LEN_PATH = 4000;
public static final int MAX_ATTR_LEN_DATA_VALUE = 4000;
+ private static final String BAD_COMPONENT_NAME_CHARS = ";,[](){}:?-%^*|/\\";
+
private static final String TAG = "PackageParsing";
protected static final String TAG_ACTION = "action";
protected static final String TAG_ACTIVITY = "activity";
@@ -128,6 +130,7 @@ public class Element {
protected static final String TAG_ATTR_VALUE = "value";
protected static final String TAG_ATTR_VERSION_NAME = "versionName";
protected static final String TAG_ATTR_WRITE_PERMISSION = "writePermission";
+ protected static final String TAG_ATTR_ZYGOTE_PRELOAD_NAME = "zygotePreloadName";
// The length of mTagCounters corresponds to the number of tags defined in getCounterIdx. If new
// tags are added then the size here should be increased to match.
@@ -374,6 +377,7 @@ public class Element {
case TAG_ATTR_TASK_AFFINITY:
case TAG_ATTR_WRITE_PERMISSION:
case TAG_ATTR_VERSION_NAME:
+ case TAG_ATTR_ZYGOTE_PRELOAD_NAME:
return MAX_ATTR_LEN_NAME;
case TAG_ATTR_PATH:
case TAG_ATTR_PATH_ADVANCED_PATTERN:
@@ -488,6 +492,7 @@ public class Element {
case R.styleable.AndroidManifestApplication_requiredAccountType:
case R.styleable.AndroidManifestApplication_restrictedAccountType:
case R.styleable.AndroidManifestApplication_taskAffinity:
+ case R.styleable.AndroidManifestApplication_zygotePreloadName:
return MAX_ATTR_LEN_NAME;
default:
return DEFAULT_MAX_STRING_ATTR_LENGTH;
@@ -738,6 +743,7 @@ public class Element {
switch (name) {
case TAG_ATTR_BACKUP_AGENT:
case TAG_ATTR_NAME:
+ case TAG_ATTR_ZYGOTE_PRELOAD_NAME:
return true;
default:
return false;
@@ -766,7 +772,8 @@ public class Element {
return index == R.styleable.AndroidManifestActivityAlias_targetActivity;
case TAG_APPLICATION:
return index == R.styleable.AndroidManifestApplication_backupAgent
- || index == R.styleable.AndroidManifestApplication_name;
+ || index == R.styleable.AndroidManifestApplication_name
+ || index == R.styleable.AndroidManifestApplication_zygotePreloadName;
case TAG_INSTRUMENTATION:
return index == R.styleable.AndroidManifestInstrumentation_name;
case TAG_PROVIDER:
@@ -785,33 +792,13 @@ public class Element {
}
void validateComponentName(CharSequence name) {
- int i = 0;
- if (name.charAt(0) == '.') {
- i = 1;
- }
boolean isStart = true;
- for (; i < name.length(); i++) {
- if (name.charAt(i) == '.') {
- if (isStart) {
- break;
- }
- isStart = true;
- } else {
- if (isStart) {
- if (Character.isJavaIdentifierStart(name.charAt(i))) {
- isStart = false;
- } else {
- break;
- }
- } else if (!Character.isJavaIdentifierPart(name.charAt(i))) {
- break;
- }
+ for (int i = 0; i < name.length(); i++) {
+ if (BAD_COMPONENT_NAME_CHARS.indexOf(name.charAt(i)) >= 0) {
+ Slog.e(TAG, name + " is not a valid Java class name");
+ throw new SecurityException(name + " is not a valid Java class name");
}
}
- if ((i < name.length()) || (name.charAt(name.length() - 1) == '.')) {
- Slog.e(TAG, name + " is not a valid Java class name");
- throw new SecurityException(name + " is not a valid Java class name");
- }
}
void validateStrAttr(String attrName, String attrValue) {
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index c872516014db..59408191cdf5 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -4194,9 +4194,8 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* <p>This control allows Camera extension clients to configure the strength of the applied
* extension effect. Strength equal to 0 means that the extension must not apply any
* post-processing and return a regular captured frame. Strength equal to 100 is the
- * default level of post-processing applied when the control is not supported or not set
- * by the client. Values between 0 and 100 will have different effect depending on the
- * extension type as described below:</p>
+ * maximum level of post-processing. Values between 0 and 100 will have different effect
+ * depending on the extension type as described below:</p>
* <ul>
* <li>{@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_BOKEH BOKEH} -
* the strength is expected to control the amount of blur.</li>
@@ -4211,7 +4210,9 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* {@link android.hardware.camera2.CameraExtensionCharacteristics#getAvailableCaptureRequestKeys }.
* The control is only defined and available to clients sending capture requests via
* {@link android.hardware.camera2.CameraExtensionSession }.
- * The default value is 100.</p>
+ * If the client doesn't specify the extension strength value, then a default value will
+ * be set by the extension. Clients can retrieve the default value by checking the
+ * corresponding capture result.</p>
* <p><b>Range of valid values:</b><br>
* 0 - 100</p>
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 57f7bca1f67e..905f98de75ff 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -5694,9 +5694,8 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <p>This control allows Camera extension clients to configure the strength of the applied
* extension effect. Strength equal to 0 means that the extension must not apply any
* post-processing and return a regular captured frame. Strength equal to 100 is the
- * default level of post-processing applied when the control is not supported or not set
- * by the client. Values between 0 and 100 will have different effect depending on the
- * extension type as described below:</p>
+ * maximum level of post-processing. Values between 0 and 100 will have different effect
+ * depending on the extension type as described below:</p>
* <ul>
* <li>{@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_BOKEH BOKEH} -
* the strength is expected to control the amount of blur.</li>
@@ -5711,7 +5710,9 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* {@link android.hardware.camera2.CameraExtensionCharacteristics#getAvailableCaptureRequestKeys }.
* The control is only defined and available to clients sending capture requests via
* {@link android.hardware.camera2.CameraExtensionSession }.
- * The default value is 100.</p>
+ * If the client doesn't specify the extension strength value, then a default value will
+ * be set by the extension. Clients can retrieve the default value by checking the
+ * corresponding capture result.</p>
* <p><b>Range of valid values:</b><br>
* 0 - 100</p>
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 1ae1b050d32f..37bd67a4b883 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -537,8 +537,15 @@ public class VpnService extends Service {
}
/**
- * Sets an HTTP proxy for the VPN network. This proxy is only a recommendation
- * and it is possible that some apps will ignore it. PAC proxies are not supported.
+ * Sets an HTTP proxy for the VPN network.
+ * <p class="note">This proxy is only a recommendation and it is possible that some apps
+ * will ignore it.
+ * <p class="note">PAC proxies are not supported over VPNs.
+ * <p class="note">Apps that do use the proxy cannot distinguish between routes handled
+ * and not handled by the VPN and will try to access HTTP resources over the proxy
+ * regardless of the destination. In practice this means using a proxy with a split
+ * tunnel generally won't work as expected, because HTTP accesses on routes not handled by
+ * the VPN will not reach as the proxy won't be available outside of the VPN network.
*/
@NonNull
public Builder setHttpProxy(@NonNull ProxyInfo proxyInfo) {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 8596e543a148..43219bc38e2d 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1968,6 +1968,9 @@ public abstract class BatteryStats {
public static final int STATE2_GPS_SIGNAL_QUALITY_SHIFT = 7;
public static final int STATE2_GPS_SIGNAL_QUALITY_MASK =
0x3 << STATE2_GPS_SIGNAL_QUALITY_SHIFT;
+ // Values for NR_STATE_*
+ public static final int STATE2_NR_STATE_SHIFT = 9;
+ public static final int STATE2_NR_STATE_MASK = 0x3 << STATE2_NR_STATE_SHIFT;
public static final int STATE2_POWER_SAVE_FLAG = 1<<31;
public static final int STATE2_VIDEO_ON_FLAG = 1<<30;
@@ -2763,6 +2766,14 @@ public abstract class BatteryStats {
*/
public abstract Timer getPhoneDataConnectionTimer(int dataType);
+ /**
+ * Returns the time in microseconds that the phone's data connection was in NR NSA mode while
+ * on battery.
+ *
+ * {@hide}
+ */
+ public abstract long getNrNsaTime(long elapsedRealtimeUs);
+
/** @hide */
public static final int RADIO_ACCESS_TECHNOLOGY_OTHER = 0;
/** @hide */
@@ -3029,7 +3040,11 @@ public abstract class BatteryStats {
"cellular_high_tx_power", "Chtp"),
new BitDescription(HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK,
HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT, "gps_signal_quality", "Gss",
- new String[] { "poor", "good", "none"}, new String[] { "poor", "good", "none"})
+ new String[] { "poor", "good", "none"}, new String[] { "poor", "good", "none"}),
+ new BitDescription(HistoryItem.STATE2_NR_STATE_MASK,
+ HistoryItem.STATE2_NR_STATE_SHIFT, "nr_state", "nrs",
+ new String[]{"none", "restricted", "not_restricted", "connected"},
+ new String[]{"0", "1", "2", "3"}),
};
public static final String[] HISTORY_EVENT_NAMES = new String[] {
@@ -5612,20 +5627,36 @@ public abstract class BatteryStats {
sb.append(prefix);
sb.append(" Cellular Radio Access Technology:");
didOne = false;
- for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
- final long time = getPhoneDataConnectionTime(i, rawRealtime, which);
+ for (int connType = 0; connType < NUM_DATA_CONNECTION_TYPES; connType++) {
+ final long time = getPhoneDataConnectionTime(connType, rawRealtime, which);
if (time == 0) {
continue;
}
sb.append("\n ");
sb.append(prefix);
didOne = true;
- sb.append(i < DATA_CONNECTION_NAMES.length ? DATA_CONNECTION_NAMES[i] : "ERROR");
+ sb.append(connType < DATA_CONNECTION_NAMES.length ?
+ DATA_CONNECTION_NAMES[connType] : "ERROR");
sb.append(" ");
formatTimeMs(sb, time/1000);
sb.append("(");
sb.append(formatRatioLocked(time, whichBatteryRealtime));
sb.append(") ");
+
+ if (connType == TelephonyManager.NETWORK_TYPE_LTE) {
+ // Report any of the LTE time was spent in NR NSA mode.
+ final long nrNsaTime = getNrNsaTime(rawRealtime);
+ if (nrNsaTime != 0) {
+ sb.append("\n ");
+ sb.append(prefix);
+ sb.append("nr_nsa");
+ sb.append(" ");
+ formatTimeMs(sb, nrNsaTime / 1000);
+ sb.append("(");
+ sb.append(formatRatioLocked(nrNsaTime, whichBatteryRealtime));
+ sb.append(") ");
+ }
+ }
}
if (!didOne) sb.append(" (no activity)");
pw.println(sb.toString());
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 538ed423626f..a07735e7540e 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -178,23 +178,6 @@ public class GraphicsEnvironment {
}
/**
- * Query to determine if the Game Mode has enabled ANGLE.
- */
- private boolean isAngleEnabledByGameMode(Context context, String packageName) {
- try {
- final boolean gameModeEnabledAngle =
- (mGameManager != null) && mGameManager.isAngleEnabled(packageName);
- Log.v(TAG, "ANGLE GameManagerService for " + packageName + ": " + gameModeEnabledAngle);
- return gameModeEnabledAngle;
- } catch (SecurityException e) {
- Log.e(TAG, "Caught exception while querying GameManagerService if ANGLE is enabled "
- + "for package: " + packageName);
- }
-
- return false;
- }
-
- /**
* Query to determine the ANGLE driver choice.
*/
private String queryAngleChoice(Context context, Bundle coreSettings,
@@ -422,8 +405,7 @@ public class GraphicsEnvironment {
* 2) The per-application switch (i.e. Settings.Global.ANGLE_GL_DRIVER_SELECTION_PKGS and
* Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES; which corresponds to the
* “angle_gl_driver_selection_pkgs” and “angle_gl_driver_selection_values” settings); if it
- * forces a choice;
- * 3) Use ANGLE if isAngleEnabledByGameMode() returns true;
+ * forces a choice.
*/
private String queryAngleChoiceInternal(Context context, Bundle bundle,
String packageName) {
@@ -457,10 +439,6 @@ public class GraphicsEnvironment {
Log.v(TAG, " angle_gl_driver_selection_pkgs=" + optInPackages);
Log.v(TAG, " angle_gl_driver_selection_values=" + optInValues);
- final String gameModeChoice = isAngleEnabledByGameMode(context, packageName)
- ? ANGLE_GL_DRIVER_CHOICE_ANGLE
- : ANGLE_GL_DRIVER_CHOICE_DEFAULT;
-
// Make sure we have good settings to use
if (optInPackages.size() == 0 || optInPackages.size() != optInValues.size()) {
Log.v(TAG,
@@ -469,7 +447,7 @@ public class GraphicsEnvironment {
+ optInPackages.size() + ", "
+ "number of values: "
+ optInValues.size());
- return gameModeChoice;
+ return ANGLE_GL_DRIVER_CHOICE_DEFAULT;
}
// See if this application is listed in the per-application settings list
@@ -477,7 +455,7 @@ public class GraphicsEnvironment {
if (pkgIndex < 0) {
Log.v(TAG, packageName + " is not listed in per-application setting");
- return gameModeChoice;
+ return ANGLE_GL_DRIVER_CHOICE_DEFAULT;
}
mAngleOptInIndex = pkgIndex;
@@ -491,11 +469,9 @@ public class GraphicsEnvironment {
return ANGLE_GL_DRIVER_CHOICE_ANGLE;
} else if (optInValue.equals(ANGLE_GL_DRIVER_CHOICE_NATIVE)) {
return ANGLE_GL_DRIVER_CHOICE_NATIVE;
- } else {
- // The user either chose default or an invalid value; go with the default driver or what
- // the game mode indicates
- return gameModeChoice;
}
+ // The user either chose default or an invalid value; go with the default driver.
+ return ANGLE_GL_DRIVER_CHOICE_DEFAULT;
}
/**
diff --git a/core/java/android/os/PerformanceHintManager.java b/core/java/android/os/PerformanceHintManager.java
index 977ef60c43b6..bcea7978a804 100644
--- a/core/java/android/os/PerformanceHintManager.java
+++ b/core/java/android/os/PerformanceHintManager.java
@@ -55,15 +55,20 @@ public final class PerformanceHintManager {
* duration.
*
* @param tids The list of threads to be associated with this session. They must be part of
- * this process' thread group.
+ * this process' thread group
* @param initialTargetWorkDurationNanos The desired duration in nanoseconds for the new
- * session.
+ * session
* @return the new session if it is supported on this device, null if hint session is not
- * supported on this device.
+ * supported on this device or the tid doesn't belong to the application
+ * @throws IllegalArgumentException if the thread id list is empty, or
+ * initialTargetWorkDurationNanos is non-positive
*/
@Nullable
public Session createHintSession(@NonNull int[] tids, long initialTargetWorkDurationNanos) {
- Preconditions.checkNotNull(tids, "tids cannot be null");
+ Objects.requireNonNull(tids, "tids cannot be null");
+ if (tids.length == 0) {
+ throw new IllegalArgumentException("thread id list can't be empty.");
+ }
Preconditions.checkArgumentPositive(initialTargetWorkDurationNanos,
"the hint target duration should be positive.");
long nativeSessionPtr = nativeCreateSession(mNativeManagerPtr, tids,
@@ -75,7 +80,7 @@ public final class PerformanceHintManager {
/**
* Get preferred update rate information for this device.
*
- * @return the preferred update rate supported by device software.
+ * @return the preferred update rate supported by device software
*/
public long getPreferredUpdateRateNanos() {
return nativeGetPreferredUpdateRateNanos(mNativeManagerPtr);
@@ -209,7 +214,7 @@ public final class PerformanceHintManager {
/**
* Sends performance hints to inform the hint session of changes in the workload.
*
- * @param hint The hint to send to the session.
+ * @param hint The hint to send to the session
*
* @hide
*/
@@ -230,11 +235,11 @@ public final class PerformanceHintManager {
* Note that this is not an oneway method.
*
* @param tids The list of threads to be associated with this session. They must be
- * part of this app's thread group.
+ * part of this app's thread group
*
- * @throws IllegalStateException if the hint session is not in the foreground.
- * @throws IllegalArgumentException if the thread id list is empty.
- * @throws SecurityException if any thread id doesn't belong to the application.
+ * @throws IllegalStateException if the hint session is not in the foreground
+ * @throws IllegalArgumentException if the thread id list is empty
+ * @throws SecurityException if any thread id doesn't belong to the application
*/
public void setThreads(@NonNull int[] tids) {
if (mNativeSessionPtr == 0) {
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index c6b9d20b450d..d676509d9317 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -33,7 +33,6 @@ import android.app.PropertyInvalidatedCache;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.service.dreams.Sandman;
-import android.sysprop.InitProperties;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
@@ -868,6 +867,8 @@ public final class PowerManager {
/**
* The 'reason' value used for rebooting userspace.
+ *
+ * @deprecated userspace reboot is not supported
* @hide
*/
@SystemApi
@@ -1824,16 +1825,18 @@ public final class PowerManager {
* <p>This method exists solely for the sake of re-using same logic between {@code PowerManager}
* and {@code PowerManagerService}.
*
+ * @deprecated TODO(b/292469129): remove this method.
* @hide
*/
public static boolean isRebootingUserspaceSupportedImpl() {
- return InitProperties.is_userspace_reboot_supported().orElse(false);
+ return false;
}
/**
* Returns {@code true} if this device supports rebooting userspace.
+ *
+ * @deprecated userspace reboot is deprecated, this method always returns {@code false}.
*/
- // TODO(b/138605180): add link to documentation once it's ready.
public boolean isRebootingUserspaceSupported() {
return isRebootingUserspaceSupportedImpl();
}
diff --git a/core/java/android/os/TEST_MAPPING b/core/java/android/os/TEST_MAPPING
index dae9b5ea6a43..60622f18fe3b 100644
--- a/core/java/android/os/TEST_MAPPING
+++ b/core/java/android/os/TEST_MAPPING
@@ -99,13 +99,10 @@
"BatteryStats[^/]*\\.java",
"BatteryUsageStats[^/]*\\.java",
"PowerComponents\\.java",
+ "PowerMonitor[^/]*\\.java",
"[^/]*BatteryConsumer[^/]*\\.java"
],
- "name": "FrameworksServicesTests",
- "options": [
- { "include-filter": "com.android.server.power.stats" },
- { "exclude-filter": "com.android.server.power.stats.BatteryStatsTests" }
- ]
+ "name": "PowerStatsTests"
},
{
"file_patterns": [
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 0527ed692da4..cac7f3b74185 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -125,7 +125,8 @@ public final class UserHandle implements Parcelable {
public static final int MIN_SECONDARY_USER_ID = 10;
/** @hide */
- public static final int MAX_SECONDARY_USER_ID = Integer.MAX_VALUE / UserHandle.PER_USER_RANGE;
+ public static final int MAX_SECONDARY_USER_ID =
+ Integer.MAX_VALUE / UserHandle.PER_USER_RANGE - 1;
/**
* (Arbitrary) user handle cache size.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2abf02ec3ed3..bf58eaa47e83 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -19175,6 +19175,14 @@ public final class Settings {
* @hide
*/
public static final String WEAR_LAUNCHER_UI_MODE = "wear_launcher_ui_mode";
+
+ /** Whether Wear Power Anomaly Service is enabled.
+ *
+ * (0 = false, 1 = true)
+ * @hide
+ */
+ public static final String WEAR_POWER_ANOMALY_SERVICE_ENABLED =
+ "wear_power_anomaly_service_enabled";
}
}
diff --git a/core/java/android/service/selectiontoolbar/DefaultSelectionToolbarRenderService.java b/core/java/android/service/selectiontoolbar/DefaultSelectionToolbarRenderService.java
deleted file mode 100644
index ad73a53cfd87..000000000000
--- a/core/java/android/service/selectiontoolbar/DefaultSelectionToolbarRenderService.java
+++ /dev/null
@@ -1,153 +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 android.service.selectiontoolbar;
-
-import static android.view.selectiontoolbar.SelectionToolbarManager.ERROR_DO_NOT_ALLOW_MULTIPLE_TOOL_BAR;
-import static android.view.selectiontoolbar.SelectionToolbarManager.NO_TOOLBAR_ID;
-
-import android.util.Pair;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.view.selectiontoolbar.ShowInfo;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.UUID;
-
-/**
- * The default implementation of {@link SelectionToolbarRenderService}.
- *
- * <p><b>NOTE:<b/> The requests are handled on the service main thread.
- *
- * @hide
- */
-// TODO(b/214122495): fix class not found then move to system service folder
-public final class DefaultSelectionToolbarRenderService extends SelectionToolbarRenderService {
-
- private static final String TAG = "DefaultSelectionToolbarRenderService";
-
- // TODO(b/215497659): handle remove if the client process dies.
- // Only show one toolbar, dismiss the old ones and remove from cache
- private final SparseArray<Pair<Long, RemoteSelectionToolbar>> mToolbarCache =
- new SparseArray<>();
-
- /**
- * Only allow one package to create one toolbar.
- */
- private boolean canShowToolbar(int uid, ShowInfo showInfo) {
- if (showInfo.getWidgetToken() != NO_TOOLBAR_ID) {
- return true;
- }
- return mToolbarCache.indexOfKey(uid) < 0;
- }
-
- @Override
- public void onShow(int callingUid, ShowInfo showInfo,
- SelectionToolbarRenderService.RemoteCallbackWrapper callbackWrapper) {
- if (!canShowToolbar(callingUid, showInfo)) {
- Slog.e(TAG, "Do not allow multiple toolbar for the app.");
- callbackWrapper.onError(ERROR_DO_NOT_ALLOW_MULTIPLE_TOOL_BAR);
- return;
- }
- long widgetToken = showInfo.getWidgetToken() == NO_TOOLBAR_ID
- ? UUID.randomUUID().getMostSignificantBits()
- : showInfo.getWidgetToken();
-
- if (mToolbarCache.indexOfKey(callingUid) < 0) {
- RemoteSelectionToolbar toolbar = new RemoteSelectionToolbar(this,
- widgetToken, showInfo,
- callbackWrapper, this::transferTouch);
- mToolbarCache.put(callingUid, new Pair<>(widgetToken, toolbar));
- }
- Slog.v(TAG, "onShow() for " + widgetToken);
- Pair<Long, RemoteSelectionToolbar> toolbarPair = mToolbarCache.get(callingUid);
- if (toolbarPair.first == widgetToken) {
- toolbarPair.second.show(showInfo);
- } else {
- Slog.w(TAG, "onShow() for unknown " + widgetToken);
- }
- }
-
- @Override
- public void onHide(long widgetToken) {
- RemoteSelectionToolbar toolbar = getRemoteSelectionToolbarByTokenLocked(widgetToken);
- if (toolbar != null) {
- Slog.v(TAG, "onHide() for " + widgetToken);
- toolbar.hide(widgetToken);
- }
- }
-
- @Override
- public void onDismiss(long widgetToken) {
- RemoteSelectionToolbar toolbar = getRemoteSelectionToolbarByTokenLocked(widgetToken);
- if (toolbar != null) {
- Slog.v(TAG, "onDismiss() for " + widgetToken);
- toolbar.dismiss(widgetToken);
- removeRemoteSelectionToolbarByTokenLocked(widgetToken);
- }
- }
-
- @Override
- public void onToolbarShowTimeout(int callingUid) {
- Slog.w(TAG, "onToolbarShowTimeout for callingUid = " + callingUid);
- Pair<Long, RemoteSelectionToolbar> toolbarPair = mToolbarCache.get(callingUid);
- if (toolbarPair != null) {
- RemoteSelectionToolbar remoteToolbar = toolbarPair.second;
- remoteToolbar.dismiss(toolbarPair.first);
- remoteToolbar.onToolbarShowTimeout();
- mToolbarCache.remove(callingUid);
- }
- }
-
- private RemoteSelectionToolbar getRemoteSelectionToolbarByTokenLocked(long widgetToken) {
- for (int i = 0; i < mToolbarCache.size(); i++) {
- Pair<Long, RemoteSelectionToolbar> toolbarPair = mToolbarCache.valueAt(i);
- if (toolbarPair.first == widgetToken) {
- return toolbarPair.second;
- }
- }
- return null;
- }
-
- private void removeRemoteSelectionToolbarByTokenLocked(long widgetToken) {
- for (int i = 0; i < mToolbarCache.size(); i++) {
- Pair<Long, RemoteSelectionToolbar> toolbarPair = mToolbarCache.valueAt(i);
- if (toolbarPair.first == widgetToken) {
- mToolbarCache.remove(mToolbarCache.keyAt(i));
- return;
- }
- }
- }
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- int size = mToolbarCache.size();
- pw.print("number selectionToolbar: "); pw.println(size);
- String pfx = " ";
- for (int i = 0; i < size; i++) {
- pw.print("#"); pw.println(i);
- int callingUid = mToolbarCache.keyAt(i);
- pw.print(pfx); pw.print("callingUid: "); pw.println(callingUid);
- Pair<Long, RemoteSelectionToolbar> toolbarPair = mToolbarCache.valueAt(i);
- RemoteSelectionToolbar selectionToolbar = toolbarPair.second;
- pw.print(pfx); pw.print("selectionToolbar: ");
- selectionToolbar.dump(pfx, pw);
- pw.println();
- }
- }
-}
-
diff --git a/core/java/android/service/selectiontoolbar/FloatingToolbarRoot.java b/core/java/android/service/selectiontoolbar/FloatingToolbarRoot.java
deleted file mode 100644
index adc9251d89be..000000000000
--- a/core/java/android/service/selectiontoolbar/FloatingToolbarRoot.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.service.selectiontoolbar;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.graphics.Rect;
-import android.os.IBinder;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.widget.LinearLayout;
-
-import java.io.PrintWriter;
-
-/**
- * This class is the root view for the selection toolbar. It is responsible for
- * detecting the click on the item and to also transfer input focus to the application.
- *
- * @hide
- */
-@SuppressLint("ViewConstructor")
-public class FloatingToolbarRoot extends LinearLayout {
-
- private static final boolean DEBUG = false;
- private static final String TAG = "FloatingToolbarRoot";
-
- private final IBinder mTargetInputToken;
- private final SelectionToolbarRenderService.TransferTouchListener mTransferTouchListener;
- private final Rect mContentRect = new Rect();
-
- private int mLastDownX = -1;
- private int mLastDownY = -1;
-
- public FloatingToolbarRoot(Context context, IBinder targetInputToken,
- SelectionToolbarRenderService.TransferTouchListener transferTouchListener) {
- super(context);
- mTargetInputToken = targetInputToken;
- mTransferTouchListener = transferTouchListener;
- setFocusable(false);
- }
-
- /**
- * Sets the Rect that shows the selection toolbar content.
- */
- public void setContentRect(Rect contentRect) {
- mContentRect.set(contentRect);
- }
-
- @Override
- @SuppressLint("ClickableViewAccessibility")
- public boolean dispatchTouchEvent(MotionEvent event) {
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
- mLastDownX = (int) event.getX();
- mLastDownY = (int) event.getY();
- if (DEBUG) {
- Log.d(TAG, "downX=" + mLastDownX + " downY=" + mLastDownY);
- }
- // TODO(b/215497659): Check FLAG_WINDOW_IS_PARTIALLY_OBSCURED
- if (!mContentRect.contains(mLastDownX, mLastDownY)) {
- if (DEBUG) {
- Log.d(TAG, "Transfer touch focus to application.");
- }
- mTransferTouchListener.onTransferTouch(getViewRootImpl().getInputToken(),
- mTargetInputToken);
- }
- }
- return super.dispatchTouchEvent(event);
- }
-
- void dump(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.println("FloatingToolbarRoot:");
- pw.print(prefix + " "); pw.print("last down X: "); pw.println(mLastDownX);
- pw.print(prefix + " "); pw.print("last down Y: "); pw.println(mLastDownY);
- }
-}
diff --git a/core/java/android/service/selectiontoolbar/ISelectionToolbarRenderService.aidl b/core/java/android/service/selectiontoolbar/ISelectionToolbarRenderService.aidl
deleted file mode 100644
index 79281b8b361d..000000000000
--- a/core/java/android/service/selectiontoolbar/ISelectionToolbarRenderService.aidl
+++ /dev/null
@@ -1,32 +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 android.service.selectiontoolbar;
-
-import android.view.selectiontoolbar.ISelectionToolbarCallback;
-import android.view.selectiontoolbar.ShowInfo;
-
-/**
- * The service to render the selection toolbar menus.
- *
- * @hide
- */
-oneway interface ISelectionToolbarRenderService {
- void onConnected(in IBinder callback);
- void onShow(int callingUid, in ShowInfo showInfo, in ISelectionToolbarCallback callback);
- void onHide(long widgetToken);
- void onDismiss(int callingUid, long widgetToken);
-}
diff --git a/core/java/android/service/selectiontoolbar/OWNERS b/core/java/android/service/selectiontoolbar/OWNERS
deleted file mode 100644
index 5500b92868dd..000000000000
--- a/core/java/android/service/selectiontoolbar/OWNERS
+++ /dev/null
@@ -1,10 +0,0 @@
-# Bug component: 709498
-
-augale@google.com
-joannechung@google.com
-licha@google.com
-lpeter@google.com
-svetoslavganov@google.com
-toki@google.com
-tonymak@google.com
-tymtsai@google.com \ No newline at end of file
diff --git a/core/java/android/service/selectiontoolbar/RemoteSelectionToolbar.java b/core/java/android/service/selectiontoolbar/RemoteSelectionToolbar.java
deleted file mode 100644
index 59e3a5e70376..000000000000
--- a/core/java/android/service/selectiontoolbar/RemoteSelectionToolbar.java
+++ /dev/null
@@ -1,1398 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.service.selectiontoolbar;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.drawable.AnimatedVectorDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.IBinder;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Size;
-import android.view.ContextThemeWrapper;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.SurfaceControlViewHost;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-import android.view.animation.Transformation;
-import android.view.selectiontoolbar.ShowInfo;
-import android.view.selectiontoolbar.ToolbarMenuItem;
-import android.view.selectiontoolbar.WidgetInfo;
-import android.widget.ArrayAdapter;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import com.android.internal.R;
-import com.android.internal.util.Preconditions;
-import com.android.internal.widget.floatingtoolbar.FloatingToolbar;
-
-import java.io.PrintWriter;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * This class is responsible for rendering/animation of the selection toolbar in the remote
- * system process. It holds 2 panels (i.e. main panel and overflow panel) and an overflow
- * button to transition between panels.
- *
- * @hide
- */
-// TODO(b/215497659): share code with LocalFloatingToolbarPopup
-final class RemoteSelectionToolbar {
- private static final String TAG = "RemoteSelectionToolbar";
-
- /* Minimum and maximum number of items allowed in the overflow. */
- private static final int MIN_OVERFLOW_SIZE = 2;
- private static final int MAX_OVERFLOW_SIZE = 4;
-
- private final Context mContext;
-
- /* Margins between the popup window and its content. */
- private final int mMarginHorizontal;
- private final int mMarginVertical;
-
- /* View components */
- private final ViewGroup mContentContainer; // holds all contents.
- private final ViewGroup mMainPanel; // holds menu items that are initially displayed.
- // holds menu items hidden in the overflow.
- private final OverflowPanel mOverflowPanel;
- private final ImageButton mOverflowButton; // opens/closes the overflow.
- /* overflow button drawables. */
- private final Drawable mArrow;
- private final Drawable mOverflow;
- private final AnimatedVectorDrawable mToArrow;
- private final AnimatedVectorDrawable mToOverflow;
-
- private final OverflowPanelViewHelper mOverflowPanelViewHelper;
-
- /* Animation interpolators. */
- private final Interpolator mLogAccelerateInterpolator;
- private final Interpolator mFastOutSlowInInterpolator;
- private final Interpolator mLinearOutSlowInInterpolator;
- private final Interpolator mFastOutLinearInInterpolator;
-
- /* Animations. */
- private final AnimatorSet mShowAnimation;
- private final AnimatorSet mDismissAnimation;
- private final AnimatorSet mHideAnimation;
- private final AnimationSet mOpenOverflowAnimation;
- private final AnimationSet mCloseOverflowAnimation;
- private final Animation.AnimationListener mOverflowAnimationListener;
-
- private final Rect mViewPortOnScreen = new Rect(); // portion of screen we can draw in.
-
- private final int mLineHeight;
- private final int mIconTextSpacing;
-
- private final long mSelectionToolbarToken;
- private IBinder mHostInputToken;
- private final SelectionToolbarRenderService.RemoteCallbackWrapper mCallbackWrapper;
- private final SelectionToolbarRenderService.TransferTouchListener mTransferTouchListener;
- private int mPopupWidth;
- private int mPopupHeight;
- // Coordinates to show the toolbar relative to the specified view port
- private final Point mRelativeCoordsForToolbar = new Point();
- private List<ToolbarMenuItem> mMenuItems;
- private SurfaceControlViewHost mSurfaceControlViewHost;
- private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
-
- /**
- * @see OverflowPanelViewHelper#preparePopupContent().
- */
- private final Runnable mPreparePopupContentRTLHelper = new Runnable() {
- @Override
- public void run() {
- setPanelsStatesAtRestingPosition();
- mContentContainer.setAlpha(1);
- }
- };
-
- private boolean mDismissed = true; // tracks whether this popup is dismissed or dismissing.
- private boolean mHidden; // tracks whether this popup is hidden or hiding.
-
- /* Calculated sizes for panels and overflow button. */
- private final Size mOverflowButtonSize;
- private Size mOverflowPanelSize; // Should be null when there is no overflow.
- private Size mMainPanelSize;
-
- /* Menu items and click listeners */
- private final View.OnClickListener mMenuItemButtonOnClickListener;
-
- private boolean mOpenOverflowUpwards; // Whether the overflow opens upwards or downwards.
- private boolean mIsOverflowOpen;
-
- private int mTransitionDurationScale; // Used to scale the toolbar transition duration.
-
- private final Rect mPreviousContentRect = new Rect();
-
- private final Rect mTempContentRect = new Rect();
- private final Rect mTempContentRectForRoot = new Rect();
- private final int[] mTempCoords = new int[2];
-
- RemoteSelectionToolbar(Context context, long selectionToolbarToken, ShowInfo showInfo,
- SelectionToolbarRenderService.RemoteCallbackWrapper callbackWrapper,
- SelectionToolbarRenderService.TransferTouchListener transferTouchListener) {
- mContext = applyDefaultTheme(context, showInfo.isIsLightTheme());
- mSelectionToolbarToken = selectionToolbarToken;
- mCallbackWrapper = callbackWrapper;
- mTransferTouchListener = transferTouchListener;
- mHostInputToken = showInfo.getHostInputToken();
- mContentContainer = createContentContainer(mContext);
- mMarginHorizontal = mContext.getResources()
- .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin);
- mMarginVertical = mContext.getResources()
- .getDimensionPixelSize(R.dimen.floating_toolbar_vertical_margin);
- mLineHeight = mContext.getResources()
- .getDimensionPixelSize(R.dimen.floating_toolbar_height);
- mIconTextSpacing = mContext.getResources()
- .getDimensionPixelSize(R.dimen.floating_toolbar_icon_text_spacing);
-
- // Interpolators
- mLogAccelerateInterpolator = new LogAccelerateInterpolator();
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(
- mContext, android.R.interpolator.fast_out_slow_in);
- mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(
- mContext, android.R.interpolator.linear_out_slow_in);
- mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(
- mContext, android.R.interpolator.fast_out_linear_in);
-
- // Drawables. Needed for views.
- mArrow = mContext.getResources()
- .getDrawable(R.drawable.ft_avd_tooverflow, mContext.getTheme());
- mArrow.setAutoMirrored(true);
- mOverflow = mContext.getResources()
- .getDrawable(R.drawable.ft_avd_toarrow, mContext.getTheme());
- mOverflow.setAutoMirrored(true);
- mToArrow = (AnimatedVectorDrawable) mContext.getResources()
- .getDrawable(R.drawable.ft_avd_toarrow_animation, mContext.getTheme());
- mToArrow.setAutoMirrored(true);
- mToOverflow = (AnimatedVectorDrawable) mContext.getResources()
- .getDrawable(R.drawable.ft_avd_tooverflow_animation, mContext.getTheme());
- mToOverflow.setAutoMirrored(true);
-
- // Views
- mOverflowButton = createOverflowButton();
- mOverflowButtonSize = measure(mOverflowButton);
- mMainPanel = createMainPanel();
- mOverflowPanelViewHelper = new OverflowPanelViewHelper(mContext, mIconTextSpacing);
- mOverflowPanel = createOverflowPanel();
-
- // Animation. Need views.
- mOverflowAnimationListener = createOverflowAnimationListener();
- mOpenOverflowAnimation = new AnimationSet(true);
- mOpenOverflowAnimation.setAnimationListener(mOverflowAnimationListener);
- mCloseOverflowAnimation = new AnimationSet(true);
- mCloseOverflowAnimation.setAnimationListener(mOverflowAnimationListener);
- mShowAnimation = createEnterAnimation(mContentContainer,
- new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- updateFloatingToolbarRootContentRect();
- }
- });
- mDismissAnimation = createExitAnimation(
- mContentContainer,
- 150, // startDelay
- new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- // TODO(b/215497659): should dismiss window after animation
- mContentContainer.removeAllViews();
- mSurfaceControlViewHost.release();
- mSurfaceControlViewHost = null;
- mSurfacePackage = null;
- }
- });
- mHideAnimation = createExitAnimation(
- mContentContainer,
- 0, // startDelay
- null); // TODO(b/215497659): should handle hide after animation
- mMenuItemButtonOnClickListener = v -> {
- Object tag = v.getTag();
- if (!(tag instanceof ToolbarMenuItem)) {
- return;
- }
- mCallbackWrapper.onMenuItemClicked((ToolbarMenuItem) tag);
- };
- }
-
- private void updateFloatingToolbarRootContentRect() {
- if (mSurfaceControlViewHost == null) {
- return;
- }
- final FloatingToolbarRoot root = (FloatingToolbarRoot) mSurfaceControlViewHost.getView();
- mContentContainer.getLocationOnScreen(mTempCoords);
- int contentLeft = mTempCoords[0];
- int contentTop = mTempCoords[1];
- mTempContentRectForRoot.set(contentLeft, contentTop,
- contentLeft + mContentContainer.getWidth(),
- contentTop + mContentContainer.getHeight());
- root.setContentRect(mTempContentRectForRoot);
- }
-
- private WidgetInfo createWidgetInfo() {
- mTempContentRect.set(mRelativeCoordsForToolbar.x, mRelativeCoordsForToolbar.y,
- mRelativeCoordsForToolbar.x + mPopupWidth,
- mRelativeCoordsForToolbar.y + mPopupHeight);
- return new WidgetInfo(mSelectionToolbarToken, mTempContentRect, getSurfacePackage());
- }
-
- private SurfaceControlViewHost.SurfacePackage getSurfacePackage() {
- if (mSurfaceControlViewHost == null) {
- final FloatingToolbarRoot contentHolder = new FloatingToolbarRoot(mContext,
- mHostInputToken, mTransferTouchListener);
- contentHolder.addView(mContentContainer);
- mSurfaceControlViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(),
- mHostInputToken, "RemoteSelectionToolbar");
- mSurfaceControlViewHost.setView(contentHolder, mPopupWidth, mPopupHeight);
- }
- if (mSurfacePackage == null) {
- mSurfacePackage = mSurfaceControlViewHost.getSurfacePackage();
- }
- return mSurfacePackage;
- }
-
- private void layoutMenuItems(
- List<ToolbarMenuItem> menuItems,
- int suggestedWidth) {
- cancelOverflowAnimations();
- clearPanels();
-
- menuItems = layoutMainPanelItems(menuItems, getAdjustedToolbarWidth(suggestedWidth));
- if (!menuItems.isEmpty()) {
- // Add remaining items to the overflow.
- layoutOverflowPanelItems(menuItems);
- }
- updatePopupSize();
- }
-
- public void onToolbarShowTimeout() {
- mCallbackWrapper.onToolbarShowTimeout();
- }
-
- /**
- * Show the specified selection toolbar.
- */
- public void show(ShowInfo showInfo) {
- debugLog("show() for " + showInfo);
-
- mMenuItems = showInfo.getMenuItems();
- mViewPortOnScreen.set(showInfo.getViewPortOnScreen());
-
- debugLog("show(): layoutRequired=" + showInfo.isLayoutRequired());
- if (showInfo.isLayoutRequired()) {
- layoutMenuItems(mMenuItems, showInfo.getSuggestedWidth());
- }
- Rect contentRect = showInfo.getContentRect();
- if (!isShowing()) {
- show(contentRect);
- } else if (!mPreviousContentRect.equals(contentRect)) {
- updateCoordinates(contentRect);
- }
- mPreviousContentRect.set(contentRect);
- }
-
- private void show(Rect contentRectOnScreen) {
- Objects.requireNonNull(contentRectOnScreen);
-
- mHidden = false;
- mDismissed = false;
- cancelDismissAndHideAnimations();
- cancelOverflowAnimations();
- refreshCoordinatesAndOverflowDirection(contentRectOnScreen);
- preparePopupContent();
- mCallbackWrapper.onShown(createWidgetInfo());
- // TODO(b/215681595): Use Choreographer to coordinate for show between different thread
- mShowAnimation.start();
- }
-
- /**
- * Dismiss the specified selection toolbar.
- */
- public void dismiss(long floatingToolbarToken) {
- debugLog("dismiss for " + floatingToolbarToken);
- if (mDismissed) {
- return;
- }
- mHidden = false;
- mDismissed = true;
-
- mHideAnimation.cancel();
- mDismissAnimation.start();
- }
-
- /**
- * Hide the specified selection toolbar.
- */
- public void hide(long floatingToolbarToken) {
- debugLog("hide for " + floatingToolbarToken);
- if (!isShowing()) {
- return;
- }
-
- mHidden = true;
- mHideAnimation.start();
- }
-
- public boolean isShowing() {
- return !mDismissed && !mHidden;
- }
-
- private void updateCoordinates(Rect contentRectOnScreen) {
- Objects.requireNonNull(contentRectOnScreen);
-
- if (!isShowing()) {
- return;
- }
- cancelOverflowAnimations();
- refreshCoordinatesAndOverflowDirection(contentRectOnScreen);
- preparePopupContent();
- WidgetInfo widgetInfo = createWidgetInfo();
- mSurfaceControlViewHost.relayout(mPopupWidth, mPopupHeight);
- mCallbackWrapper.onWidgetUpdated(widgetInfo);
- }
-
- private void refreshCoordinatesAndOverflowDirection(Rect contentRectOnScreen) {
- // Initialize x ensuring that the toolbar isn't rendered behind the nav bar in
- // landscape.
- final int x = Math.min(
- contentRectOnScreen.centerX() - mPopupWidth / 2,
- mViewPortOnScreen.right - mPopupWidth);
-
- final int y;
-
- final int availableHeightAboveContent =
- contentRectOnScreen.top - mViewPortOnScreen.top;
- final int availableHeightBelowContent =
- mViewPortOnScreen.bottom - contentRectOnScreen.bottom;
-
- final int margin = 2 * mMarginVertical;
- final int toolbarHeightWithVerticalMargin = mLineHeight + margin;
-
- if (!hasOverflow()) {
- if (availableHeightAboveContent >= toolbarHeightWithVerticalMargin) {
- // There is enough space at the top of the content.
- y = contentRectOnScreen.top - toolbarHeightWithVerticalMargin;
- } else if (availableHeightBelowContent >= toolbarHeightWithVerticalMargin) {
- // There is enough space at the bottom of the content.
- y = contentRectOnScreen.bottom;
- } else if (availableHeightBelowContent >= mLineHeight) {
- // Just enough space to fit the toolbar with no vertical margins.
- y = contentRectOnScreen.bottom - mMarginVertical;
- } else {
- // Not enough space. Prefer to position as high as possible.
- y = Math.max(
- mViewPortOnScreen.top,
- contentRectOnScreen.top - toolbarHeightWithVerticalMargin);
- }
- } else {
- // Has an overflow.
- final int minimumOverflowHeightWithMargin =
- calculateOverflowHeight(MIN_OVERFLOW_SIZE) + margin;
- final int availableHeightThroughContentDown =
- mViewPortOnScreen.bottom - contentRectOnScreen.top
- + toolbarHeightWithVerticalMargin;
- final int availableHeightThroughContentUp =
- contentRectOnScreen.bottom - mViewPortOnScreen.top
- + toolbarHeightWithVerticalMargin;
-
- if (availableHeightAboveContent >= minimumOverflowHeightWithMargin) {
- // There is enough space at the top of the content rect for the overflow.
- // Position above and open upwards.
- updateOverflowHeight(availableHeightAboveContent - margin);
- y = contentRectOnScreen.top - mPopupHeight;
- mOpenOverflowUpwards = true;
- } else if (availableHeightAboveContent >= toolbarHeightWithVerticalMargin
- && availableHeightThroughContentDown >= minimumOverflowHeightWithMargin) {
- // There is enough space at the top of the content rect for the main panel
- // but not the overflow.
- // Position above but open downwards.
- updateOverflowHeight(availableHeightThroughContentDown - margin);
- y = contentRectOnScreen.top - toolbarHeightWithVerticalMargin;
- mOpenOverflowUpwards = false;
- } else if (availableHeightBelowContent >= minimumOverflowHeightWithMargin) {
- // There is enough space at the bottom of the content rect for the overflow.
- // Position below and open downwards.
- updateOverflowHeight(availableHeightBelowContent - margin);
- y = contentRectOnScreen.bottom;
- mOpenOverflowUpwards = false;
- } else if (availableHeightBelowContent >= toolbarHeightWithVerticalMargin
- && mViewPortOnScreen.height() >= minimumOverflowHeightWithMargin) {
- // There is enough space at the bottom of the content rect for the main panel
- // but not the overflow.
- // Position below but open upwards.
- updateOverflowHeight(availableHeightThroughContentUp - margin);
- y = contentRectOnScreen.bottom + toolbarHeightWithVerticalMargin
- - mPopupHeight;
- mOpenOverflowUpwards = true;
- } else {
- // Not enough space.
- // Position at the top of the view port and open downwards.
- updateOverflowHeight(mViewPortOnScreen.height() - margin);
- y = mViewPortOnScreen.top;
- mOpenOverflowUpwards = false;
- }
- }
- mRelativeCoordsForToolbar.set(x, y);
- }
-
- private void cancelDismissAndHideAnimations() {
- mDismissAnimation.cancel();
- mHideAnimation.cancel();
- }
-
- private void cancelOverflowAnimations() {
- mContentContainer.clearAnimation();
- mMainPanel.animate().cancel();
- mOverflowPanel.animate().cancel();
- mToArrow.stop();
- mToOverflow.stop();
- }
-
- private void openOverflow() {
- final int targetWidth = mOverflowPanelSize.getWidth();
- final int targetHeight = mOverflowPanelSize.getHeight();
- final int startWidth = mContentContainer.getWidth();
- final int startHeight = mContentContainer.getHeight();
- final float startY = mContentContainer.getY();
- final float left = mContentContainer.getX();
- final float right = left + mContentContainer.getWidth();
- Animation widthAnimation = new Animation() {
- @Override
- protected void applyTransformation(float interpolatedTime, Transformation t) {
- int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth));
- setWidth(mContentContainer, startWidth + deltaWidth);
- if (isInRTLMode()) {
- mContentContainer.setX(left);
-
- // Lock the panels in place.
- mMainPanel.setX(0);
- mOverflowPanel.setX(0);
- } else {
- mContentContainer.setX(right - mContentContainer.getWidth());
-
- // Offset the panels' positions so they look like they're locked in place
- // on the screen.
- mMainPanel.setX(mContentContainer.getWidth() - startWidth);
- mOverflowPanel.setX(mContentContainer.getWidth() - targetWidth);
- }
- }
- };
- Animation heightAnimation = new Animation() {
- @Override
- protected void applyTransformation(float interpolatedTime, Transformation t) {
- int deltaHeight = (int) (interpolatedTime * (targetHeight - startHeight));
- setHeight(mContentContainer, startHeight + deltaHeight);
- if (mOpenOverflowUpwards) {
- mContentContainer.setY(
- startY - (mContentContainer.getHeight() - startHeight));
- positionContentYCoordinatesIfOpeningOverflowUpwards();
- }
- }
- };
- final float overflowButtonStartX = mOverflowButton.getX();
- final float overflowButtonTargetX =
- isInRTLMode() ? overflowButtonStartX + targetWidth - mOverflowButton.getWidth()
- : overflowButtonStartX - targetWidth + mOverflowButton.getWidth();
- Animation overflowButtonAnimation = new Animation() {
- @Override
- protected void applyTransformation(float interpolatedTime, Transformation t) {
- float overflowButtonX = overflowButtonStartX
- + interpolatedTime * (overflowButtonTargetX - overflowButtonStartX);
- float deltaContainerWidth =
- isInRTLMode() ? 0 : mContentContainer.getWidth() - startWidth;
- float actualOverflowButtonX = overflowButtonX + deltaContainerWidth;
- mOverflowButton.setX(actualOverflowButtonX);
- updateFloatingToolbarRootContentRect();
- }
- };
- widthAnimation.setInterpolator(mLogAccelerateInterpolator);
- widthAnimation.setDuration(getAnimationDuration());
- heightAnimation.setInterpolator(mFastOutSlowInInterpolator);
- heightAnimation.setDuration(getAnimationDuration());
- overflowButtonAnimation.setInterpolator(mFastOutSlowInInterpolator);
- overflowButtonAnimation.setDuration(getAnimationDuration());
- mOpenOverflowAnimation.getAnimations().clear();
- mOpenOverflowAnimation.addAnimation(widthAnimation);
- mOpenOverflowAnimation.addAnimation(heightAnimation);
- mOpenOverflowAnimation.addAnimation(overflowButtonAnimation);
- mContentContainer.startAnimation(mOpenOverflowAnimation);
- mIsOverflowOpen = true;
- mMainPanel.animate()
- .alpha(0).withLayer()
- .setInterpolator(mLinearOutSlowInInterpolator)
- .setDuration(250)
- .start();
- mOverflowPanel.setAlpha(1); // fadeIn in 0ms.
- }
-
- private void closeOverflow() {
- final int targetWidth = mMainPanelSize.getWidth();
- final int startWidth = mContentContainer.getWidth();
- final float left = mContentContainer.getX();
- final float right = left + mContentContainer.getWidth();
- Animation widthAnimation = new Animation() {
- @Override
- protected void applyTransformation(float interpolatedTime, Transformation t) {
- int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth));
- setWidth(mContentContainer, startWidth + deltaWidth);
- if (isInRTLMode()) {
- mContentContainer.setX(left);
-
- // Lock the panels in place.
- mMainPanel.setX(0);
- mOverflowPanel.setX(0);
- } else {
- mContentContainer.setX(right - mContentContainer.getWidth());
-
- // Offset the panels' positions so they look like they're locked in place
- // on the screen.
- mMainPanel.setX(mContentContainer.getWidth() - targetWidth);
- mOverflowPanel.setX(mContentContainer.getWidth() - startWidth);
- }
- }
- };
- final int targetHeight = mMainPanelSize.getHeight();
- final int startHeight = mContentContainer.getHeight();
- final float bottom = mContentContainer.getY() + mContentContainer.getHeight();
- Animation heightAnimation = new Animation() {
- @Override
- protected void applyTransformation(float interpolatedTime, Transformation t) {
- int deltaHeight = (int) (interpolatedTime * (targetHeight - startHeight));
- setHeight(mContentContainer, startHeight + deltaHeight);
- if (mOpenOverflowUpwards) {
- mContentContainer.setY(bottom - mContentContainer.getHeight());
- positionContentYCoordinatesIfOpeningOverflowUpwards();
- }
- }
- };
- final float overflowButtonStartX = mOverflowButton.getX();
- final float overflowButtonTargetX =
- isInRTLMode() ? overflowButtonStartX - startWidth + mOverflowButton.getWidth()
- : overflowButtonStartX + startWidth - mOverflowButton.getWidth();
- Animation overflowButtonAnimation = new Animation() {
- @Override
- protected void applyTransformation(float interpolatedTime, Transformation t) {
- float overflowButtonX = overflowButtonStartX
- + interpolatedTime * (overflowButtonTargetX - overflowButtonStartX);
- float deltaContainerWidth =
- isInRTLMode() ? 0 : mContentContainer.getWidth() - startWidth;
- float actualOverflowButtonX = overflowButtonX + deltaContainerWidth;
- mOverflowButton.setX(actualOverflowButtonX);
- updateFloatingToolbarRootContentRect();
- }
- };
- widthAnimation.setInterpolator(mFastOutSlowInInterpolator);
- widthAnimation.setDuration(getAnimationDuration());
- heightAnimation.setInterpolator(mLogAccelerateInterpolator);
- heightAnimation.setDuration(getAnimationDuration());
- overflowButtonAnimation.setInterpolator(mFastOutSlowInInterpolator);
- overflowButtonAnimation.setDuration(getAnimationDuration());
- mCloseOverflowAnimation.getAnimations().clear();
- mCloseOverflowAnimation.addAnimation(widthAnimation);
- mCloseOverflowAnimation.addAnimation(heightAnimation);
- mCloseOverflowAnimation.addAnimation(overflowButtonAnimation);
- mContentContainer.startAnimation(mCloseOverflowAnimation);
- mIsOverflowOpen = false;
- mMainPanel.animate()
- .alpha(1).withLayer()
- .setInterpolator(mFastOutLinearInInterpolator)
- .setDuration(100)
- .start();
- mOverflowPanel.animate()
- .alpha(0).withLayer()
- .setInterpolator(mLinearOutSlowInInterpolator)
- .setDuration(150)
- .start();
- }
-
- /**
- * Defines the position of the floating toolbar popup panels when transition animation has
- * stopped.
- */
- private void setPanelsStatesAtRestingPosition() {
- mOverflowButton.setEnabled(true);
- mOverflowPanel.awakenScrollBars();
-
- if (mIsOverflowOpen) {
- // Set open state.
- final Size containerSize = mOverflowPanelSize;
- setSize(mContentContainer, containerSize);
- mMainPanel.setAlpha(0);
- mMainPanel.setVisibility(View.INVISIBLE);
- mOverflowPanel.setAlpha(1);
- mOverflowPanel.setVisibility(View.VISIBLE);
- mOverflowButton.setImageDrawable(mArrow);
- mOverflowButton.setContentDescription(mContext.getString(
- R.string.floating_toolbar_close_overflow_description));
-
- // Update x-coordinates depending on RTL state.
- if (isInRTLMode()) {
- mContentContainer.setX(mMarginHorizontal); // align left
- mMainPanel.setX(0); // align left
- mOverflowButton.setX(// align right
- containerSize.getWidth() - mOverflowButtonSize.getWidth());
- mOverflowPanel.setX(0); // align left
- } else {
- mContentContainer.setX(// align right
- mPopupWidth - containerSize.getWidth() - mMarginHorizontal);
- mMainPanel.setX(-mContentContainer.getX()); // align right
- mOverflowButton.setX(0); // align left
- mOverflowPanel.setX(0); // align left
- }
-
- // Update y-coordinates depending on overflow's open direction.
- if (mOpenOverflowUpwards) {
- mContentContainer.setY(mMarginVertical); // align top
- mMainPanel.setY(// align bottom
- containerSize.getHeight() - mContentContainer.getHeight());
- mOverflowButton.setY(// align bottom
- containerSize.getHeight() - mOverflowButtonSize.getHeight());
- mOverflowPanel.setY(0); // align top
- } else {
- // opens downwards.
- mContentContainer.setY(mMarginVertical); // align top
- mMainPanel.setY(0); // align top
- mOverflowButton.setY(0); // align top
- mOverflowPanel.setY(mOverflowButtonSize.getHeight()); // align bottom
- }
- } else {
- // Overflow not open. Set closed state.
- final Size containerSize = mMainPanelSize;
- setSize(mContentContainer, containerSize);
- mMainPanel.setAlpha(1);
- mMainPanel.setVisibility(View.VISIBLE);
- mOverflowPanel.setAlpha(0);
- mOverflowPanel.setVisibility(View.INVISIBLE);
- mOverflowButton.setImageDrawable(mOverflow);
- mOverflowButton.setContentDescription(mContext.getString(
- R.string.floating_toolbar_open_overflow_description));
-
- if (hasOverflow()) {
- // Update x-coordinates depending on RTL state.
- if (isInRTLMode()) {
- mContentContainer.setX(mMarginHorizontal); // align left
- mMainPanel.setX(0); // align left
- mOverflowButton.setX(0); // align left
- mOverflowPanel.setX(0); // align left
- } else {
- mContentContainer.setX(// align right
- mPopupWidth - containerSize.getWidth() - mMarginHorizontal);
- mMainPanel.setX(0); // align left
- mOverflowButton.setX(// align right
- containerSize.getWidth() - mOverflowButtonSize.getWidth());
- mOverflowPanel.setX(// align right
- containerSize.getWidth() - mOverflowPanelSize.getWidth());
- }
-
- // Update y-coordinates depending on overflow's open direction.
- if (mOpenOverflowUpwards) {
- mContentContainer.setY(// align bottom
- mMarginVertical + mOverflowPanelSize.getHeight()
- - containerSize.getHeight());
- mMainPanel.setY(0); // align top
- mOverflowButton.setY(0); // align top
- mOverflowPanel.setY(// align bottom
- containerSize.getHeight() - mOverflowPanelSize.getHeight());
- } else {
- // opens downwards.
- mContentContainer.setY(mMarginVertical); // align top
- mMainPanel.setY(0); // align top
- mOverflowButton.setY(0); // align top
- mOverflowPanel.setY(mOverflowButtonSize.getHeight()); // align bottom
- }
- } else {
- // No overflow.
- mContentContainer.setX(mMarginHorizontal); // align left
- mContentContainer.setY(mMarginVertical); // align top
- mMainPanel.setX(0); // align left
- mMainPanel.setY(0); // align top
- }
- }
- }
-
- private void updateOverflowHeight(int suggestedHeight) {
- if (hasOverflow()) {
- final int maxItemSize =
- (suggestedHeight - mOverflowButtonSize.getHeight()) / mLineHeight;
- final int newHeight = calculateOverflowHeight(maxItemSize);
- if (mOverflowPanelSize.getHeight() != newHeight) {
- mOverflowPanelSize = new Size(mOverflowPanelSize.getWidth(), newHeight);
- }
- setSize(mOverflowPanel, mOverflowPanelSize);
- if (mIsOverflowOpen) {
- setSize(mContentContainer, mOverflowPanelSize);
- if (mOpenOverflowUpwards) {
- final int deltaHeight = mOverflowPanelSize.getHeight() - newHeight;
- mContentContainer.setY(mContentContainer.getY() + deltaHeight);
- mOverflowButton.setY(mOverflowButton.getY() - deltaHeight);
- }
- } else {
- setSize(mContentContainer, mMainPanelSize);
- }
- updatePopupSize();
- }
- }
-
- private void updatePopupSize() {
- int width = 0;
- int height = 0;
- if (mMainPanelSize != null) {
- width = Math.max(width, mMainPanelSize.getWidth());
- height = Math.max(height, mMainPanelSize.getHeight());
- }
- if (mOverflowPanelSize != null) {
- width = Math.max(width, mOverflowPanelSize.getWidth());
- height = Math.max(height, mOverflowPanelSize.getHeight());
- }
-
- mPopupWidth = width + mMarginHorizontal * 2;
- mPopupHeight = height + mMarginVertical * 2;
- maybeComputeTransitionDurationScale();
- }
-
- private int getAdjustedToolbarWidth(int suggestedWidth) {
- int width = suggestedWidth;
- int maximumWidth = mViewPortOnScreen.width() - 2 * mContext.getResources()
- .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin);
- if (width <= 0) {
- width = mContext.getResources()
- .getDimensionPixelSize(R.dimen.floating_toolbar_preferred_width);
- }
- return Math.min(width, maximumWidth);
- }
-
- private boolean isInRTLMode() {
- return mContext.getApplicationInfo().hasRtlSupport()
- && mContext.getResources().getConfiguration().getLayoutDirection()
- == View.LAYOUT_DIRECTION_RTL;
- }
-
- private boolean hasOverflow() {
- return mOverflowPanelSize != null;
- }
-
- /**
- * Fits as many menu items in the main panel and returns a list of the menu items that
- * were not fit in.
- *
- * @return The menu items that are not included in this main panel.
- */
- private List<ToolbarMenuItem> layoutMainPanelItems(List<ToolbarMenuItem> menuItems,
- int toolbarWidth) {
- final LinkedList<ToolbarMenuItem> remainingMenuItems = new LinkedList<>();
- // add the overflow menu items to the end of the remainingMenuItems list.
- final LinkedList<ToolbarMenuItem> overflowMenuItems = new LinkedList();
- for (ToolbarMenuItem menuItem : menuItems) {
- if (menuItem.getItemId() != android.R.id.textAssist
- && menuItem.getPriority() == ToolbarMenuItem.PRIORITY_OVERFLOW) {
- overflowMenuItems.add(menuItem);
- } else {
- remainingMenuItems.add(menuItem);
- }
- }
- remainingMenuItems.addAll(overflowMenuItems);
-
- mMainPanel.removeAllViews();
- mMainPanel.setPaddingRelative(0, 0, 0, 0);
-
- int availableWidth = toolbarWidth;
- boolean isFirstItem = true;
- while (!remainingMenuItems.isEmpty()) {
- ToolbarMenuItem menuItem = remainingMenuItems.peek();
- // if this is the first item, regardless of requiresOverflow(), it should be
- // displayed on the main panel. Otherwise all items including this one will be
- // overflow items, and should be displayed in overflow panel.
- if (!isFirstItem && menuItem.getPriority() == ToolbarMenuItem.PRIORITY_OVERFLOW) {
- break;
- }
- final boolean showIcon = isFirstItem && menuItem.getItemId() == R.id.textAssist;
- final View menuItemButton = createMenuItemButton(
- mContext, menuItem, mIconTextSpacing, showIcon);
- if (!showIcon && menuItemButton instanceof LinearLayout) {
- ((LinearLayout) menuItemButton).setGravity(Gravity.CENTER);
- }
- // Adding additional start padding for the first button to even out button spacing.
- if (isFirstItem) {
- menuItemButton.setPaddingRelative(
- (int) (1.5 * menuItemButton.getPaddingStart()),
- menuItemButton.getPaddingTop(),
- menuItemButton.getPaddingEnd(),
- menuItemButton.getPaddingBottom());
- }
- // Adding additional end padding for the last button to even out button spacing.
- boolean isLastItem = remainingMenuItems.size() == 1;
- if (isLastItem) {
- menuItemButton.setPaddingRelative(
- menuItemButton.getPaddingStart(),
- menuItemButton.getPaddingTop(),
- (int) (1.5 * menuItemButton.getPaddingEnd()),
- menuItemButton.getPaddingBottom());
- }
- menuItemButton.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
- final int menuItemButtonWidth = Math.min(
- menuItemButton.getMeasuredWidth(), toolbarWidth);
- // Check if we can fit an item while reserving space for the overflowButton.
- final boolean canFitWithOverflow =
- menuItemButtonWidth <= availableWidth - mOverflowButtonSize.getWidth();
- final boolean canFitNoOverflow =
- isLastItem && menuItemButtonWidth <= availableWidth;
- if (canFitWithOverflow || canFitNoOverflow) {
- menuItemButton.setTag(menuItem);
- menuItemButton.setOnClickListener(mMenuItemButtonOnClickListener);
- // Set tooltips for main panel items, but not overflow items (b/35726766).
- menuItemButton.setTooltipText(menuItem.getTooltipText());
- mMainPanel.addView(menuItemButton);
- final ViewGroup.LayoutParams params = menuItemButton.getLayoutParams();
- params.width = menuItemButtonWidth;
- menuItemButton.setLayoutParams(params);
- availableWidth -= menuItemButtonWidth;
- remainingMenuItems.pop();
- } else {
- break;
- }
- isFirstItem = false;
- }
- if (!remainingMenuItems.isEmpty()) {
- // Reserve space for overflowButton.
- mMainPanel.setPaddingRelative(0, 0, mOverflowButtonSize.getWidth(), 0);
- }
- mMainPanelSize = measure(mMainPanel);
-
- return remainingMenuItems;
- }
-
- private void layoutOverflowPanelItems(List<ToolbarMenuItem> menuItems) {
- ArrayAdapter<ToolbarMenuItem> overflowPanelAdapter =
- (ArrayAdapter<ToolbarMenuItem>) mOverflowPanel.getAdapter();
- overflowPanelAdapter.clear();
- final int size = menuItems.size();
- for (int i = 0; i < size; i++) {
- overflowPanelAdapter.add(menuItems.get(i));
- }
- mOverflowPanel.setAdapter(overflowPanelAdapter);
- if (mOpenOverflowUpwards) {
- mOverflowPanel.setY(0);
- } else {
- mOverflowPanel.setY(mOverflowButtonSize.getHeight());
- }
- int width = Math.max(getOverflowWidth(), mOverflowButtonSize.getWidth());
- int height = calculateOverflowHeight(MAX_OVERFLOW_SIZE);
- mOverflowPanelSize = new Size(width, height);
- setSize(mOverflowPanel, mOverflowPanelSize);
- }
-
- /**
- * Resets the content container and appropriately position it's panels.
- */
- private void preparePopupContent() {
- mContentContainer.removeAllViews();
- // Add views in the specified order so they stack up as expected.
- // Order: overflowPanel, mainPanel, overflowButton.
- if (hasOverflow()) {
- mContentContainer.addView(mOverflowPanel);
- }
- mContentContainer.addView(mMainPanel);
- if (hasOverflow()) {
- mContentContainer.addView(mOverflowButton);
- }
- setPanelsStatesAtRestingPosition();
-
- // The positioning of contents in RTL is wrong when the view is first rendered.
- // Hide the view and post a runnable to recalculate positions and render the view.
- // TODO: Investigate why this happens and fix.
- if (isInRTLMode()) {
- mContentContainer.setAlpha(0);
- mContentContainer.post(mPreparePopupContentRTLHelper);
- }
- }
-
- /**
- * Clears out the panels and their container. Resets their calculated sizes.
- */
- private void clearPanels() {
- mIsOverflowOpen = false;
- mMainPanelSize = null;
- mMainPanel.removeAllViews();
- mOverflowPanelSize = null;
- ArrayAdapter<ToolbarMenuItem> overflowPanelAdapter =
- (ArrayAdapter<ToolbarMenuItem>) mOverflowPanel.getAdapter();
- overflowPanelAdapter.clear();
- mOverflowPanel.setAdapter(overflowPanelAdapter);
- mContentContainer.removeAllViews();
- }
-
- private void positionContentYCoordinatesIfOpeningOverflowUpwards() {
- if (mOpenOverflowUpwards) {
- mMainPanel.setY(mContentContainer.getHeight() - mMainPanelSize.getHeight());
- mOverflowButton.setY(mContentContainer.getHeight() - mOverflowButton.getHeight());
- mOverflowPanel.setY(mContentContainer.getHeight() - mOverflowPanelSize.getHeight());
- }
- }
-
- private int getOverflowWidth() {
- int overflowWidth = 0;
- final int count = mOverflowPanel.getAdapter().getCount();
- for (int i = 0; i < count; i++) {
- ToolbarMenuItem menuItem = (ToolbarMenuItem) mOverflowPanel.getAdapter().getItem(i);
- overflowWidth =
- Math.max(mOverflowPanelViewHelper.calculateWidth(menuItem), overflowWidth);
- }
- return overflowWidth;
- }
-
- private int calculateOverflowHeight(int maxItemSize) {
- // Maximum of 4 items, minimum of 2 if the overflow has to scroll.
- int actualSize = Math.min(
- MAX_OVERFLOW_SIZE,
- Math.min(
- Math.max(MIN_OVERFLOW_SIZE, maxItemSize),
- mOverflowPanel.getCount()));
- int extension = 0;
- if (actualSize < mOverflowPanel.getCount()) {
- // The overflow will require scrolling to get to all the items.
- // Extend the height so that part of the hidden items is displayed.
- extension = (int) (mLineHeight * 0.5f);
- }
- return actualSize * mLineHeight
- + mOverflowButtonSize.getHeight()
- + extension;
- }
-
- /**
- * NOTE: Use only in android.view.animation.* animations. Do not use in android.animation.*
- * animations. See comment about this in the code.
- */
- private int getAnimationDuration() {
- if (mTransitionDurationScale < 150) {
- // For smaller transition, decrease the time.
- return 200;
- } else if (mTransitionDurationScale > 300) {
- // For bigger transition, increase the time.
- return 300;
- }
-
- // Scale the animation duration with getDurationScale(). This allows
- // android.view.animation.* animations to scale just like android.animation.* animations
- // when animator duration scale is adjusted in "Developer Options".
- // For this reason, do not use this method for android.animation.* animations.
- return (int) (250 * ValueAnimator.getDurationScale());
- }
-
- private void maybeComputeTransitionDurationScale() {
- if (mMainPanelSize != null && mOverflowPanelSize != null) {
- int w = mMainPanelSize.getWidth() - mOverflowPanelSize.getWidth();
- int h = mOverflowPanelSize.getHeight() - mMainPanelSize.getHeight();
- mTransitionDurationScale = (int) (Math.sqrt(w * w + h * h)
- / mContentContainer.getContext().getResources().getDisplayMetrics().density);
- }
- }
-
- private ViewGroup createMainPanel() {
- return new LinearLayout(mContext) {
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- if (isOverflowAnimating()) {
- // Update widthMeasureSpec to make sure that this view is not clipped
- // as we offset its coordinates with respect to its parent.
- widthMeasureSpec = MeasureSpec.makeMeasureSpec(
- mMainPanelSize.getWidth(),
- MeasureSpec.EXACTLY);
- }
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- // Intercept the touch event while the overflow is animating.
- return isOverflowAnimating();
- }
- };
- }
-
- private ImageButton createOverflowButton() {
- final ImageButton overflowButton = (ImageButton) LayoutInflater.from(mContext)
- .inflate(R.layout.floating_popup_overflow_button, null);
- overflowButton.setImageDrawable(mOverflow);
- overflowButton.setOnClickListener(v -> {
- if (isShowing()) {
- preparePopupContent();
- WidgetInfo widgetInfo = createWidgetInfo();
- mSurfaceControlViewHost.relayout(mPopupWidth, mPopupHeight);
- mCallbackWrapper.onWidgetUpdated(widgetInfo);
- }
- if (mIsOverflowOpen) {
- overflowButton.setImageDrawable(mToOverflow);
- mToOverflow.start();
- closeOverflow();
- } else {
- overflowButton.setImageDrawable(mToArrow);
- mToArrow.start();
- openOverflow();
- }
- });
- return overflowButton;
- }
-
- private OverflowPanel createOverflowPanel() {
- final OverflowPanel overflowPanel = new OverflowPanel(this);
- overflowPanel.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
- overflowPanel.setDivider(null);
- overflowPanel.setDividerHeight(0);
-
- final ArrayAdapter adapter =
- new ArrayAdapter<ToolbarMenuItem>(mContext, 0) {
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- return mOverflowPanelViewHelper.getView(
- getItem(position), mOverflowPanelSize.getWidth(), convertView);
- }
- };
- overflowPanel.setAdapter(adapter);
- overflowPanel.setOnItemClickListener((parent, view, position, id) -> {
- ToolbarMenuItem menuItem =
- (ToolbarMenuItem) overflowPanel.getAdapter().getItem(position);
- mCallbackWrapper.onMenuItemClicked(menuItem);
- });
- return overflowPanel;
- }
-
- private boolean isOverflowAnimating() {
- final boolean overflowOpening = mOpenOverflowAnimation.hasStarted()
- && !mOpenOverflowAnimation.hasEnded();
- final boolean overflowClosing = mCloseOverflowAnimation.hasStarted()
- && !mCloseOverflowAnimation.hasEnded();
- return overflowOpening || overflowClosing;
- }
-
- private Animation.AnimationListener createOverflowAnimationListener() {
- return new Animation.AnimationListener() {
- @Override
- public void onAnimationStart(Animation animation) {
- // Disable the overflow button while it's animating.
- // It will be re-enabled when the animation stops.
- mOverflowButton.setEnabled(false);
- // Ensure both panels have visibility turned on when the overflow animation
- // starts.
- mMainPanel.setVisibility(View.VISIBLE);
- mOverflowPanel.setVisibility(View.VISIBLE);
- }
-
- @Override
- public void onAnimationEnd(Animation animation) {
- // Posting this because it seems like this is called before the animation
- // actually ends.
- mContentContainer.post(() -> {
- setPanelsStatesAtRestingPosition();
- });
- }
-
- @Override
- public void onAnimationRepeat(Animation animation) {
- }
- };
- }
-
- private static Size measure(View view) {
- Preconditions.checkState(view.getParent() == null);
- view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
- return new Size(view.getMeasuredWidth(), view.getMeasuredHeight());
- }
-
- private static void setSize(View view, int width, int height) {
- view.setMinimumWidth(width);
- view.setMinimumHeight(height);
- ViewGroup.LayoutParams params = view.getLayoutParams();
- params = (params == null) ? new ViewGroup.LayoutParams(0, 0) : params;
- params.width = width;
- params.height = height;
- view.setLayoutParams(params);
- }
-
- private static void setSize(View view, Size size) {
- setSize(view, size.getWidth(), size.getHeight());
- }
-
- private static void setWidth(View view, int width) {
- ViewGroup.LayoutParams params = view.getLayoutParams();
- setSize(view, width, params.height);
- }
-
- private static void setHeight(View view, int height) {
- ViewGroup.LayoutParams params = view.getLayoutParams();
- setSize(view, params.width, height);
- }
-
- /**
- * A custom ListView for the overflow panel.
- */
- private static final class OverflowPanel extends ListView {
-
- private final RemoteSelectionToolbar mPopup;
-
- OverflowPanel(RemoteSelectionToolbar popup) {
- super(Objects.requireNonNull(popup).mContext);
- this.mPopup = popup;
- setScrollBarDefaultDelayBeforeFade(ViewConfiguration.getScrollDefaultDelay() * 3);
- setScrollIndicators(View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_BOTTOM);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- // Update heightMeasureSpec to make sure that this view is not clipped
- // as we offset it's coordinates with respect to its parent.
- int height = mPopup.mOverflowPanelSize.getHeight()
- - mPopup.mOverflowButtonSize.getHeight();
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- if (mPopup.isOverflowAnimating()) {
- // Eat the touch event.
- return true;
- }
- return super.dispatchTouchEvent(ev);
- }
-
- @Override
- protected boolean awakenScrollBars() {
- return super.awakenScrollBars();
- }
- }
-
- /**
- * A custom interpolator used for various floating toolbar animations.
- */
- private static final class LogAccelerateInterpolator implements Interpolator {
-
- private static final int BASE = 100;
- private static final float LOGS_SCALE = 1f / computeLog(1, BASE);
-
- private static float computeLog(float t, int base) {
- return (float) (1 - Math.pow(base, -t));
- }
-
- @Override
- public float getInterpolation(float t) {
- return 1 - computeLog(1 - t, BASE) * LOGS_SCALE;
- }
- }
-
- /**
- * A helper for generating views for the overflow panel.
- */
- private static final class OverflowPanelViewHelper {
- private final Context mContext;
- private final View mCalculator;
- private final int mIconTextSpacing;
- private final int mSidePadding;
-
- OverflowPanelViewHelper(Context context, int iconTextSpacing) {
- mContext = Objects.requireNonNull(context);
- mIconTextSpacing = iconTextSpacing;
- mSidePadding = context.getResources()
- .getDimensionPixelSize(R.dimen.floating_toolbar_overflow_side_padding);
- mCalculator = createMenuButton(null);
- }
-
- public View getView(ToolbarMenuItem menuItem, int minimumWidth, View convertView) {
- Objects.requireNonNull(menuItem);
- if (convertView != null) {
- updateMenuItemButton(
- convertView, menuItem, mIconTextSpacing, shouldShowIcon(menuItem));
- } else {
- convertView = createMenuButton(menuItem);
- }
- convertView.setMinimumWidth(minimumWidth);
- return convertView;
- }
-
- public int calculateWidth(ToolbarMenuItem menuItem) {
- updateMenuItemButton(
- mCalculator, menuItem, mIconTextSpacing, shouldShowIcon(menuItem));
- mCalculator.measure(
- View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
- return mCalculator.getMeasuredWidth();
- }
-
- private View createMenuButton(ToolbarMenuItem menuItem) {
- View button = createMenuItemButton(
- mContext, menuItem, mIconTextSpacing, shouldShowIcon(menuItem));
- button.setPadding(mSidePadding, 0, mSidePadding, 0);
- return button;
- }
-
- private boolean shouldShowIcon(ToolbarMenuItem menuItem) {
- if (menuItem != null) {
- return menuItem.getGroupId() == android.R.id.textAssist;
- }
- return false;
- }
- }
-
- /**
- * Creates and returns a menu button for the specified menu item.
- */
- private static View createMenuItemButton(
- Context context, ToolbarMenuItem menuItem, int iconTextSpacing, boolean showIcon) {
- final View menuItemButton = LayoutInflater.from(context)
- .inflate(R.layout.floating_popup_menu_button, null);
- if (menuItem != null) {
- updateMenuItemButton(menuItemButton, menuItem, iconTextSpacing, showIcon);
- }
- return menuItemButton;
- }
-
- /**
- * Updates the specified menu item button with the specified menu item data.
- */
- private static void updateMenuItemButton(View menuItemButton, ToolbarMenuItem menuItem,
- int iconTextSpacing, boolean showIcon) {
- final TextView buttonText = menuItemButton.findViewById(
- R.id.floating_toolbar_menu_item_text);
- buttonText.setEllipsize(null);
- if (TextUtils.isEmpty(menuItem.getTitle())) {
- buttonText.setVisibility(View.GONE);
- } else {
- buttonText.setVisibility(View.VISIBLE);
- buttonText.setText(menuItem.getTitle());
- }
- final ImageView buttonIcon = menuItemButton.findViewById(
- R.id.floating_toolbar_menu_item_image);
- if (menuItem.getIcon() == null || !showIcon) {
- buttonIcon.setVisibility(View.GONE);
- buttonText.setPaddingRelative(0, 0, 0, 0);
- } else {
- buttonIcon.setVisibility(View.VISIBLE);
- buttonIcon.setImageDrawable(
- menuItem.getIcon().loadDrawable(menuItemButton.getContext()));
- buttonText.setPaddingRelative(iconTextSpacing, 0, 0, 0);
- }
- final CharSequence contentDescription = menuItem.getContentDescription();
- if (TextUtils.isEmpty(contentDescription)) {
- menuItemButton.setContentDescription(menuItem.getTitle());
- } else {
- menuItemButton.setContentDescription(contentDescription);
- }
- }
-
- private static ViewGroup createContentContainer(Context context) {
- ViewGroup contentContainer = (ViewGroup) LayoutInflater.from(context)
- .inflate(R.layout.floating_popup_container, null);
- contentContainer.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
- contentContainer.setTag(FloatingToolbar.FLOATING_TOOLBAR_TAG);
- contentContainer.setClipToOutline(true);
- return contentContainer;
- }
-
- /**
- * Creates an "appear" animation for the specified view.
- *
- * @param view The view to animate
- */
- private static AnimatorSet createEnterAnimation(View view, Animator.AnimatorListener listener) {
- AnimatorSet animation = new AnimatorSet();
- animation.playTogether(
- ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(150));
- animation.addListener(listener);
- return animation;
- }
-
- /**
- * Creates a "disappear" animation for the specified view.
- *
- * @param view The view to animate
- * @param startDelay The start delay of the animation
- * @param listener The animation listener
- */
- private static AnimatorSet createExitAnimation(
- View view, int startDelay, Animator.AnimatorListener listener) {
- AnimatorSet animation = new AnimatorSet();
- animation.playTogether(
- ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(100));
- animation.setStartDelay(startDelay);
- if (listener != null) {
- animation.addListener(listener);
- }
- return animation;
- }
-
- /**
- * Returns a re-themed context with controlled look and feel for views.
- */
- private static Context applyDefaultTheme(Context originalContext, boolean isLightTheme) {
- int themeId =
- isLightTheme ? R.style.Theme_DeviceDefault_Light : R.style.Theme_DeviceDefault;
- return new ContextThemeWrapper(originalContext, themeId);
- }
-
- private static void debugLog(String message) {
- if (Log.isLoggable(FloatingToolbar.FLOATING_TOOLBAR_TAG, Log.DEBUG)) {
- Log.v(TAG, message);
- }
- }
-
- void dump(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.print("toolbar token: "); pw.println(mSelectionToolbarToken);
- pw.print(prefix); pw.print("dismissed: "); pw.println(mDismissed);
- pw.print(prefix); pw.print("hidden: "); pw.println(mHidden);
- pw.print(prefix); pw.print("popup width: "); pw.println(mPopupWidth);
- pw.print(prefix); pw.print("popup height: "); pw.println(mPopupHeight);
- pw.print(prefix); pw.print("relative coords: "); pw.println(mRelativeCoordsForToolbar);
- pw.print(prefix); pw.print("main panel size: "); pw.println(mMainPanelSize);
- boolean hasOverflow = hasOverflow();
- pw.print(prefix); pw.print("has overflow: "); pw.println(hasOverflow);
- if (hasOverflow) {
- pw.print(prefix); pw.print("overflow open: "); pw.println(mIsOverflowOpen);
- pw.print(prefix); pw.print("overflow size: "); pw.println(mOverflowPanelSize);
- }
- if (mSurfaceControlViewHost != null) {
- FloatingToolbarRoot root = (FloatingToolbarRoot) mSurfaceControlViewHost.getView();
- root.dump(prefix, pw);
- }
- if (mMenuItems != null) {
- int menuItemSize = mMenuItems.size();
- pw.print(prefix); pw.print("number menu items: "); pw.println(menuItemSize);
- for (int i = 0; i < menuItemSize; i++) {
- pw.print(prefix); pw.print("#"); pw.println(i);
- pw.print(prefix + " "); pw.println(mMenuItems.get(i));
- }
- }
- }
-}
diff --git a/core/java/android/service/selectiontoolbar/SelectionToolbarRenderCallback.java b/core/java/android/service/selectiontoolbar/SelectionToolbarRenderCallback.java
deleted file mode 100644
index a10b6a8ac8cb..000000000000
--- a/core/java/android/service/selectiontoolbar/SelectionToolbarRenderCallback.java
+++ /dev/null
@@ -1,49 +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 android.service.selectiontoolbar;
-
-import android.view.selectiontoolbar.ToolbarMenuItem;
-import android.view.selectiontoolbar.WidgetInfo;
-
-/**
- * The callback that the render service uses to communicate with the host of the selection toolbar
- * container.
- *
- * @hide
- */
-public interface SelectionToolbarRenderCallback {
- /**
- * The selection toolbar is shown.
- */
- void onShown(WidgetInfo widgetInfo);
- /**
- * The selection toolbar has changed.
- */
- void onWidgetUpdated(WidgetInfo info);
- /**
- * The menu item on the selection toolbar has been clicked.
- */
- void onMenuItemClicked(ToolbarMenuItem item);
- /**
- * The toolbar doesn't be dismissed after showing on a given timeout.
- */
- void onToolbarShowTimeout();
- /**
- * The error occurred when operating on the selection toolbar.
- */
- void onError(int errorCode);
-}
diff --git a/core/java/android/service/selectiontoolbar/SelectionToolbarRenderService.java b/core/java/android/service/selectiontoolbar/SelectionToolbarRenderService.java
deleted file mode 100644
index f33feaec6dde..000000000000
--- a/core/java/android/service/selectiontoolbar/SelectionToolbarRenderService.java
+++ /dev/null
@@ -1,257 +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 android.service.selectiontoolbar;
-
-import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
-
-import android.annotation.CallSuper;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.Service;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.util.Log;
-import android.util.Pair;
-import android.util.SparseArray;
-import android.view.selectiontoolbar.ISelectionToolbarCallback;
-import android.view.selectiontoolbar.ShowInfo;
-import android.view.selectiontoolbar.ToolbarMenuItem;
-import android.view.selectiontoolbar.WidgetInfo;
-
-/**
- * Service for rendering selection toolbar.
- *
- * @hide
- */
-public abstract class SelectionToolbarRenderService extends Service {
-
- private static final String TAG = "SelectionToolbarRenderService";
-
- // TODO(b/215497659): read from DeviceConfig
- // The timeout to clean the cache if the client forgot to call dismiss()
- private static final int CACHE_CLEAN_AFTER_SHOW_TIMEOUT_IN_MS = 10 * 60 * 1000; // 10 minutes
-
- /**
- * The {@link Intent} that must be declared as handled by the service.
- *
- * <p>To be supported, the service must also require the
- * {@link android.Manifest.permission#BIND_SELECTION_TOOLBAR_RENDER_SERVICE} permission so
- * that other applications can not abuse it.
- */
- public static final String SERVICE_INTERFACE =
- "android.service.selectiontoolbar.SelectionToolbarRenderService";
-
- private Handler mHandler;
- private ISelectionToolbarRenderServiceCallback mServiceCallback;
-
- private final SparseArray<Pair<RemoteCallbackWrapper, CleanCacheRunnable>> mCache =
- new SparseArray<>();
-
- /**
- * Binder to receive calls from system server.
- */
- private final ISelectionToolbarRenderService mInterface =
- new ISelectionToolbarRenderService.Stub() {
-
- @Override
- public void onShow(int callingUid, ShowInfo showInfo, ISelectionToolbarCallback callback) {
- if (mCache.indexOfKey(callingUid) < 0) {
- mCache.put(callingUid, new Pair<>(new RemoteCallbackWrapper(callback),
- new CleanCacheRunnable(callingUid)));
- }
- Pair<RemoteCallbackWrapper, CleanCacheRunnable> toolbarPair = mCache.get(callingUid);
- CleanCacheRunnable cleanRunnable = toolbarPair.second;
- mHandler.removeCallbacks(cleanRunnable);
- mHandler.sendMessage(obtainMessage(SelectionToolbarRenderService::onShow,
- SelectionToolbarRenderService.this, callingUid, showInfo,
- toolbarPair.first));
- mHandler.postDelayed(cleanRunnable, CACHE_CLEAN_AFTER_SHOW_TIMEOUT_IN_MS);
- }
-
- @Override
- public void onHide(long widgetToken) {
- mHandler.sendMessage(obtainMessage(SelectionToolbarRenderService::onHide,
- SelectionToolbarRenderService.this, widgetToken));
- }
-
- @Override
- public void onDismiss(int callingUid, long widgetToken) {
- mHandler.sendMessage(obtainMessage(SelectionToolbarRenderService::onDismiss,
- SelectionToolbarRenderService.this, widgetToken));
- Pair<RemoteCallbackWrapper, CleanCacheRunnable> toolbarPair = mCache.get(callingUid);
- if (toolbarPair != null) {
- mHandler.removeCallbacks(toolbarPair.second);
- mCache.remove(callingUid);
- }
- }
-
- @Override
- public void onConnected(IBinder callback) {
- mHandler.sendMessage(obtainMessage(SelectionToolbarRenderService::handleOnConnected,
- SelectionToolbarRenderService.this, callback));
- }
- };
-
- @CallSuper
- @Override
- public void onCreate() {
- super.onCreate();
- mHandler = new Handler(Looper.getMainLooper(), null, true);
- }
-
- @Override
- @Nullable
- public final IBinder onBind(@NonNull Intent intent) {
- if (SERVICE_INTERFACE.equals(intent.getAction())) {
- return mInterface.asBinder();
- }
- Log.w(TAG, "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + ": " + intent);
- return null;
- }
-
- private void handleOnConnected(@NonNull IBinder callback) {
- mServiceCallback = ISelectionToolbarRenderServiceCallback.Stub.asInterface(callback);
- }
-
- protected void transferTouch(@NonNull IBinder source, @NonNull IBinder target) {
- final ISelectionToolbarRenderServiceCallback callback = mServiceCallback;
- if (callback == null) {
- Log.e(TAG, "transferTouch(): no server callback");
- return;
- }
- try {
- callback.transferTouch(source, target);
- } catch (RemoteException e) {
- // no-op
- }
- }
-
- /**
- * Called when showing the selection toolbar.
- */
- public abstract void onShow(int callingUid, ShowInfo showInfo,
- RemoteCallbackWrapper callbackWrapper);
-
- /**
- * Called when hiding the selection toolbar.
- */
- public abstract void onHide(long widgetToken);
-
-
- /**
- * Called when dismissing the selection toolbar.
- */
- public abstract void onDismiss(long widgetToken);
-
- /**
- * Called when showing the selection toolbar for a specific timeout. This avoids the client
- * forgot to call dismiss to clean the state.
- */
- public void onToolbarShowTimeout(int callingUid) {
- // no-op
- }
-
- /**
- * Callback to notify the client toolbar events.
- */
- public static final class RemoteCallbackWrapper implements SelectionToolbarRenderCallback {
-
- private final ISelectionToolbarCallback mRemoteCallback;
-
- RemoteCallbackWrapper(ISelectionToolbarCallback remoteCallback) {
- // TODO(b/215497659): handle if the binder dies.
- mRemoteCallback = remoteCallback;
- }
-
- @Override
- public void onShown(WidgetInfo widgetInfo) {
- try {
- mRemoteCallback.onShown(widgetInfo);
- } catch (RemoteException e) {
- // no-op
- }
- }
-
- @Override
- public void onToolbarShowTimeout() {
- try {
- mRemoteCallback.onToolbarShowTimeout();
- } catch (RemoteException e) {
- // no-op
- }
- }
-
- @Override
- public void onWidgetUpdated(WidgetInfo widgetInfo) {
- try {
- mRemoteCallback.onWidgetUpdated(widgetInfo);
- } catch (RemoteException e) {
- // no-op
- }
- }
-
- @Override
- public void onMenuItemClicked(ToolbarMenuItem item) {
- try {
- mRemoteCallback.onMenuItemClicked(item);
- } catch (RemoteException e) {
- // no-op
- }
- }
-
- @Override
- public void onError(int errorCode) {
- try {
- mRemoteCallback.onError(errorCode);
- } catch (RemoteException e) {
- // no-op
- }
- }
- }
-
- private class CleanCacheRunnable implements Runnable {
-
- int mCleanUid;
-
- CleanCacheRunnable(int cleanUid) {
- mCleanUid = cleanUid;
- }
-
- @Override
- public void run() {
- Pair<RemoteCallbackWrapper, CleanCacheRunnable> toolbarPair = mCache.get(mCleanUid);
- if (toolbarPair != null) {
- Log.w(TAG, "CleanCacheRunnable: remove " + mCleanUid + " from cache.");
- mCache.remove(mCleanUid);
- onToolbarShowTimeout(mCleanUid);
- }
- }
- }
-
- /**
- * A listener to notify the service to the transfer touch focus.
- */
- public interface TransferTouchListener {
- /**
- * Notify the service to transfer the touch focus.
- */
- void onTransferTouch(IBinder source, IBinder target);
- }
-}
diff --git a/core/java/android/util/apk/TEST_MAPPING b/core/java/android/util/apk/TEST_MAPPING
index a3a86fdb4b82..7668eec474ab 100644
--- a/core/java/android/util/apk/TEST_MAPPING
+++ b/core/java/android/util/apk/TEST_MAPPING
@@ -7,7 +7,9 @@
"include-filter": "android.util.apk.SourceStampVerifierTest"
}
]
- },
+ }
+ ],
+ "presubmit-large": [
{
"name": "CtsPackageManagerTestCases",
"options": [
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 4b96d74b5687..0b2b6ce33666 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -375,6 +375,14 @@ public final class Display {
public static final int FLAG_REAR = 1 << 13;
/**
+ * Display flag: Indicates that the orientation of this display is not fixed and is coupled to
+ * the orientation of its content.
+ *
+ * @hide
+ */
+ public static final int FLAG_ROTATES_WITH_CONTENT = 1 << 14;
+
+ /**
* Display flag: Indicates that the contents of the display should not be scaled
* to fit the physical screen dimensions. Used for development only to emulate
* devices with smaller physicals screens while preserving density.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 21ee0e783fbc..3aa610af60b0 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1810,6 +1810,9 @@ public final class ViewRootImpl implements ViewParent,
// Request to update light center.
mAttachInfo.mNeedsUpdateLightCenter = true;
}
+ if ((changes & WindowManager.LayoutParams.COLOR_MODE_CHANGED) != 0) {
+ invalidate();
+ }
if (mWindowAttributes.packageName == null) {
mWindowAttributes.packageName = mBasePackageName;
}
@@ -3792,6 +3795,11 @@ public final class ViewRootImpl implements ViewParent,
boolean cancelDueToPreDrawListener = mAttachInfo.mTreeObserver.dispatchOnPreDraw();
boolean cancelAndRedraw = cancelDueToPreDrawListener
|| (cancelDraw && mDrewOnceForSync);
+ if (cancelAndRedraw) {
+ Log.d(mTag, "Cancelling draw."
+ + " cancelDueToPreDrawListener=" + cancelDueToPreDrawListener
+ + " cancelDueToSync=" + (cancelDraw && mDrewOnceForSync));
+ }
if (!cancelAndRedraw) {
// A sync was already requested before the WMS requested sync. This means we need to
// sync the buffer, regardless if WMS wants to sync the buffer.
@@ -5561,6 +5569,7 @@ public final class ViewRootImpl implements ViewParent,
if (desiredRatio != mDesiredHdrSdrRatio) {
mDesiredHdrSdrRatio = desiredRatio;
updateRenderHdrSdrRatio();
+ invalidate();
if (mDesiredHdrSdrRatio < 1.01f) {
mDisplay.unregisterHdrSdrRatioChangedListener(mHdrSdrRatioChangedListener);
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 7f8f61109287..9687a5395afd 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1516,7 +1516,7 @@ public final class InputMethodManager {
* @see #startStylusHandwriting(View)
*/
public boolean isStylusHandwritingAvailable() {
- return isStylusHandwritingAvailableAsUser(UserHandle.myUserId());
+ return isStylusHandwritingAvailableAsUser(UserHandle.of(UserHandle.myUserId()));
}
/**
@@ -1527,14 +1527,17 @@ public final class InputMethodManager {
* called and Stylus touch should continue as normal touch input.</p>
*
* <p>{@link Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required when and only when
- * {@code userId} is different from the user id of the current process.</p>
+ * {@code user} is different from the user of the current process.</p>
*
* @see #startStylusHandwriting(View)
- * @param userId user ID to query.
+ * @param user UserHandle to query.
* @hide
*/
+ @NonNull
@RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
- public boolean isStylusHandwritingAvailableAsUser(@UserIdInt int userId) {
+ @TestApi
+ @SuppressLint("UserHandle")
+ public boolean isStylusHandwritingAvailableAsUser(@NonNull UserHandle user) {
final Context fallbackContext = ActivityThread.currentApplication();
if (fallbackContext == null) {
return false;
@@ -1551,7 +1554,7 @@ public final class InputMethodManager {
}
};
}
- isAvailable = mStylusHandwritingAvailableCache.query(userId);
+ isAvailable = mStylusHandwritingAvailableCache.query(user.getIdentifier());
}
return isAvailable;
}
@@ -1643,16 +1646,19 @@ public final class InputMethodManager {
* Returns the list of enabled input methods for the specified user.
*
* <p>{@link Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required when and only when
- * {@code userId} is different from the user id of the current process.</p>
+ * {@code user} is different from the user of the current process.</p>
*
- * @param userId user ID to query
+ * @param user UserHandle to query
* @return {@link List} of {@link InputMethodInfo}.
- * @see #getEnabledInputMethodSubtypeListAsUser(String, boolean, int)
+ * @see #getEnabledInputMethodSubtypeListAsUser(String, boolean, UserHandle)
* @hide
*/
+ @NonNull
@RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
- public List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
- return IInputMethodManagerGlobalInvoker.getEnabledInputMethodList(userId);
+ @TestApi
+ @SuppressLint("UserHandle")
+ public List<InputMethodInfo> getEnabledInputMethodListAsUser(@NonNull UserHandle user) {
+ return IInputMethodManagerGlobalInvoker.getEnabledInputMethodList(user.getIdentifier());
}
/**
@@ -1681,7 +1687,7 @@ public final class InputMethodManager {
*
* @param imeId IME ID to be queried about.
* @param allowsImplicitlyEnabledSubtypes {@code true} to include implicitly enabled subtypes.
- * @param userId user ID to be queried about.
+ * @param user UserHandle to be queried about.
* {@link Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required if this is
* different from the calling process user ID.
* @return {@link List} of {@link InputMethodSubtype}.
@@ -1690,10 +1696,14 @@ public final class InputMethodManager {
*/
@NonNull
@RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
+ @TestApi
+ @SuppressLint("UserHandle")
public List<InputMethodSubtype> getEnabledInputMethodSubtypeListAsUser(
- @NonNull String imeId, boolean allowsImplicitlyEnabledSubtypes, @UserIdInt int userId) {
+ @NonNull String imeId, boolean allowsImplicitlyEnabledSubtypes,
+ @NonNull UserHandle user) {
return IInputMethodManagerGlobalInvoker.getEnabledInputMethodSubtypeList(
- Objects.requireNonNull(imeId), allowsImplicitlyEnabledSubtypes, userId);
+ Objects.requireNonNull(imeId), allowsImplicitlyEnabledSubtypes,
+ user.getIdentifier());
}
/**
diff --git a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
index 987ac2e90240..d588c487844b 100644
--- a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
+++ b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
@@ -809,11 +809,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub {
return; // cancelled
}
InputConnection ic = getInputConnection();
- // Note we do NOT check isActive() here, because this is safe
- // for an IME to call at any time, and we need to allow it
- // through to clean up our state after the IME has switched to
- // another client.
- if (ic == null) {
+ if (ic == null || !isActive()) {
Log.w(TAG, "finishComposingTextFromImm on inactive InputConnection");
return;
}
@@ -837,11 +833,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub {
return; // cancelled
}
InputConnection ic = getInputConnection();
- // Note we do NOT check isActive() here, because this is safe
- // for an IME to call at any time, and we need to allow it
- // through to clean up our state after the IME has switched to
- // another client.
- if (ic == null) {
+ if (ic == null && !isActive()) {
Log.w(TAG, "finishComposingText on inactive InputConnection");
return;
}
diff --git a/core/java/android/view/selectiontoolbar/ISelectionToolbarCallback.aidl b/core/java/android/view/selectiontoolbar/ISelectionToolbarCallback.aidl
deleted file mode 100644
index aaeb12012f68..000000000000
--- a/core/java/android/view/selectiontoolbar/ISelectionToolbarCallback.aidl
+++ /dev/null
@@ -1,32 +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 android.view.selectiontoolbar;
-
-import android.view.selectiontoolbar.ToolbarMenuItem;
-import android.view.selectiontoolbar.WidgetInfo;
-
-/**
- * Binder interface to notify the selection toolbar events from one process to the other.
- * @hide
- */
-oneway interface ISelectionToolbarCallback {
- void onShown(in WidgetInfo info);
- void onWidgetUpdated(in WidgetInfo info);
- void onToolbarShowTimeout();
- void onMenuItemClicked(in ToolbarMenuItem item);
- void onError(int errorCode);
-}
diff --git a/core/java/android/view/selectiontoolbar/ISelectionToolbarManager.aidl b/core/java/android/view/selectiontoolbar/ISelectionToolbarManager.aidl
deleted file mode 100644
index 4a647ada1d6c..000000000000
--- a/core/java/android/view/selectiontoolbar/ISelectionToolbarManager.aidl
+++ /dev/null
@@ -1,31 +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 android.view.selectiontoolbar;
-
-import android.view.selectiontoolbar.ISelectionToolbarCallback;
-import android.view.selectiontoolbar.ShowInfo;
-
-/**
- * Mediator between apps and selection toolbar service implementation.
- *
- * @hide
- */
-oneway interface ISelectionToolbarManager {
- void showToolbar(in ShowInfo showInfo, in ISelectionToolbarCallback callback, int userId);
- void hideToolbar(long widgetToken, int userId);
- void dismissToolbar(long widgetToken, int userId);
-} \ No newline at end of file
diff --git a/core/java/android/view/selectiontoolbar/OWNERS b/core/java/android/view/selectiontoolbar/OWNERS
deleted file mode 100644
index 5500b92868dd..000000000000
--- a/core/java/android/view/selectiontoolbar/OWNERS
+++ /dev/null
@@ -1,10 +0,0 @@
-# Bug component: 709498
-
-augale@google.com
-joannechung@google.com
-licha@google.com
-lpeter@google.com
-svetoslavganov@google.com
-toki@google.com
-tonymak@google.com
-tymtsai@google.com \ No newline at end of file
diff --git a/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java b/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java
deleted file mode 100644
index 6de031628768..000000000000
--- a/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java
+++ /dev/null
@@ -1,122 +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 android.view.selectiontoolbar;
-
-import android.annotation.NonNull;
-import android.annotation.SystemService;
-import android.content.Context;
-import android.os.RemoteException;
-import android.provider.DeviceConfig;
-
-import java.util.Objects;
-
-/**
- * The {@link SelectionToolbarManager} class provides ways for apps to control the
- * selection toolbar.
- *
- * @hide
- */
-@SystemService(Context.SELECTION_TOOLBAR_SERVICE)
-public final class SelectionToolbarManager {
-
- private static final String TAG = "SelectionToolbar";
-
- /**
- * The tag which uses for enabling debug log dump. To enable it, we can use command "adb shell
- * setprop log.tag.UiTranslation DEBUG".
- */
- public static final String LOG_TAG = "SelectionToolbar";
-
- /**
- * Whether system selection toolbar is enabled.
- */
- private static final String REMOTE_SELECTION_TOOLBAR_ENABLED =
- "remote_selection_toolbar_enabled";
-
- /**
- * Used to mark a toolbar that has no toolbar token id.
- */
- public static final long NO_TOOLBAR_ID = 0;
-
- /**
- * The error code that do not allow to create multiple toolbar.
- */
- public static final int ERROR_DO_NOT_ALLOW_MULTIPLE_TOOL_BAR = 1;
-
- @NonNull
- private final Context mContext;
- private final ISelectionToolbarManager mService;
-
- public SelectionToolbarManager(@NonNull Context context,
- @NonNull ISelectionToolbarManager service) {
- mContext = Objects.requireNonNull(context);
- mService = service;
- }
-
- /**
- * Request to show selection toolbar for a given View.
- */
- public void showToolbar(@NonNull ShowInfo showInfo,
- @NonNull ISelectionToolbarCallback callback) {
- try {
- Objects.requireNonNull(showInfo);
- Objects.requireNonNull(callback);
- mService.showToolbar(showInfo, callback, mContext.getUserId());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Request to hide selection toolbar.
- */
- public void hideToolbar(long widgetToken) {
- try {
- mService.hideToolbar(widgetToken, mContext.getUserId());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Dismiss to dismiss selection toolbar.
- */
- public void dismissToolbar(long widgetToken) {
- try {
- mService.dismissToolbar(widgetToken, mContext.getUserId());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- private boolean isRemoteSelectionToolbarEnabled() {
- return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SELECTION_TOOLBAR,
- REMOTE_SELECTION_TOOLBAR_ENABLED, false);
- }
-
- /**
- * Returns {@code true} if remote render selection toolbar enabled, otherwise
- * returns {@code false}.
- */
- public static boolean isRemoteSelectionToolbarEnabled(Context context) {
- SelectionToolbarManager manager = context.getSystemService(SelectionToolbarManager.class);
- if (manager != null) {
- return manager.isRemoteSelectionToolbarEnabled();
- }
- return false;
- }
-}
diff --git a/core/java/android/view/selectiontoolbar/ShowInfo.java b/core/java/android/view/selectiontoolbar/ShowInfo.java
deleted file mode 100644
index 28b4480d4967..000000000000
--- a/core/java/android/view/selectiontoolbar/ShowInfo.java
+++ /dev/null
@@ -1,361 +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 android.view.selectiontoolbar;
-
-import android.annotation.NonNull;
-import android.graphics.Rect;
-import android.os.IBinder;
-import android.os.Parcelable;
-
-import com.android.internal.util.DataClass;
-
-import java.util.List;
-
-
-/**
- * The class holds menu information for render service to render the selection toolbar.
- *
- * @hide
- */
-@DataClass(genToString = true, genEqualsHashCode = true)
-public final class ShowInfo implements Parcelable {
-
- /**
- * The token that is used to identify the selection toolbar. This is initially set to 0
- * until a selection toolbar has been created for the showToolbar request.
- */
- private final long mWidgetToken;
-
- /**
- * If the toolbar menu items need to be re-layout.
- */
- private final boolean mLayoutRequired;
-
- /**
- * The menu items to be rendered in the selection toolbar.
- */
- @NonNull
- private final List<ToolbarMenuItem> mMenuItems;
-
- /**
- * A rect specifying where the selection toolbar on the screen.
- */
- @NonNull
- private final Rect mContentRect;
-
- /**
- * A recommended maximum suggested width of the selection toolbar.
- */
- private final int mSuggestedWidth;
-
- /**
- * The portion of the screen that is available to the selection toolbar.
- */
- @NonNull
- private final Rect mViewPortOnScreen;
-
- /**
- * The host application's input token, this allows the remote render service to transfer
- * the touch focus to the host application.
- */
- @NonNull
- private final IBinder mHostInputToken;
-
- /**
- * If the host application uses light theme.
- */
- private final boolean mIsLightTheme;
-
-
-
- // Code below generated by codegen v1.0.23.
- //
- // DO NOT MODIFY!
- // CHECKSTYLE:OFF Generated code
- //
- // To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/selectiontoolbar/ShowInfo.java
- //
- // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
- // Settings > Editor > Code Style > Formatter Control
- //@formatter:off
-
-
- /**
- * Creates a new ShowInfo.
- *
- * @param widgetToken
- * The token that is used to identify the selection toolbar. This is initially set to 0
- * until a selection toolbar has been created for the showToolbar request.
- * @param layoutRequired
- * If the toolbar menu items need to be re-layout.
- * @param menuItems
- * The menu items to be rendered in the selection toolbar.
- * @param contentRect
- * A rect specifying where the selection toolbar on the screen.
- * @param suggestedWidth
- * A recommended maximum suggested width of the selection toolbar.
- * @param viewPortOnScreen
- * The portion of the screen that is available to the selection toolbar.
- * @param hostInputToken
- * The host application's input token, this allows the remote render service to transfer
- * the touch focus to the host application.
- * @param isLightTheme
- * If the host application uses light theme.
- */
- @DataClass.Generated.Member
- public ShowInfo(
- long widgetToken,
- boolean layoutRequired,
- @NonNull List<ToolbarMenuItem> menuItems,
- @NonNull Rect contentRect,
- int suggestedWidth,
- @NonNull Rect viewPortOnScreen,
- @NonNull IBinder hostInputToken,
- boolean isLightTheme) {
- this.mWidgetToken = widgetToken;
- this.mLayoutRequired = layoutRequired;
- this.mMenuItems = menuItems;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mMenuItems);
- this.mContentRect = contentRect;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mContentRect);
- this.mSuggestedWidth = suggestedWidth;
- this.mViewPortOnScreen = viewPortOnScreen;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mViewPortOnScreen);
- this.mHostInputToken = hostInputToken;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mHostInputToken);
- this.mIsLightTheme = isLightTheme;
-
- // onConstructed(); // You can define this method to get a callback
- }
-
- /**
- * The token that is used to identify the selection toolbar. This is initially set to 0
- * until a selection toolbar has been created for the showToolbar request.
- */
- @DataClass.Generated.Member
- public long getWidgetToken() {
- return mWidgetToken;
- }
-
- /**
- * If the toolbar menu items need to be re-layout.
- */
- @DataClass.Generated.Member
- public boolean isLayoutRequired() {
- return mLayoutRequired;
- }
-
- /**
- * The menu items to be rendered in the selection toolbar.
- */
- @DataClass.Generated.Member
- public @NonNull List<ToolbarMenuItem> getMenuItems() {
- return mMenuItems;
- }
-
- /**
- * A rect specifying where the selection toolbar on the screen.
- */
- @DataClass.Generated.Member
- public @NonNull Rect getContentRect() {
- return mContentRect;
- }
-
- /**
- * A recommended maximum suggested width of the selection toolbar.
- */
- @DataClass.Generated.Member
- public int getSuggestedWidth() {
- return mSuggestedWidth;
- }
-
- /**
- * The portion of the screen that is available to the selection toolbar.
- */
- @DataClass.Generated.Member
- public @NonNull Rect getViewPortOnScreen() {
- return mViewPortOnScreen;
- }
-
- /**
- * The host application's input token, this allows the remote render service to transfer
- * the touch focus to the host application.
- */
- @DataClass.Generated.Member
- public @NonNull IBinder getHostInputToken() {
- return mHostInputToken;
- }
-
- /**
- * If the host application uses light theme.
- */
- @DataClass.Generated.Member
- public boolean isIsLightTheme() {
- return mIsLightTheme;
- }
-
- @Override
- @DataClass.Generated.Member
- public String toString() {
- // You can override field toString logic by defining methods like:
- // String fieldNameToString() { ... }
-
- return "ShowInfo { " +
- "widgetToken = " + mWidgetToken + ", " +
- "layoutRequired = " + mLayoutRequired + ", " +
- "menuItems = " + mMenuItems + ", " +
- "contentRect = " + mContentRect + ", " +
- "suggestedWidth = " + mSuggestedWidth + ", " +
- "viewPortOnScreen = " + mViewPortOnScreen + ", " +
- "hostInputToken = " + mHostInputToken + ", " +
- "isLightTheme = " + mIsLightTheme +
- " }";
- }
-
- @Override
- @DataClass.Generated.Member
- public boolean equals(@android.annotation.Nullable Object o) {
- // You can override field equality logic by defining either of the methods like:
- // boolean fieldNameEquals(ShowInfo other) { ... }
- // boolean fieldNameEquals(FieldType otherValue) { ... }
-
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- @SuppressWarnings("unchecked")
- ShowInfo that = (ShowInfo) o;
- //noinspection PointlessBooleanExpression
- return true
- && mWidgetToken == that.mWidgetToken
- && mLayoutRequired == that.mLayoutRequired
- && java.util.Objects.equals(mMenuItems, that.mMenuItems)
- && java.util.Objects.equals(mContentRect, that.mContentRect)
- && mSuggestedWidth == that.mSuggestedWidth
- && java.util.Objects.equals(mViewPortOnScreen, that.mViewPortOnScreen)
- && java.util.Objects.equals(mHostInputToken, that.mHostInputToken)
- && mIsLightTheme == that.mIsLightTheme;
- }
-
- @Override
- @DataClass.Generated.Member
- public int hashCode() {
- // You can override field hashCode logic by defining methods like:
- // int fieldNameHashCode() { ... }
-
- int _hash = 1;
- _hash = 31 * _hash + Long.hashCode(mWidgetToken);
- _hash = 31 * _hash + Boolean.hashCode(mLayoutRequired);
- _hash = 31 * _hash + java.util.Objects.hashCode(mMenuItems);
- _hash = 31 * _hash + java.util.Objects.hashCode(mContentRect);
- _hash = 31 * _hash + mSuggestedWidth;
- _hash = 31 * _hash + java.util.Objects.hashCode(mViewPortOnScreen);
- _hash = 31 * _hash + java.util.Objects.hashCode(mHostInputToken);
- _hash = 31 * _hash + Boolean.hashCode(mIsLightTheme);
- return _hash;
- }
-
- @Override
- @DataClass.Generated.Member
- public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
- // You can override field parcelling by defining methods like:
- // void parcelFieldName(Parcel dest, int flags) { ... }
-
- int flg = 0;
- if (mLayoutRequired) flg |= 0x2;
- if (mIsLightTheme) flg |= 0x80;
- dest.writeInt(flg);
- dest.writeLong(mWidgetToken);
- dest.writeParcelableList(mMenuItems, flags);
- dest.writeTypedObject(mContentRect, flags);
- dest.writeInt(mSuggestedWidth);
- dest.writeTypedObject(mViewPortOnScreen, flags);
- dest.writeStrongBinder(mHostInputToken);
- }
-
- @Override
- @DataClass.Generated.Member
- public int describeContents() { return 0; }
-
- /** @hide */
- @SuppressWarnings({"unchecked", "RedundantCast"})
- @DataClass.Generated.Member
- /* package-private */ ShowInfo(@NonNull android.os.Parcel in) {
- // You can override field unparcelling by defining methods like:
- // static FieldType unparcelFieldName(Parcel in) { ... }
-
- int flg = in.readInt();
- boolean layoutRequired = (flg & 0x2) != 0;
- boolean isLightTheme = (flg & 0x80) != 0;
- long widgetToken = in.readLong();
- List<ToolbarMenuItem> menuItems = new java.util.ArrayList<>();
- in.readParcelableList(menuItems, ToolbarMenuItem.class.getClassLoader(), android.view.selectiontoolbar.ToolbarMenuItem.class);
- Rect contentRect = (Rect) in.readTypedObject(Rect.CREATOR);
- int suggestedWidth = in.readInt();
- Rect viewPortOnScreen = (Rect) in.readTypedObject(Rect.CREATOR);
- IBinder hostInputToken = (IBinder) in.readStrongBinder();
-
- this.mWidgetToken = widgetToken;
- this.mLayoutRequired = layoutRequired;
- this.mMenuItems = menuItems;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mMenuItems);
- this.mContentRect = contentRect;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mContentRect);
- this.mSuggestedWidth = suggestedWidth;
- this.mViewPortOnScreen = viewPortOnScreen;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mViewPortOnScreen);
- this.mHostInputToken = hostInputToken;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mHostInputToken);
- this.mIsLightTheme = isLightTheme;
-
- // onConstructed(); // You can define this method to get a callback
- }
-
- @DataClass.Generated.Member
- public static final @NonNull Parcelable.Creator<ShowInfo> CREATOR
- = new Parcelable.Creator<ShowInfo>() {
- @Override
- public ShowInfo[] newArray(int size) {
- return new ShowInfo[size];
- }
-
- @Override
- public ShowInfo createFromParcel(@NonNull android.os.Parcel in) {
- return new ShowInfo(in);
- }
- };
-
- @DataClass.Generated(
- time = 1645108384245L,
- codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/view/selectiontoolbar/ShowInfo.java",
- inputSignatures = "private final long mWidgetToken\nprivate final boolean mLayoutRequired\nprivate final @android.annotation.NonNull java.util.List<android.view.selectiontoolbar.ToolbarMenuItem> mMenuItems\nprivate final @android.annotation.NonNull android.graphics.Rect mContentRect\nprivate final int mSuggestedWidth\nprivate final @android.annotation.NonNull android.graphics.Rect mViewPortOnScreen\nprivate final @android.annotation.NonNull android.os.IBinder mHostInputToken\nprivate final boolean mIsLightTheme\nclass ShowInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true)")
- @Deprecated
- private void __metadata() {}
-
-
- //@formatter:on
- // End of generated code
-
-}
diff --git a/core/java/android/view/selectiontoolbar/ToolbarMenuItem.java b/core/java/android/view/selectiontoolbar/ToolbarMenuItem.java
deleted file mode 100644
index 89347c613310..000000000000
--- a/core/java/android/view/selectiontoolbar/ToolbarMenuItem.java
+++ /dev/null
@@ -1,543 +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 android.view.selectiontoolbar;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.graphics.drawable.Icon;
-import android.os.Parcelable;
-import android.view.MenuItem;
-
-import com.android.internal.util.DataClass;
-
-/**
- * The menu item that is used to show the selection toolbar.
- *
- * @hide
- */
-@DataClass(genBuilder = true, genToString = true, genEqualsHashCode = true)
-public final class ToolbarMenuItem implements Parcelable {
-
- /**
- * The priority of menu item is unknown.
- */
- public static final int PRIORITY_UNKNOWN = 0;
-
- /**
- * The priority of menu item is shown in primary selection toolbar.
- */
- public static final int PRIORITY_PRIMARY = 1;
-
- /**
- * The priority of menu item is shown in overflow selection toolbar.
- */
- public static final int PRIORITY_OVERFLOW = 2;
-
- /**
- * The id of the menu item.
- *
- * @see MenuItem#getItemId()
- */
- private final int mItemId;
-
- /**
- * The title of the menu item.
- *
- * @see MenuItem#getTitle()
- */
- @NonNull
- private final CharSequence mTitle;
-
- /**
- * The content description of the menu item.
- *
- * @see MenuItem#getContentDescription()
- */
- @Nullable
- private final CharSequence mContentDescription;
-
- /**
- * The group id of the menu item.
- *
- * @see MenuItem#getGroupId()
- */
- private final int mGroupId;
-
- /**
- * The icon id of the menu item.
- *
- * @see MenuItem#getIcon()
- */
- @Nullable
- private final Icon mIcon;
-
- /**
- * The tooltip text of the menu item.
- *
- * @see MenuItem#getTooltipText()
- */
- @Nullable
- private final CharSequence mTooltipText;
-
- /**
- * The priority of the menu item used to display the order of the menu item.
- */
- private final int mPriority;
-
- /**
- * Returns the priority from a given {@link MenuItem}.
- */
- public static int getPriorityFromMenuItem(MenuItem menuItem) {
- if (menuItem.requiresActionButton()) {
- return PRIORITY_PRIMARY;
- } else if (menuItem.requiresOverflow()) {
- return PRIORITY_OVERFLOW;
- }
- return PRIORITY_UNKNOWN;
- }
-
-
-
-
- // Code below generated by codegen v1.0.23.
- //
- // DO NOT MODIFY!
- // CHECKSTYLE:OFF Generated code
- //
- // To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/selectiontoolbar/ToolbarMenuItem.java
- //
- // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
- // Settings > Editor > Code Style > Formatter Control
- //@formatter:off
-
-
- @android.annotation.IntDef(prefix = "PRIORITY_", value = {
- PRIORITY_UNKNOWN,
- PRIORITY_PRIMARY,
- PRIORITY_OVERFLOW
- })
- @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
- @DataClass.Generated.Member
- public @interface Priority {}
-
- @DataClass.Generated.Member
- public static String priorityToString(@Priority int value) {
- switch (value) {
- case PRIORITY_UNKNOWN:
- return "PRIORITY_UNKNOWN";
- case PRIORITY_PRIMARY:
- return "PRIORITY_PRIMARY";
- case PRIORITY_OVERFLOW:
- return "PRIORITY_OVERFLOW";
- default: return Integer.toHexString(value);
- }
- }
-
- @DataClass.Generated.Member
- /* package-private */ ToolbarMenuItem(
- int itemId,
- @NonNull CharSequence title,
- @Nullable CharSequence contentDescription,
- int groupId,
- @Nullable Icon icon,
- @Nullable CharSequence tooltipText,
- int priority) {
- this.mItemId = itemId;
- this.mTitle = title;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mTitle);
- this.mContentDescription = contentDescription;
- this.mGroupId = groupId;
- this.mIcon = icon;
- this.mTooltipText = tooltipText;
- this.mPriority = priority;
-
- // onConstructed(); // You can define this method to get a callback
- }
-
- /**
- * The id of the menu item.
- *
- * @see MenuItem#getItemId()
- */
- @DataClass.Generated.Member
- public int getItemId() {
- return mItemId;
- }
-
- /**
- * The title of the menu item.
- *
- * @see MenuItem#getTitle()
- */
- @DataClass.Generated.Member
- public @NonNull CharSequence getTitle() {
- return mTitle;
- }
-
- /**
- * The content description of the menu item.
- *
- * @see MenuItem#getContentDescription()
- */
- @DataClass.Generated.Member
- public @Nullable CharSequence getContentDescription() {
- return mContentDescription;
- }
-
- /**
- * The group id of the menu item.
- *
- * @see MenuItem#getGroupId()
- */
- @DataClass.Generated.Member
- public int getGroupId() {
- return mGroupId;
- }
-
- /**
- * The icon id of the menu item.
- *
- * @see MenuItem#getIcon()
- */
- @DataClass.Generated.Member
- public @Nullable Icon getIcon() {
- return mIcon;
- }
-
- /**
- * The tooltip text of the menu item.
- *
- * @see MenuItem#getTooltipText()
- */
- @DataClass.Generated.Member
- public @Nullable CharSequence getTooltipText() {
- return mTooltipText;
- }
-
- /**
- * The priority of the menu item used to display the order of the menu item.
- */
- @DataClass.Generated.Member
- public int getPriority() {
- return mPriority;
- }
-
- @Override
- @DataClass.Generated.Member
- public String toString() {
- // You can override field toString logic by defining methods like:
- // String fieldNameToString() { ... }
-
- return "ToolbarMenuItem { " +
- "itemId = " + mItemId + ", " +
- "title = " + mTitle + ", " +
- "contentDescription = " + mContentDescription + ", " +
- "groupId = " + mGroupId + ", " +
- "icon = " + mIcon + ", " +
- "tooltipText = " + mTooltipText + ", " +
- "priority = " + mPriority +
- " }";
- }
-
- @Override
- @DataClass.Generated.Member
- public boolean equals(@Nullable Object o) {
- // You can override field equality logic by defining either of the methods like:
- // boolean fieldNameEquals(ToolbarMenuItem other) { ... }
- // boolean fieldNameEquals(FieldType otherValue) { ... }
-
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- @SuppressWarnings("unchecked")
- ToolbarMenuItem that = (ToolbarMenuItem) o;
- //noinspection PointlessBooleanExpression
- return true
- && mItemId == that.mItemId
- && java.util.Objects.equals(mTitle, that.mTitle)
- && java.util.Objects.equals(mContentDescription, that.mContentDescription)
- && mGroupId == that.mGroupId
- && java.util.Objects.equals(mIcon, that.mIcon)
- && java.util.Objects.equals(mTooltipText, that.mTooltipText)
- && mPriority == that.mPriority;
- }
-
- @Override
- @DataClass.Generated.Member
- public int hashCode() {
- // You can override field hashCode logic by defining methods like:
- // int fieldNameHashCode() { ... }
-
- int _hash = 1;
- _hash = 31 * _hash + mItemId;
- _hash = 31 * _hash + java.util.Objects.hashCode(mTitle);
- _hash = 31 * _hash + java.util.Objects.hashCode(mContentDescription);
- _hash = 31 * _hash + mGroupId;
- _hash = 31 * _hash + java.util.Objects.hashCode(mIcon);
- _hash = 31 * _hash + java.util.Objects.hashCode(mTooltipText);
- _hash = 31 * _hash + mPriority;
- return _hash;
- }
-
- @Override
- @DataClass.Generated.Member
- public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
- // You can override field parcelling by defining methods like:
- // void parcelFieldName(Parcel dest, int flags) { ... }
-
- byte flg = 0;
- if (mContentDescription != null) flg |= 0x4;
- if (mIcon != null) flg |= 0x10;
- if (mTooltipText != null) flg |= 0x20;
- dest.writeByte(flg);
- dest.writeInt(mItemId);
- dest.writeCharSequence(mTitle);
- if (mContentDescription != null) dest.writeCharSequence(mContentDescription);
- dest.writeInt(mGroupId);
- if (mIcon != null) dest.writeTypedObject(mIcon, flags);
- if (mTooltipText != null) dest.writeCharSequence(mTooltipText);
- dest.writeInt(mPriority);
- }
-
- @Override
- @DataClass.Generated.Member
- public int describeContents() { return 0; }
-
- /** @hide */
- @SuppressWarnings({"unchecked", "RedundantCast"})
- @DataClass.Generated.Member
- /* package-private */ ToolbarMenuItem(@NonNull android.os.Parcel in) {
- // You can override field unparcelling by defining methods like:
- // static FieldType unparcelFieldName(Parcel in) { ... }
-
- byte flg = in.readByte();
- int itemId = in.readInt();
- CharSequence title = (CharSequence) in.readCharSequence();
- CharSequence contentDescription = (flg & 0x4) == 0 ? null : (CharSequence) in.readCharSequence();
- int groupId = in.readInt();
- Icon icon = (flg & 0x10) == 0 ? null : (Icon) in.readTypedObject(Icon.CREATOR);
- CharSequence tooltipText = (flg & 0x20) == 0 ? null : (CharSequence) in.readCharSequence();
- int priority = in.readInt();
-
- this.mItemId = itemId;
- this.mTitle = title;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mTitle);
- this.mContentDescription = contentDescription;
- this.mGroupId = groupId;
- this.mIcon = icon;
- this.mTooltipText = tooltipText;
- this.mPriority = priority;
-
- // onConstructed(); // You can define this method to get a callback
- }
-
- @DataClass.Generated.Member
- public static final @NonNull Parcelable.Creator<ToolbarMenuItem> CREATOR
- = new Parcelable.Creator<ToolbarMenuItem>() {
- @Override
- public ToolbarMenuItem[] newArray(int size) {
- return new ToolbarMenuItem[size];
- }
-
- @Override
- public ToolbarMenuItem createFromParcel(@NonNull android.os.Parcel in) {
- return new ToolbarMenuItem(in);
- }
- };
-
- /**
- * A builder for {@link ToolbarMenuItem}
- */
- @SuppressWarnings("WeakerAccess")
- @DataClass.Generated.Member
- public static final class Builder {
-
- private int mItemId;
- private @NonNull CharSequence mTitle;
- private @Nullable CharSequence mContentDescription;
- private int mGroupId;
- private @Nullable Icon mIcon;
- private @Nullable CharSequence mTooltipText;
- private int mPriority;
-
- private long mBuilderFieldsSet = 0L;
-
- /**
- * Creates a new Builder.
- *
- * @param itemId
- * The id of the menu item.
- * @param title
- * The title of the menu item.
- * @param contentDescription
- * The content description of the menu item.
- * @param groupId
- * The group id of the menu item.
- * @param icon
- * The icon id of the menu item.
- * @param tooltipText
- * The tooltip text of the menu item.
- * @param priority
- * The priority of the menu item used to display the order of the menu item.
- */
- public Builder(
- int itemId,
- @NonNull CharSequence title,
- @Nullable CharSequence contentDescription,
- int groupId,
- @Nullable Icon icon,
- @Nullable CharSequence tooltipText,
- int priority) {
- mItemId = itemId;
- mTitle = title;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mTitle);
- mContentDescription = contentDescription;
- mGroupId = groupId;
- mIcon = icon;
- mTooltipText = tooltipText;
- mPriority = priority;
- }
-
- /**
- * The id of the menu item.
- *
- * @see MenuItem#getItemId()
- */
- @DataClass.Generated.Member
- public @NonNull Builder setItemId(int value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x1;
- mItemId = value;
- return this;
- }
-
- /**
- * The title of the menu item.
- *
- * @see MenuItem#getTitle()
- */
- @DataClass.Generated.Member
- public @NonNull Builder setTitle(@NonNull CharSequence value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x2;
- mTitle = value;
- return this;
- }
-
- /**
- * The content description of the menu item.
- *
- * @see MenuItem#getContentDescription()
- */
- @DataClass.Generated.Member
- public @NonNull Builder setContentDescription(@NonNull CharSequence value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x4;
- mContentDescription = value;
- return this;
- }
-
- /**
- * The group id of the menu item.
- *
- * @see MenuItem#getGroupId()
- */
- @DataClass.Generated.Member
- public @NonNull Builder setGroupId(int value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x8;
- mGroupId = value;
- return this;
- }
-
- /**
- * The icon id of the menu item.
- *
- * @see MenuItem#getIcon()
- */
- @DataClass.Generated.Member
- public @NonNull Builder setIcon(@NonNull Icon value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x10;
- mIcon = value;
- return this;
- }
-
- /**
- * The tooltip text of the menu item.
- *
- * @see MenuItem#getTooltipText()
- */
- @DataClass.Generated.Member
- public @NonNull Builder setTooltipText(@NonNull CharSequence value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x20;
- mTooltipText = value;
- return this;
- }
-
- /**
- * The priority of the menu item used to display the order of the menu item.
- */
- @DataClass.Generated.Member
- public @NonNull Builder setPriority(int value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x40;
- mPriority = value;
- return this;
- }
-
- /** Builds the instance. This builder should not be touched after calling this! */
- public @NonNull ToolbarMenuItem build() {
- checkNotUsed();
- mBuilderFieldsSet |= 0x80; // Mark builder used
-
- ToolbarMenuItem o = new ToolbarMenuItem(
- mItemId,
- mTitle,
- mContentDescription,
- mGroupId,
- mIcon,
- mTooltipText,
- mPriority);
- return o;
- }
-
- private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x80) != 0) {
- throw new IllegalStateException(
- "This Builder should not be reused. Use a new Builder instance instead");
- }
- }
- }
-
- @DataClass.Generated(
- time = 1643200806234L,
- codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/view/selectiontoolbar/ToolbarMenuItem.java",
- inputSignatures = "public static final int PRIORITY_UNKNOWN\npublic static final int PRIORITY_PRIMARY\npublic static final int PRIORITY_OVERFLOW\nprivate final int mItemId\nprivate final @android.annotation.NonNull java.lang.CharSequence mTitle\nprivate final @android.annotation.Nullable java.lang.CharSequence mContentDescription\nprivate final int mGroupId\nprivate final @android.annotation.Nullable android.graphics.drawable.Icon mIcon\nprivate final @android.annotation.Nullable java.lang.CharSequence mTooltipText\nprivate final int mPriority\npublic static int getPriorityFromMenuItem(android.view.MenuItem)\nclass ToolbarMenuItem extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genEqualsHashCode=true)")
- @Deprecated
- private void __metadata() {}
-
-
- //@formatter:on
- // End of generated code
-
-}
diff --git a/core/java/android/view/selectiontoolbar/WidgetInfo.java b/core/java/android/view/selectiontoolbar/WidgetInfo.java
deleted file mode 100644
index 5d0fd473c914..000000000000
--- a/core/java/android/view/selectiontoolbar/WidgetInfo.java
+++ /dev/null
@@ -1,228 +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 android.view.selectiontoolbar;
-
-import android.annotation.NonNull;
-import android.graphics.Rect;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.view.SurfaceControlViewHost;
-
-import com.android.internal.util.DataClass;
-
-/**
- * The class holds the rendered content and the related information from the render service to
- * be used to show on the selection toolbar.
- *
- * @hide
- */
-@DataClass(genToString = true, genEqualsHashCode = true)
-public final class WidgetInfo implements Parcelable {
-
- /**
- * The token that is used to identify the selection toolbar.
- */
- private final long mWidgetToken;
-
- /**
- * A Rect that defines the size and positioning of the remote view with respect to
- * its host window.
- */
- @NonNull
- private final Rect mContentRect;
-
- /**
- * The SurfacePackage pointing to the remote view.
- */
- @NonNull
- private final SurfaceControlViewHost.SurfacePackage mSurfacePackage;
-
-
-
- // Code below generated by codegen v1.0.23.
- //
- // DO NOT MODIFY!
- // CHECKSTYLE:OFF Generated code
- //
- // To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/selectiontoolbar/WidgetInfo.java
- //
- // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
- // Settings > Editor > Code Style > Formatter Control
- //@formatter:off
-
-
- /**
- * Creates a new WidgetInfo.
- *
- * @param widgetToken
- * The token that is used to identify the selection toolbar.
- * @param contentRect
- * A Rect that defines the size and positioning of the remote view with respect to
- * its host window.
- * @param surfacePackage
- * The SurfacePackage pointing to the remote view.
- */
- @DataClass.Generated.Member
- public WidgetInfo(
- long widgetToken,
- @NonNull Rect contentRect,
- @NonNull SurfaceControlViewHost.SurfacePackage surfacePackage) {
- this.mWidgetToken = widgetToken;
- this.mContentRect = contentRect;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mContentRect);
- this.mSurfacePackage = surfacePackage;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mSurfacePackage);
-
- // onConstructed(); // You can define this method to get a callback
- }
-
- /**
- * The token that is used to identify the selection toolbar.
- */
- @DataClass.Generated.Member
- public long getWidgetToken() {
- return mWidgetToken;
- }
-
- /**
- * A Rect that defines the size and positioning of the remote view with respect to
- * its host window.
- */
- @DataClass.Generated.Member
- public @NonNull Rect getContentRect() {
- return mContentRect;
- }
-
- /**
- * The SurfacePackage pointing to the remote view.
- */
- @DataClass.Generated.Member
- public @NonNull SurfaceControlViewHost.SurfacePackage getSurfacePackage() {
- return mSurfacePackage;
- }
-
- @Override
- @DataClass.Generated.Member
- public String toString() {
- // You can override field toString logic by defining methods like:
- // String fieldNameToString() { ... }
-
- return "WidgetInfo { " +
- "widgetToken = " + mWidgetToken + ", " +
- "contentRect = " + mContentRect + ", " +
- "surfacePackage = " + mSurfacePackage +
- " }";
- }
-
- @Override
- @DataClass.Generated.Member
- public boolean equals(@android.annotation.Nullable Object o) {
- // You can override field equality logic by defining either of the methods like:
- // boolean fieldNameEquals(WidgetInfo other) { ... }
- // boolean fieldNameEquals(FieldType otherValue) { ... }
-
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- @SuppressWarnings("unchecked")
- WidgetInfo that = (WidgetInfo) o;
- //noinspection PointlessBooleanExpression
- return true
- && mWidgetToken == that.mWidgetToken
- && java.util.Objects.equals(mContentRect, that.mContentRect)
- && java.util.Objects.equals(mSurfacePackage, that.mSurfacePackage);
- }
-
- @Override
- @DataClass.Generated.Member
- public int hashCode() {
- // You can override field hashCode logic by defining methods like:
- // int fieldNameHashCode() { ... }
-
- int _hash = 1;
- _hash = 31 * _hash + Long.hashCode(mWidgetToken);
- _hash = 31 * _hash + java.util.Objects.hashCode(mContentRect);
- _hash = 31 * _hash + java.util.Objects.hashCode(mSurfacePackage);
- return _hash;
- }
-
- @Override
- @DataClass.Generated.Member
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- // You can override field parcelling by defining methods like:
- // void parcelFieldName(Parcel dest, int flags) { ... }
-
- dest.writeLong(mWidgetToken);
- dest.writeTypedObject(mContentRect, flags);
- dest.writeTypedObject(mSurfacePackage, flags);
- }
-
- @Override
- @DataClass.Generated.Member
- public int describeContents() { return 0; }
-
- /** @hide */
- @SuppressWarnings({"unchecked", "RedundantCast"})
- @DataClass.Generated.Member
- /* package-private */ WidgetInfo(@NonNull Parcel in) {
- // You can override field unparcelling by defining methods like:
- // static FieldType unparcelFieldName(Parcel in) { ... }
-
- long widgetToken = in.readLong();
- Rect contentRect = (Rect) in.readTypedObject(Rect.CREATOR);
- SurfaceControlViewHost.SurfacePackage surfacePackage = (SurfaceControlViewHost.SurfacePackage) in.readTypedObject(SurfaceControlViewHost.SurfacePackage.CREATOR);
-
- this.mWidgetToken = widgetToken;
- this.mContentRect = contentRect;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mContentRect);
- this.mSurfacePackage = surfacePackage;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mSurfacePackage);
-
- // onConstructed(); // You can define this method to get a callback
- }
-
- @DataClass.Generated.Member
- public static final @NonNull Parcelable.Creator<WidgetInfo> CREATOR
- = new Parcelable.Creator<WidgetInfo>() {
- @Override
- public WidgetInfo[] newArray(int size) {
- return new WidgetInfo[size];
- }
-
- @Override
- public WidgetInfo createFromParcel(@NonNull Parcel in) {
- return new WidgetInfo(in);
- }
- };
-
- @DataClass.Generated(
- time = 1643281495056L,
- codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/view/selectiontoolbar/WidgetInfo.java",
- inputSignatures = "private final long mWidgetToken\nprivate final @android.annotation.NonNull android.graphics.Rect mContentRect\nprivate final @android.annotation.NonNull android.view.SurfaceControlViewHost.SurfacePackage mSurfacePackage\nclass WidgetInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true)")
- @Deprecated
- private void __metadata() {}
-
-
- //@formatter:on
- // End of generated code
-
-}
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 1d6778b8a4a9..55b2251ac196 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -1498,6 +1498,11 @@ public class HorizontalScrollView extends FrameLayout {
* @return The unconsumed delta after the EdgeEffects have had an opportunity to consume.
*/
private int consumeFlingInStretch(int unconsumed) {
+ int scrollX = getScrollX();
+ if (scrollX < 0 || scrollX > getScrollRange()) {
+ // We've overscrolled, so don't stretch
+ return unconsumed;
+ }
if (unconsumed > 0 && mEdgeGlowLeft != null && mEdgeGlowLeft.getDistance() != 0f) {
int size = getWidth();
float deltaDistance = -unconsumed * FLING_DESTRETCH_FACTOR / size;
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index eeb6b43a89f2..d330ebf73323 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -1566,6 +1566,11 @@ public class ScrollView extends FrameLayout {
* @return The unconsumed delta after the EdgeEffects have had an opportunity to consume.
*/
private int consumeFlingInStretch(int unconsumed) {
+ int scrollY = getScrollY();
+ if (scrollY < 0 || scrollY > getScrollRange()) {
+ // We've overscrolled, so don't stretch
+ return unconsumed;
+ }
if (unconsumed > 0 && mEdgeGlowTop != null && mEdgeGlowTop.getDistance() != 0f) {
int size = getHeight();
float deltaDistance = -unconsumed * FLING_DESTRETCH_FACTOR / size;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 56349d10a404..7dbab96f3684 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -13202,9 +13202,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mTextOperationUser == null) {
return super.isStylusHandwritingAvailable();
}
- final int userId = mTextOperationUser.getIdentifier();
final InputMethodManager imm = getInputMethodManager();
- return imm.isStylusHandwritingAvailableAsUser(userId);
+ return imm.isStylusHandwritingAvailableAsUser(mTextOperationUser);
}
@Nullable
diff --git a/core/java/android/window/IWindowOrganizerController.aidl b/core/java/android/window/IWindowOrganizerController.aidl
index 534c9de8102c..5ba2f6caac2d 100644
--- a/core/java/android/window/IWindowOrganizerController.aidl
+++ b/core/java/android/window/IWindowOrganizerController.aidl
@@ -80,13 +80,8 @@ interface IWindowOrganizerController {
* Finishes a transition. This must be called for all created transitions.
* @param transitionToken Which transition to finish
* @param t Changes to make before finishing but in the same SF Transaction. Can be null.
- * @param callback Called when t is finished applying.
- * @return An ID for the sync operation (see {@link #applySyncTransaction}. This will be
- * negative if no sync transaction was attached (null t or callback)
*/
- int finishTransition(in IBinder transitionToken,
- in @nullable WindowContainerTransaction t,
- in IWindowContainerTransactionCallback callback);
+ void finishTransition(in IBinder transitionToken, in @nullable WindowContainerTransaction t);
/** @return An interface enabling the management of task organizers. */
ITaskOrganizerController getTaskOrganizerController();
diff --git a/core/java/android/window/WindowOrganizer.java b/core/java/android/window/WindowOrganizer.java
index 695d01e92316..2dc2cbca0548 100644
--- a/core/java/android/window/WindowOrganizer.java
+++ b/core/java/android/window/WindowOrganizer.java
@@ -115,19 +115,15 @@ public class WindowOrganizer {
* Finishes a running transition.
* @param transitionToken The transition to finish. Can't be null.
* @param t A set of window operations to apply before finishing.
- * @param callback A sync callback (if provided). See {@link #applySyncTransaction}.
- * @return An ID for the sync operation if performed. See {@link #applySyncTransaction}.
*
* @hide
*/
@SuppressLint("ExecutorRegistration")
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
- public int finishTransition(@NonNull IBinder transitionToken,
- @Nullable WindowContainerTransaction t,
- @Nullable WindowContainerTransactionCallback callback) {
+ public void finishTransition(@NonNull IBinder transitionToken,
+ @Nullable WindowContainerTransaction t) {
try {
- return getWindowOrganizerController().finishTransition(transitionToken, t,
- callback != null ? callback.mInterface : null);
+ getWindowOrganizerController().finishTransition(transitionToken, t);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java
index 6a32529f31c7..c1d1b2754895 100644
--- a/core/java/android/window/WindowTokenClient.java
+++ b/core/java/android/window/WindowTokenClient.java
@@ -23,12 +23,12 @@ import android.annotation.AnyThread;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.app.ActivityThread;
-import android.app.IWindowToken;
import android.app.ResourcesManager;
import android.content.Context;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.inputmethodservice.AbstractInputMethodService;
+import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
@@ -37,6 +37,7 @@ import android.os.IBinder;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.function.pooled.PooledLambda;
import java.lang.ref.WeakReference;
@@ -52,7 +53,7 @@ import java.lang.ref.WeakReference;
*
* @hide
*/
-public class WindowTokenClient extends IWindowToken.Stub {
+public class WindowTokenClient extends Binder {
private static final String TAG = WindowTokenClient.class.getSimpleName();
/**
@@ -95,16 +96,16 @@ public class WindowTokenClient extends IWindowToken.Stub {
* @param newConfig the updated {@link Configuration}
* @param newDisplayId the updated {@link android.view.Display} ID
*/
- @AnyThread
- @Override
+ @VisibleForTesting
+ @MainThread
public void onConfigurationChanged(Configuration newConfig, int newDisplayId) {
- // TODO(b/290876897): No need to post on mHandler after migrating to ClientTransaction
- postOnConfigurationChanged(newConfig, newDisplayId);
+ onConfigurationChanged(newConfig, newDisplayId, true /* shouldReportConfigChange */);
}
/**
* Posts an {@link #onConfigurationChanged} to the main thread.
*/
+ @VisibleForTesting
public void postOnConfigurationChanged(@NonNull Configuration newConfig, int newDisplayId) {
mHandler.post(PooledLambda.obtainRunnable(this::onConfigurationChanged, newConfig,
newDisplayId, true /* shouldReportConfigChange */).recycleOnUse());
@@ -120,14 +121,13 @@ public class WindowTokenClient extends IWindowToken.Stub {
* <p>
* Note that this method must be executed on the main thread if
* {@code shouldReportConfigChange} is {@code true}, which is usually from
- * {@link IWindowToken#onConfigurationChanged(Configuration, int)}
+ * {@link #onConfigurationChanged(Configuration, int)}
* directly, while this method could be run on any thread if it is used to initialize
* Context's {@code Configuration} via {@link WindowTokenClientController#attachToDisplayArea}
* or {@link WindowTokenClientController#attachToDisplayContent}.
*
* @param shouldReportConfigChange {@code true} to indicate that the {@code Configuration}
* should be dispatched to listeners.
- *
*/
@AnyThread
public void onConfigurationChanged(Configuration newConfig, int newDisplayId,
@@ -193,16 +193,12 @@ public class WindowTokenClient extends IWindowToken.Stub {
}
}
- @AnyThread
- @Override
- public void onWindowTokenRemoved() {
- // TODO(b/290876897): No need to post on mHandler after migrating to ClientTransaction
- mHandler.post(PooledLambda.obtainRunnable(
- WindowTokenClient::onWindowTokenRemovedInner, this).recycleOnUse());
- }
-
+ /**
+ * Called when the attached window is removed from the display.
+ */
+ @VisibleForTesting
@MainThread
- private void onWindowTokenRemovedInner() {
+ public void onWindowTokenRemoved() {
final Context context = mContextRef.get();
if (context != null) {
context.destroy();
diff --git a/core/java/android/window/WindowTokenClientController.java b/core/java/android/window/WindowTokenClientController.java
index 7a84123c91e1..10f6d5e7abaa 100644
--- a/core/java/android/window/WindowTokenClientController.java
+++ b/core/java/android/window/WindowTokenClientController.java
@@ -160,7 +160,7 @@ public class WindowTokenClientController {
/** Detaches a {@link WindowTokenClient} from associated WindowContainer if there's one. */
public void detachIfNeeded(@NonNull WindowTokenClient client) {
synchronized (mLock) {
- if (mWindowTokenClientMap.remove(client.asBinder()) == null) {
+ if (mWindowTokenClientMap.remove(client) == null) {
return;
}
}
@@ -174,7 +174,7 @@ public class WindowTokenClientController {
private void onWindowContextTokenAttached(@NonNull WindowTokenClient client,
@NonNull WindowContextInfo info, boolean shouldReportConfigChange) {
synchronized (mLock) {
- mWindowTokenClientMap.put(client.asBinder(), client);
+ mWindowTokenClientMap.put(client, client);
}
if (shouldReportConfigChange) {
// Should trigger an #onConfigurationChanged callback to the WindowContext. Post the
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index f19f6c7949d2..2efe44544f37 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -128,7 +128,7 @@ public class AccessibilityShortcutController {
DialogStatus.SHOWN,
})
/** Denotes the user shortcut type. */
- private @interface DialogStatus {
+ @interface DialogStatus {
int NOT_SHOWN = 0;
int SHOWN = 1;
}
@@ -333,12 +333,35 @@ public class AccessibilityShortcutController {
// Avoid non-a11y users accidentally turning shortcut on without reading this carefully.
// Put "don't turn on" as the primary action.
final AlertDialog alertDialog = mFrameworkObjectProvider.getAlertDialogBuilder(
- // Use SystemUI context so we pick up any theme set in a vendor overlay
- mFrameworkObjectProvider.getSystemUiContext())
+ // Use SystemUI context so we pick up any theme set in a vendor overlay
+ mFrameworkObjectProvider.getSystemUiContext())
.setTitle(getShortcutWarningTitle(targets))
.setMessage(getShortcutWarningMessage(targets))
.setCancelable(false)
- .setNegativeButton(R.string.accessibility_shortcut_on, null)
+ .setNegativeButton(R.string.accessibility_shortcut_on,
+ (DialogInterface d, int which) -> {
+ String targetServices = Settings.Secure.getStringForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, userId);
+ String defaultService = mContext.getString(
+ R.string.config_defaultAccessibilityService);
+ // If the targetServices is null, means the user enables a
+ // shortcut for the default service by triggering the volume keys
+ // shortcut in the SUW instead of intentionally configuring the
+ // shortcut on UI.
+ if (targetServices == null && !TextUtils.isEmpty(defaultService)) {
+ // The defaultService in the string resource could be a shorten
+ // form like com.google.android.marvin.talkback/.TalkBackService.
+ // Converts it to the componentName for consistency before saving
+ // to the Settings.
+ final ComponentName configDefaultService =
+ ComponentName.unflattenFromString(defaultService);
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+ configDefaultService.flattenToString(),
+ userId);
+ }
+ })
.setPositiveButton(R.string.accessibility_shortcut_off,
(DialogInterface d, int which) -> {
Settings.Secure.putStringForUser(mContext.getContentResolver(),
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index d433cd652606..5f688f6406bc 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -158,7 +158,8 @@ interface IBatteryStats {
@EnforcePermission("UPDATE_DEVICE_STATS")
void notePhoneSignalStrength(in SignalStrength signalStrength);
@EnforcePermission("UPDATE_DEVICE_STATS")
- void notePhoneDataConnectionState(int dataType, boolean hasData, int serviceType, int nrFrequency);
+ void notePhoneDataConnectionState(int dataType, boolean hasData, int serviceType, int nrState,
+ int nrFrequency);
@EnforcePermission("UPDATE_DEVICE_STATS")
void notePhoneState(int phoneState);
@EnforcePermission("UPDATE_DEVICE_STATS")
diff --git a/core/java/com/android/internal/app/NetInitiatedActivity.java b/core/java/com/android/internal/app/NetInitiatedActivity.java
deleted file mode 100644
index f34aabbeded6..000000000000
--- a/core/java/com/android/internal/app/NetInitiatedActivity.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2007 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.app;
-
-import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.location.LocationManagerInternal;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-
-import com.android.internal.R;
-import com.android.internal.location.GpsNetInitiatedHandler;
-import com.android.server.LocalServices;
-
-/**
- * This activity is shown to the user for them to accept or deny network-initiated
- * requests. It uses the alert dialog style. It will be launched from a notification.
- */
-public class NetInitiatedActivity extends AlertActivity implements DialogInterface.OnClickListener {
-
- private static final String TAG = "NetInitiatedActivity";
-
- private static final boolean DEBUG = true;
-
- private static final int POSITIVE_BUTTON = AlertDialog.BUTTON_POSITIVE;
- private static final int NEGATIVE_BUTTON = AlertDialog.BUTTON_NEGATIVE;
-
- private static final int GPS_NO_RESPONSE_TIME_OUT = 1;
- // Received ID from intent, -1 when no notification is in progress
- private int notificationId = -1;
- private int timeout = -1;
- private int default_response = -1;
- private int default_response_timeout = 6;
-
- private final Handler mHandler = new Handler() {
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case GPS_NO_RESPONSE_TIME_OUT: {
- if (notificationId != -1) {
- sendUserResponse(default_response);
- }
- finish();
- }
- break;
- default:
- }
- }
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
-
- // Set up the "dialog"
- final Intent intent = getIntent();
- final AlertController.AlertParams p = mAlertParams;
- Context context = getApplicationContext();
- p.mTitle = intent.getStringExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_TITLE);
- p.mMessage = intent.getStringExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_MESSAGE);
- p.mPositiveButtonText = String.format(context.getString(R.string.gpsVerifYes));
- p.mPositiveButtonListener = this;
- p.mNegativeButtonText = String.format(context.getString(R.string.gpsVerifNo));
- p.mNegativeButtonListener = this;
-
- notificationId = intent.getIntExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_NOTIF_ID, -1);
- timeout = intent.getIntExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_TIMEOUT, default_response_timeout);
- default_response = intent.getIntExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_DEFAULT_RESPONSE, GpsNetInitiatedHandler.GPS_NI_RESPONSE_ACCEPT);
- if (DEBUG) Log.d(TAG, "onCreate() : notificationId: " + notificationId + " timeout: " + timeout + " default_response:" + default_response);
-
- mHandler.sendMessageDelayed(mHandler.obtainMessage(GPS_NO_RESPONSE_TIME_OUT), (timeout * 1000));
- setupAlert();
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- if (DEBUG) Log.d(TAG, "onResume");
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- if (DEBUG) Log.d(TAG, "onPause");
- }
-
- /**
- * {@inheritDoc}
- */
- public void onClick(DialogInterface dialog, int which) {
- if (which == POSITIVE_BUTTON) {
- sendUserResponse(GpsNetInitiatedHandler.GPS_NI_RESPONSE_ACCEPT);
- }
- if (which == NEGATIVE_BUTTON) {
- sendUserResponse(GpsNetInitiatedHandler.GPS_NI_RESPONSE_DENY);
- }
-
- // No matter what, finish the activity
- finish();
- notificationId = -1;
- }
-
- // Respond to NI Handler under GnssLocationProvider, 1 = accept, 2 = deny
- private void sendUserResponse(int response) {
- if (DEBUG) Log.d(TAG, "sendUserResponse, response: " + response);
- LocationManagerInternal lm = LocalServices.getService(LocationManagerInternal.class);
- lm.sendNiResponse(notificationId, response);
- }
-}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 2445daf89b64..ac15f11ee989 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -40,6 +40,7 @@ import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTE
import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.UiThread;
@@ -68,6 +69,7 @@ import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Insets;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
@@ -93,6 +95,7 @@ import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.Button;
@@ -488,6 +491,14 @@ public class ResolverActivity extends Activity implements
rdl.setOnApplyWindowInsetsListener(this::onApplyWindowInsets);
mResolverDrawerLayout = rdl;
+
+ for (int i = 0, size = mMultiProfilePagerAdapter.getCount(); i < size; i++) {
+ View view = mMultiProfilePagerAdapter.getItem(i).rootView.findViewById(
+ R.id.resolver_list);
+ if (view != null) {
+ view.setAccessibilityDelegate(new AppListAccessibilityDelegate(rdl));
+ }
+ }
}
mProfileView = findViewById(R.id.profile_button);
@@ -2607,4 +2618,41 @@ public class ResolverActivity extends Activity implements
}
return resolveInfo.userHandle;
}
+
+ /**
+ * An a11y delegate that expands resolver drawer when gesture navigation reaches a partially
+ * invisible target in the list.
+ */
+ private static class AppListAccessibilityDelegate extends View.AccessibilityDelegate {
+ private final ResolverDrawerLayout mDrawer;
+ @Nullable
+ private final View mBottomBar;
+ private final Rect mRect = new Rect();
+
+ private AppListAccessibilityDelegate(ResolverDrawerLayout drawer) {
+ mDrawer = drawer;
+ mBottomBar = mDrawer.findViewById(R.id.button_bar_container);
+ }
+
+ @Override
+ public boolean onRequestSendAccessibilityEvent(@androidx.annotation.NonNull ViewGroup host,
+ @NonNull View child,
+ @NonNull AccessibilityEvent event) {
+ boolean result = super.onRequestSendAccessibilityEvent(host, child, event);
+ if (result && event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
+ && mDrawer.isCollapsed()) {
+ child.getBoundsOnScreen(mRect);
+ int childTop = mRect.top;
+ int childBottom = mRect.bottom;
+ mDrawer.getBoundsOnScreen(mRect, true);
+ int bottomBarHeight = mBottomBar == null ? 0 : mBottomBar.getHeight();
+ int drawerTop = mRect.top;
+ int drawerBottom = mRect.bottom - bottomBarHeight;
+ if (drawerTop > childTop || childBottom > drawerBottom) {
+ mDrawer.setCollapsed(false);
+ }
+ }
+ return result;
+ }
+ }
}
diff --git a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
index 10336bd36c28..9233050c97ad 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
@@ -70,10 +70,6 @@ public class SystemUiSystemPropertiesFlags {
public static final Flag OTP_REDACTION =
devFlag("persist.sysui.notification.otp_redaction");
- /** Gating the removal of sorting-notifications-by-interruptiveness. */
- public static final Flag NO_SORT_BY_INTERRUPTIVENESS =
- releasedFlag("persist.sysui.notification.no_sort_by_interruptiveness");
-
/** Gating the logging of DND state change events. */
public static final Flag LOG_DND_STATE_EVENTS =
releasedFlag("persist.sysui.notification.log_dnd_state_events");
@@ -86,7 +82,7 @@ public class SystemUiSystemPropertiesFlags {
public static final Flag RANKING_UPDATE_ASHMEM = devFlag(
"persist.sysui.notification.ranking_update_ashmem");
- public static final Flag PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS = devFlag(
+ public static final Flag PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS = releasedFlag(
"persist.sysui.notification.propagate_channel_updates_to_conversations");
}
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index 1cde7421fe6b..0a938ef4d81c 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -1226,6 +1226,17 @@ public class BatteryStatsHistory {
}
/**
+ * Records a data connection type change event.
+ */
+ public void recordNrStateChangeEvent(long elapsedRealtimeMs, long uptimeMs,
+ int nrState) {
+ mHistoryCur.states2 = setBitField(mHistoryCur.states2, nrState,
+ HistoryItem.STATE2_NR_STATE_SHIFT,
+ HistoryItem.STATE2_NR_STATE_MASK);
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
+
+ /**
* Records a WiFi supplicant state change event.
*/
public void recordWifiSupplicantStateChangeEvent(long elapsedRealtimeMs, long uptimeMs,
@@ -1556,7 +1567,7 @@ public class BatteryStatsHistory {
State2 change int: if C in the first token is set,
31 23 15 7 0
- █M|L|K|J|I|H|H|G█F|E|D|C| | | | █ | | | | | | |N█N|B|B|B|A|A|A|A█
+ █M|L|K|J|I|H|H|G█F|E|D|C| | | | █ | | | | |O|O|N█N|B|B|B|A|A|A|A█
A: 4 bits indicating the wifi supplicant state: {@link BatteryStats#WIFI_SUPPL_STATE_NAMES}.
B: 3 bits indicating the wifi signal strength: 0, 1, 2, 3, 4.
@@ -1572,6 +1583,7 @@ public class BatteryStatsHistory {
L: video was playing.
M: power save mode was on.
N: 2 bits indicating the gps signal strength: poor, good, none.
+ O: 2 bits indicating nr state: none, restricted, not restricted, connected.
Wakelock/wakereason struct: if D in the first token is set,
Event struct: if E in the first token is set,
diff --git a/core/java/com/android/internal/os/TEST_MAPPING b/core/java/com/android/internal/os/TEST_MAPPING
index 60b160ad18c2..d552e0b8c643 100644
--- a/core/java/com/android/internal/os/TEST_MAPPING
+++ b/core/java/com/android/internal/os/TEST_MAPPING
@@ -38,11 +38,18 @@
],
"name": "FrameworksServicesTests",
"options": [
- { "include-filter": "com.android.server.am.BatteryStatsServiceTest" },
- { "include-filter": "com.android.server.power.stats.BatteryStatsTests" }
+ { "include-filter": "com.android.server.am.BatteryStatsServiceTest" }
]
},
{
+ "file_patterns": [
+ "Battery[^/]*\\.java",
+ "Kernel[^/]*\\.java",
+ "[^/]*Power[^/]*\\.java"
+ ],
+ "name": "PowerStatsTests"
+ },
+ {
"name": "FrameworksCoreTests",
"options": [
{
diff --git a/core/java/com/android/internal/power/TEST_MAPPING b/core/java/com/android/internal/power/TEST_MAPPING
index c6cab183d970..1946f5cc99eb 100644
--- a/core/java/com/android/internal/power/TEST_MAPPING
+++ b/core/java/com/android/internal/power/TEST_MAPPING
@@ -8,11 +8,7 @@
]
},
{
- "name": "FrameworksServicesTests",
- "options": [
- { "include-filter": "com.android.server.am.BatteryStatsServiceTest" },
- { "include-filter": "com.android.server.power.stats.BatteryStatsTests" }
- ]
+ "name": "PowerStatsTests"
}
]
}
diff --git a/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbarPopup.java b/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbarPopup.java
index f7af67b3b2a8..e9449eb96bb3 100644
--- a/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbarPopup.java
+++ b/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbarPopup.java
@@ -21,7 +21,6 @@ import android.content.Context;
import android.graphics.Rect;
import android.view.MenuItem;
import android.view.View;
-import android.view.selectiontoolbar.SelectionToolbarManager;
import android.widget.PopupWindow;
import java.util.List;
@@ -89,14 +88,10 @@ public interface FloatingToolbarPopup {
@Nullable PopupWindow.OnDismissListener onDismiss);
/**
- * Returns {@link RemoteFloatingToolbarPopup} implementation if the system selection toolbar
- * enabled, otherwise returns {@link LocalFloatingToolbarPopup} implementation.
+ * Returns {@link LocalFloatingToolbarPopup} implementation.
*/
static FloatingToolbarPopup createInstance(Context context, View parent) {
- boolean enabled = SelectionToolbarManager.isRemoteSelectionToolbarEnabled(context);
- return enabled
- ? new RemoteFloatingToolbarPopup(context, parent)
- : new LocalFloatingToolbarPopup(context, parent);
+ return new LocalFloatingToolbarPopup(context, parent);
}
}
diff --git a/core/java/com/android/internal/widget/floatingtoolbar/RemoteFloatingToolbarPopup.java b/core/java/com/android/internal/widget/floatingtoolbar/RemoteFloatingToolbarPopup.java
deleted file mode 100644
index 8787c39458b9..000000000000
--- a/core/java/com/android/internal/widget/floatingtoolbar/RemoteFloatingToolbarPopup.java
+++ /dev/null
@@ -1,572 +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.internal.widget.floatingtoolbar;
-
-import static android.view.selectiontoolbar.SelectionToolbarManager.NO_TOOLBAR_ID;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UiThread;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.PixelFormat;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.MenuItem;
-import android.view.SurfaceView;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.selectiontoolbar.ISelectionToolbarCallback;
-import android.view.selectiontoolbar.SelectionToolbarManager;
-import android.view.selectiontoolbar.ShowInfo;
-import android.view.selectiontoolbar.ToolbarMenuItem;
-import android.view.selectiontoolbar.WidgetInfo;
-import android.widget.LinearLayout;
-import android.widget.PopupWindow;
-
-import com.android.internal.R;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * A popup window used by the floating toolbar to render menu items in the remote system process.
- *
- * It holds 2 panels (i.e. main panel and overflow panel) and an overflow button
- * to transition between panels.
- */
-public final class RemoteFloatingToolbarPopup implements FloatingToolbarPopup {
-
- private static final boolean DEBUG =
- Log.isLoggable(FloatingToolbar.FLOATING_TOOLBAR_TAG, Log.VERBOSE);
-
- private static final int TOOLBAR_STATE_SHOWN = 1;
- private static final int TOOLBAR_STATE_HIDDEN = 2;
- private static final int TOOLBAR_STATE_DISMISSED = 3;
-
- @IntDef(prefix = {"TOOLBAR_STATE_"}, value = {
- TOOLBAR_STATE_SHOWN,
- TOOLBAR_STATE_HIDDEN,
- TOOLBAR_STATE_DISMISSED
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface ToolbarState {
- }
-
- @NonNull
- private final SelectionToolbarManager mSelectionToolbarManager;
- // Parent for the popup window.
- @NonNull
- private final View mParent;
- // A popup window used for showing menu items rendered by the remote system process
- @NonNull
- private final PopupWindow mPopupWindow;
- // The callback to handle remote rendered selection toolbar.
- @NonNull
- private final SelectionToolbarCallbackImpl mSelectionToolbarCallback;
-
- // tracks this popup state.
- private @ToolbarState int mState;
-
- // The token of the current showing floating toolbar.
- private long mFloatingToolbarToken;
- private final Rect mPreviousContentRect = new Rect();
- private List<MenuItem> mMenuItems;
- private MenuItem.OnMenuItemClickListener mMenuItemClickListener;
- private int mSuggestedWidth;
- private final Rect mScreenViewPort = new Rect();
- private boolean mWidthChanged = true;
- private final boolean mIsLightTheme;
-
- private final int[] mCoordsOnScreen = new int[2];
- private final int[] mCoordsOnWindow = new int[2];
-
- public RemoteFloatingToolbarPopup(Context context, View parent) {
- mParent = Objects.requireNonNull(parent);
- mPopupWindow = createPopupWindow(context);
- mSelectionToolbarManager = context.getSystemService(SelectionToolbarManager.class);
- mSelectionToolbarCallback = new SelectionToolbarCallbackImpl(this);
- mIsLightTheme = isLightTheme(context);
- mFloatingToolbarToken = NO_TOOLBAR_ID;
- }
-
- private boolean isLightTheme(Context context) {
- TypedArray a = context.obtainStyledAttributes(new int[]{R.attr.isLightTheme});
- boolean isLightTheme = a.getBoolean(0, true);
- a.recycle();
- return isLightTheme;
- }
-
- @UiThread
- @Override
- public void show(List<MenuItem> menuItems,
- MenuItem.OnMenuItemClickListener menuItemClickListener, Rect contentRect) {
- Objects.requireNonNull(menuItems);
- Objects.requireNonNull(menuItemClickListener);
- if (isShowing() && Objects.equals(menuItems, mMenuItems)
- && Objects.equals(contentRect, mPreviousContentRect)) {
- if (DEBUG) {
- Log.v(FloatingToolbar.FLOATING_TOOLBAR_TAG,
- "Ignore duplicate show() for the same content.");
- }
- return;
- }
-
- boolean isLayoutRequired = mMenuItems == null
- || !MenuItemRepr.reprEquals(menuItems, mMenuItems)
- || mWidthChanged;
- if (isLayoutRequired) {
- mSelectionToolbarManager.dismissToolbar(mFloatingToolbarToken);
- doDismissPopupWindow();
- }
- mMenuItemClickListener = menuItemClickListener;
- mMenuItems = menuItems;
-
- mParent.getWindowVisibleDisplayFrame(mScreenViewPort);
- final int suggestWidth = mSuggestedWidth > 0
- ? mSuggestedWidth
- : mParent.getResources().getDimensionPixelSize(
- R.dimen.floating_toolbar_preferred_width);
- final ShowInfo showInfo = new ShowInfo(
- mFloatingToolbarToken, isLayoutRequired,
- getToolbarMenuItems(mMenuItems),
- contentRect,
- suggestWidth,
- mScreenViewPort,
- mParent.getViewRootImpl().getInputToken(), mIsLightTheme);
- if (DEBUG) {
- Log.v(FloatingToolbar.FLOATING_TOOLBAR_TAG,
- "RemoteFloatingToolbarPopup.show() for " + showInfo);
- }
- mSelectionToolbarManager.showToolbar(showInfo, mSelectionToolbarCallback);
- mPreviousContentRect.set(contentRect);
- }
-
- @UiThread
- @Override
- public void dismiss() {
- if (mState == TOOLBAR_STATE_DISMISSED) {
- Log.w(FloatingToolbar.FLOATING_TOOLBAR_TAG,
- "The floating toolbar already dismissed.");
- return;
- }
- if (DEBUG) {
- Log.v(FloatingToolbar.FLOATING_TOOLBAR_TAG,
- "RemoteFloatingToolbarPopup.dismiss().");
- }
- mSelectionToolbarManager.dismissToolbar(mFloatingToolbarToken);
- doDismissPopupWindow();
- }
-
- @UiThread
- @Override
- public void hide() {
- if (mState == TOOLBAR_STATE_DISMISSED || mState == TOOLBAR_STATE_HIDDEN) {
- if (DEBUG) {
- Log.v(FloatingToolbar.FLOATING_TOOLBAR_TAG,
- "The floating toolbar already dismissed or hidden.");
- }
- return;
- }
- if (DEBUG) {
- Log.v(FloatingToolbar.FLOATING_TOOLBAR_TAG,
- "RemoteFloatingToolbarPopup.hide().");
- }
- mSelectionToolbarManager.hideToolbar(mFloatingToolbarToken);
- mState = TOOLBAR_STATE_HIDDEN;
- mPopupWindow.dismiss();
- }
-
- @UiThread
- @Override
- public void setSuggestedWidth(int suggestedWidth) {
- int difference = Math.abs(suggestedWidth - mSuggestedWidth);
- mWidthChanged = difference > (mSuggestedWidth * 0.2);
- mSuggestedWidth = suggestedWidth;
- }
-
- @Override
- public void setWidthChanged(boolean widthChanged) {
- mWidthChanged = widthChanged;
- }
-
- @UiThread
- @Override
- public boolean isHidden() {
- return mState == TOOLBAR_STATE_HIDDEN;
- }
-
- @UiThread
- @Override
- public boolean isShowing() {
- return mState == TOOLBAR_STATE_SHOWN;
- }
-
- @UiThread
- @Override
- public boolean setOutsideTouchable(boolean outsideTouchable,
- @Nullable PopupWindow.OnDismissListener onDismiss) {
- if (mState == TOOLBAR_STATE_DISMISSED) {
- return false;
- }
- boolean ret = false;
- if (mPopupWindow.isOutsideTouchable() ^ outsideTouchable) {
- mPopupWindow.setOutsideTouchable(outsideTouchable);
- mPopupWindow.setFocusable(!outsideTouchable);
- mPopupWindow.update();
- ret = true;
- }
- mPopupWindow.setOnDismissListener(onDismiss);
- return ret;
- }
-
- private void updatePopupWindowContent(WidgetInfo widgetInfo) {
- if (DEBUG) {
- Log.v(FloatingToolbar.FLOATING_TOOLBAR_TAG, "updatePopupWindowContent.");
- }
- ViewGroup contentContainer = (ViewGroup) mPopupWindow.getContentView();
- contentContainer.removeAllViews();
- SurfaceView surfaceView = new SurfaceView(mParent.getContext());
- surfaceView.setZOrderOnTop(true);
- surfaceView.getHolder().setFormat(PixelFormat.TRANSPARENT);
- surfaceView.setChildSurfacePackage(widgetInfo.getSurfacePackage());
- contentContainer.addView(surfaceView);
- }
-
- private MenuItem getMenuItemByToolbarMenuItem(ToolbarMenuItem toolbarMenuItem) {
- for (MenuItem item : mMenuItems) {
- if (toolbarMenuItem.getItemId() == item.getItemId()) {
- return item;
- }
- }
- return null;
- }
-
- private Point getCoordinatesInWindow(int x, int y) {
- // We later specify the location of PopupWindow relative to the attached window.
- // The idea here is that 1) we can get the location of a View in both window coordinates
- // and screen coordinates, where the offset between them should be equal to the window
- // origin, and 2) we can use an arbitrary for this calculation while calculating the
- // location of the rootview is supposed to be least expensive.
- // TODO: Consider to use PopupWindow.setIsLaidOutInScreen(true) so that we can avoid
- // the following calculation.
- mParent.getRootView().getLocationOnScreen(mCoordsOnScreen);
- mParent.getRootView().getLocationInWindow(mCoordsOnWindow);
- int windowLeftOnScreen = mCoordsOnScreen[0] - mCoordsOnWindow[0];
- int windowTopOnScreen = mCoordsOnScreen[1] - mCoordsOnWindow[1];
- return new Point(Math.max(0, x - windowLeftOnScreen), Math.max(0, y - windowTopOnScreen));
- }
-
- private static List<ToolbarMenuItem> getToolbarMenuItems(List<MenuItem> menuItems) {
- final List<ToolbarMenuItem> list = new ArrayList<>(menuItems.size());
- for (MenuItem menuItem : menuItems) {
- // TODO: use ToolbarMenuItem.Builder(MenuItem) instead
- ToolbarMenuItem toolbarMenuItem = new ToolbarMenuItem.Builder(menuItem.getItemId(),
- menuItem.getTitle(), menuItem.getContentDescription(), menuItem.getGroupId(),
- convertDrawableToIcon(menuItem.getIcon()),
- menuItem.getTooltipText(),
- ToolbarMenuItem.getPriorityFromMenuItem(menuItem)).build();
- list.add(toolbarMenuItem);
- }
- return list;
- }
-
- private static Icon convertDrawableToIcon(Drawable drawable) {
- if (drawable == null) {
- return null;
- }
- if (drawable instanceof BitmapDrawable) {
- final BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
- if (bitmapDrawable.getBitmap() != null) {
- return Icon.createWithBitmap(bitmapDrawable.getBitmap());
- }
- }
- final Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
- drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
- final Canvas canvas = new Canvas(bitmap);
- drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
- drawable.draw(canvas);
- return Icon.createWithBitmap(bitmap);
- }
-
- private static PopupWindow createPopupWindow(Context content) {
- ViewGroup popupContentHolder = new LinearLayout(content);
- PopupWindow popupWindow = new PopupWindow(popupContentHolder);
- popupWindow.setClippingEnabled(false);
- popupWindow.setWindowLayoutType(
- WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL);
- popupWindow.setAnimationStyle(0);
- popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
- return popupWindow;
- }
-
- private void doDismissPopupWindow() {
- if (DEBUG) {
- Log.v(FloatingToolbar.FLOATING_TOOLBAR_TAG, "RemoteFloatingToolbarPopup.doDismiss().");
- }
- mState = TOOLBAR_STATE_DISMISSED;
- mMenuItems = null;
- mMenuItemClickListener = null;
- mFloatingToolbarToken = 0;
- mSuggestedWidth = 0;
- mWidthChanged = true;
- resetCoords();
- mPreviousContentRect.setEmpty();
- mScreenViewPort.setEmpty();
- mPopupWindow.dismiss();
- }
-
- private void resetCoords() {
- mCoordsOnScreen[0] = 0;
- mCoordsOnScreen[1] = 0;
- mCoordsOnWindow[0] = 0;
- mCoordsOnWindow[1] = 0;
- }
-
- private void runOnUiThread(Runnable runnable) {
- mParent.post(runnable);
- }
-
- private void onShow(WidgetInfo info) {
- runOnUiThread(() -> {
- mFloatingToolbarToken = info.getWidgetToken();
- mState = TOOLBAR_STATE_SHOWN;
- updatePopupWindowContent(info);
- Rect contentRect = info.getContentRect();
- mPopupWindow.setWidth(contentRect.width());
- mPopupWindow.setHeight(contentRect.height());
- final Point coords = getCoordinatesInWindow(contentRect.left, contentRect.top);
- mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, coords.x, coords.y);
- });
- }
-
- private void onWidgetUpdated(WidgetInfo info) {
- runOnUiThread(() -> {
- if (!isShowing()) {
- Log.w(FloatingToolbar.FLOATING_TOOLBAR_TAG,
- "onWidgetUpdated(): The widget isn't showing.");
- return;
- }
- updatePopupWindowContent(info);
- Rect contentRect = info.getContentRect();
- Point coords = getCoordinatesInWindow(contentRect.left, contentRect.top);
- if (DEBUG) {
- Log.v(FloatingToolbar.FLOATING_TOOLBAR_TAG,
- "PopupWindow x= " + coords.x + " y= " + coords.y + " w="
- + contentRect.width() + " h=" + contentRect.height());
- }
- mPopupWindow.update(coords.x, coords.y, contentRect.width(), contentRect.height());
- });
- }
-
- private void onToolbarShowTimeout() {
- runOnUiThread(() -> {
- if (mState == TOOLBAR_STATE_DISMISSED) {
- return;
- }
- doDismissPopupWindow();
- });
- }
-
- private void onMenuItemClicked(ToolbarMenuItem toolbarMenuItem) {
- runOnUiThread(() -> {
- if (mMenuItems == null || mMenuItemClickListener == null) {
- return;
- }
- MenuItem item = getMenuItemByToolbarMenuItem(toolbarMenuItem);
- if (DEBUG) {
- Log.v(FloatingToolbar.FLOATING_TOOLBAR_TAG,
- "SelectionToolbarCallbackImpl onMenuItemClicked. toolbarMenuItem="
- + toolbarMenuItem + " item=" + item);
- }
- // TODO: handle the menu item like clipboard
- if (item != null) {
- mMenuItemClickListener.onMenuItemClick(item);
- } else {
- Log.e(FloatingToolbar.FLOATING_TOOLBAR_TAG,
- "onMenuItemClicked: cannot find menu item.");
- }
- });
- }
-
- private static class SelectionToolbarCallbackImpl extends ISelectionToolbarCallback.Stub {
-
- private final WeakReference<RemoteFloatingToolbarPopup> mRemotePopup;
-
- SelectionToolbarCallbackImpl(RemoteFloatingToolbarPopup popup) {
- mRemotePopup = new WeakReference<>(popup);
- }
-
- @Override
- public void onShown(WidgetInfo info) {
- if (DEBUG) {
- Log.v(FloatingToolbar.FLOATING_TOOLBAR_TAG,
- "SelectionToolbarCallbackImpl onShown: " + info);
- }
- final RemoteFloatingToolbarPopup remoteFloatingToolbarPopup = mRemotePopup.get();
- if (remoteFloatingToolbarPopup != null) {
- remoteFloatingToolbarPopup.onShow(info);
- } else {
- Log.w(FloatingToolbar.FLOATING_TOOLBAR_TAG,
- "Lost remoteFloatingToolbarPopup reference for onShown.");
- }
- }
-
- @Override
- public void onWidgetUpdated(WidgetInfo info) {
- if (DEBUG) {
- Log.v(FloatingToolbar.FLOATING_TOOLBAR_TAG,
- "SelectionToolbarCallbackImpl onWidgetUpdated: info = " + info);
- }
- final RemoteFloatingToolbarPopup remoteFloatingToolbarPopup = mRemotePopup.get();
- if (remoteFloatingToolbarPopup != null) {
- remoteFloatingToolbarPopup.onWidgetUpdated(info);
- } else {
- Log.w(FloatingToolbar.FLOATING_TOOLBAR_TAG,
- "Lost remoteFloatingToolbarPopup reference for onWidgetUpdated.");
- }
- }
-
- @Override
- public void onToolbarShowTimeout() {
- final RemoteFloatingToolbarPopup remoteFloatingToolbarPopup = mRemotePopup.get();
- if (remoteFloatingToolbarPopup != null) {
- remoteFloatingToolbarPopup.onToolbarShowTimeout();
- } else {
- Log.w(FloatingToolbar.FLOATING_TOOLBAR_TAG,
- "Lost remoteFloatingToolbarPopup reference for onToolbarShowTimeout.");
- }
- }
-
- @Override
- public void onMenuItemClicked(ToolbarMenuItem toolbarMenuItem) {
- final RemoteFloatingToolbarPopup remoteFloatingToolbarPopup = mRemotePopup.get();
- if (remoteFloatingToolbarPopup != null) {
- remoteFloatingToolbarPopup.onMenuItemClicked(toolbarMenuItem);
- } else {
- Log.w(FloatingToolbar.FLOATING_TOOLBAR_TAG,
- "Lost remoteFloatingToolbarPopup reference for onMenuItemClicked.");
- }
- }
-
- @Override
- public void onError(int errorCode) {
- if (DEBUG) {
- Log.v(FloatingToolbar.FLOATING_TOOLBAR_TAG,
- "SelectionToolbarCallbackImpl onError: " + errorCode);
- }
- }
- }
-
- /**
- * Represents the identity of a MenuItem that is rendered in a FloatingToolbarPopup.
- */
- static final class MenuItemRepr {
-
- public final int mItemId;
- public final int mGroupId;
- @Nullable
- public final String mTitle;
- @Nullable private final Drawable mIcon;
-
- private MenuItemRepr(
- int itemId, int groupId, @Nullable CharSequence title,
- @Nullable Drawable icon) {
- mItemId = itemId;
- mGroupId = groupId;
- mTitle = (title == null) ? null : title.toString();
- mIcon = icon;
- }
-
- /**
- * Creates an instance of MenuItemRepr for the specified menu item.
- */
- public static MenuItemRepr of(MenuItem menuItem) {
- return new MenuItemRepr(
- menuItem.getItemId(),
- menuItem.getGroupId(),
- menuItem.getTitle(),
- menuItem.getIcon());
- }
-
- /**
- * Returns this object's hashcode.
- */
- @Override
- public int hashCode() {
- return Objects.hash(mItemId, mGroupId, mTitle, mIcon);
- }
-
- /**
- * Returns true if this object is the same as the specified object.
- */
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if (!(o instanceof LocalFloatingToolbarPopup.MenuItemRepr)) {
- return false;
- }
- final MenuItemRepr other = (MenuItemRepr) o;
- return mItemId == other.mItemId
- && mGroupId == other.mGroupId
- && TextUtils.equals(mTitle, other.mTitle)
- // Many Drawables (icons) do not implement equals(). Using equals() here instead
- // of reference comparisons in case a Drawable subclass implements equals().
- && Objects.equals(mIcon, other.mIcon);
- }
-
- /**
- * Returns true if the two menu item collections are the same based on MenuItemRepr.
- */
- public static boolean reprEquals(
- Collection<MenuItem> menuItems1, Collection<MenuItem> menuItems2) {
- if (menuItems1.size() != menuItems2.size()) {
- return false;
- }
-
- final Iterator<MenuItem> menuItems2Iter = menuItems2.iterator();
- for (MenuItem menuItem1 : menuItems1) {
- final MenuItem menuItem2 = menuItems2Iter.next();
- if (!MenuItemRepr.of(menuItem1).equals(
- MenuItemRepr.of(menuItem2))) {
- return false;
- }
- }
- return true;
- }
- }
-}
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 4cf17b78f489..199854818989 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -523,13 +523,14 @@ android_media_AudioSystem_dyn_policy_callback(int event, String8 regId, int val)
}
jclass clazz = env->FindClass(kClassPathName);
- const char* zechars = regId.string();
- jstring zestring = env->NewStringUTF(zechars);
+ const char *regIdString = regId.string();
+ jstring regIdJString = env->NewStringUTF(regIdString);
env->CallStaticVoidMethod(clazz, gAudioPolicyEventHandlerMethods.postDynPolicyEventFromNative,
- event, zestring, val);
+ event, regIdJString, val);
- env->ReleaseStringUTFChars(zestring, zechars);
+ const char *regIdJChars = env->GetStringUTFChars(regIdJString, NULL);
+ env->ReleaseStringUTFChars(regIdJString, regIdJChars);
env->DeleteLocalRef(clazz);
}
diff --git a/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp b/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp
index bba1760bc45c..d4f6e1868695 100644
--- a/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp
+++ b/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp
@@ -44,6 +44,8 @@ static struct fabricated_overlay_internal_entry_offsets_t {
jfieldID stringData;
jfieldID binaryData;
jfieldID configuration;
+ jfieldID binaryDataOffset;
+ jfieldID binaryDataSize;
} gFabricatedOverlayInternalEntryOffsets;
static struct parcel_file_descriptor_offsets_t {
@@ -281,10 +283,17 @@ static void CreateFrroFile(JNIEnv* env, jclass /*clazz*/, jstring jsFrroFilePath
auto binary_data =
getNullableFileDescriptor(env, entry,
gFabricatedOverlayInternalEntryOffsets.binaryData);
+
+ const auto data_offset =
+ env->GetLongField(entry, gFabricatedOverlayInternalEntryOffsets.binaryDataOffset);
+ const auto data_size =
+ env->GetLongField(entry, gFabricatedOverlayInternalEntryOffsets.binaryDataSize);
entries_params.push_back(
FabricatedOverlayEntryParameters{resourceName.c_str(), (DataType)dataType,
(DataValue)data,
string_data.value_or(std::string()), binary_data,
+ static_cast<off64_t>(data_offset),
+ static_cast<size_t>(data_size),
configuration.value_or(std::string())});
ALOGV("resourceName = %s, dataType = 0x%08x, data = 0x%08x, dataString = %s,"
" binaryData = %d, configuration = %s",
@@ -440,6 +449,12 @@ int register_com_android_internal_content_om_OverlayManagerImpl(JNIEnv* env) {
gFabricatedOverlayInternalEntryOffsets.configuration =
GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject,
"configuration", "Ljava/lang/String;");
+ gFabricatedOverlayInternalEntryOffsets.binaryDataOffset =
+ GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject,
+ "binaryDataOffset", "J");
+ gFabricatedOverlayInternalEntryOffsets.binaryDataSize =
+ GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject,
+ "binaryDataSize", "J");
jclass parcelFileDescriptorClass =
android::FindClassOrDie(env, "android/os/ParcelFileDescriptor");
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 86cf80e8847c..67710f64e1e4 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -821,7 +821,6 @@
<protected-broadcast android:name="android.intent.action.PROFILE_REMOVED" />
<protected-broadcast android:name="com.android.internal.telephony.cat.SMS_SENT_ACTION" />
<protected-broadcast android:name="com.android.internal.telephony.cat.SMS_DELIVERY_ACTION" />
- <protected-broadcast android:name="com.android.internal.telephony.data.ACTION_RETRY" />
<protected-broadcast android:name="android.companion.virtual.action.VIRTUAL_DEVICE_REMOVED" />
<protected-broadcast android:name="com.android.internal.intent.action.FLASH_NOTIFICATION_START_PREVIEW" />
<protected-broadcast android:name="com.android.internal.intent.action.FLASH_NOTIFICATION_STOP_PREVIEW" />
diff --git a/core/res/res/values/config_device_idle.xml b/core/res/res/values/config_device_idle.xml
index 764dbbe5dc93..98a5ff9c4a79 100644
--- a/core/res/res/values/config_device_idle.xml
+++ b/core/res/res/values/config_device_idle.xml
@@ -120,7 +120,7 @@
<!-- Default for DeviceIdleController.Constants.USE_WINDOW_ALARMS -->
<bool name="device_idle_use_window_alarms">true</bool>
- <!-- Default for DeviceIdleController.Constants.USE_BODY_SENSOR -->
- <bool name="device_idle_use_body_sensor">false</bool>
+ <!-- Default for DeviceIdleController.Constants.USE_MODE_MANAGER -->
+ <bool name="device_idle_use_mode_manager">false</bool>
</resources>
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 18abe7073757..bda194add759 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -160,6 +160,7 @@
3 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_SMS}
4 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_VIDEO}
5 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_EMERGENCY}
+ 6 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_MMS}
Example of a config string: "10011:2,3"
The PLMNs not configured in this array will be ignored and will not be used for satellite
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a11eaa91b2a6..d828f33ca514 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1786,10 +1786,6 @@
<string name="biometric_dialog_default_title">Verify it\u2019s you</string>
<!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with a biometric (e.g. fingerprint or face). [CHAR LIMIT=70] -->
<string name="biometric_dialog_default_subtitle">Use your biometric to continue</string>
- <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with fingerprint. [CHAR LIMIT=70] -->
- <string name="biometric_dialog_fingerprint_subtitle">Use your fingerprint to continue</string>
- <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with face. [CHAR LIMIT=70] -->
- <string name="biometric_dialog_face_subtitle">Use your face to continue</string>
<!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with a biometric (e.g. fingerprint or face) or their screen lock credential (i.e. PIN, pattern, or password). [CHAR LIMIT=90] -->
<string name="biometric_or_screen_lock_dialog_default_subtitle">Use your biometric or screen lock to continue</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 5806e93d4a93..8a395f88cb63 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2585,8 +2585,6 @@
<java-symbol type="string" name="biometric_or_screen_lock_app_setting_name" />
<java-symbol type="string" name="biometric_dialog_default_title" />
<java-symbol type="string" name="biometric_dialog_default_subtitle" />
- <java-symbol type="string" name="biometric_dialog_face_subtitle" />
- <java-symbol type="string" name="biometric_dialog_fingerprint_subtitle" />
<java-symbol type="string" name="biometric_or_screen_lock_dialog_default_subtitle" />
<java-symbol type="string" name="biometric_error_hw_unavailable" />
<java-symbol type="string" name="biometric_error_user_canceled" />
@@ -4522,7 +4520,7 @@
<java-symbol type="integer" name="device_idle_notification_allowlist_duration_ms" />
<java-symbol type="bool" name="device_idle_wait_for_unlock" />
<java-symbol type="bool" name="device_idle_use_window_alarms" />
- <java-symbol type="bool" name="device_idle_use_body_sensor" />
+ <java-symbol type="bool" name="device_idle_use_mode_manager" />
<!-- Binder heavy hitter watcher configs -->
<java-symbol type="bool" name="config_defaultBinderHeavyHitterWatcherEnabled" />
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index c7aaeb0339bd..c14da299c6ef 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -91,7 +91,6 @@ android_test {
java_resources: [":ApkVerityTestCertDer"],
data: [
- ":BstatsTestApp",
":BinderDeathRecipientHelperApp1",
":BinderDeathRecipientHelperApp2",
":com.android.cts.helpers.aosp",
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 129de649a4b5..31755efb88ed 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -231,6 +231,28 @@
</intent-filter>
</activity>
+ <activity android:name="android.widget.HorizontalScrollViewActivity"
+ android:label="HorizontalScrollViewActivity"
+ android:screenOrientation="portrait"
+ android:exported="true"
+ android:theme="@android:style/Theme.Material.Light">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name="android.widget.ScrollViewActivity"
+ android:label="ScrollViewActivity"
+ android:screenOrientation="portrait"
+ android:exported="true"
+ android:theme="@android:style/Theme.Material.Light">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
<activity android:name="android.widget.DatePickerActivity"
android:label="DatePickerActivity"
android:screenOrientation="portrait"
diff --git a/core/tests/coretests/AndroidTest.xml b/core/tests/coretests/AndroidTest.xml
index 3e4c47b36ed9..05b309b2cd52 100644
--- a/core/tests/coretests/AndroidTest.xml
+++ b/core/tests/coretests/AndroidTest.xml
@@ -20,7 +20,6 @@
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="FrameworksCoreTests.apk" />
- <option name="test-file-name" value="BstatsTestApp.apk" />
<option name="test-file-name" value="BinderDeathRecipientHelperApp1.apk" />
<option name="test-file-name" value="BinderDeathRecipientHelperApp2.apk" />
</target_preparer>
diff --git a/core/tests/coretests/BstatsTestApp/OWNERS b/core/tests/coretests/BstatsTestApp/OWNERS
deleted file mode 100644
index 4068e2bc03b7..000000000000
--- a/core/tests/coretests/BstatsTestApp/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include /BATTERY_STATS_OWNERS
diff --git a/core/tests/coretests/res/layout/activity_horizontal_scroll_view.xml b/core/tests/coretests/res/layout/activity_horizontal_scroll_view.xml
new file mode 100644
index 000000000000..866e1a95c3f5
--- /dev/null
+++ b/core/tests/coretests/res/layout/activity_horizontal_scroll_view.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/horizontal_scroll_view">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <View
+ android:background="#F00"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#880"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#0F0"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#088"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#00F"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#808"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#F00"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#880"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#0F0"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#088"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#00F"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#808"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#F00"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#880"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#0F0"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#088"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#00F"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#808"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ </LinearLayout>
+</HorizontalScrollView>
diff --git a/core/tests/coretests/res/layout/activity_scroll_view.xml b/core/tests/coretests/res/layout/activity_scroll_view.xml
new file mode 100644
index 000000000000..61fabf8ee437
--- /dev/null
+++ b/core/tests/coretests/res/layout/activity_scroll_view.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/scroll_view">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <View
+ android:background="#F00"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#880"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#0F0"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#088"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#00F"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#808"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#F00"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#880"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#0F0"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#088"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#00F"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#808"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#F00"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#880"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#0F0"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#088"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#00F"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ <View
+ android:background="#808"
+ android:layout_width="100dp"
+ android:layout_height="100dp" />
+
+ </LinearLayout>
+</ScrollView>
diff --git a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
index 2c03fdc2ef0d..b0826ab77035 100644
--- a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
+++ b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
@@ -69,6 +69,24 @@ public class PerformanceHintManagerTest {
}
@Test
+ public void testCreateHintSession_noTids() {
+ assertThrows(NullPointerException.class, () -> {
+ mPerformanceHintManager.createHintSession(
+ null, DEFAULT_TARGET_NS);
+ });
+ assertThrows(IllegalArgumentException.class, () -> {
+ mPerformanceHintManager.createHintSession(
+ new int[]{}, DEFAULT_TARGET_NS);
+ });
+ }
+
+ @Test
+ public void testCreateHintSession_invalidTids() {
+ assertNull(mPerformanceHintManager.createHintSession(
+ new int[]{-1}, DEFAULT_TARGET_NS));
+ }
+
+ @Test
public void testGetPreferredUpdateRateNanos() {
if (createSession() != null) {
assertTrue(mPerformanceHintManager.getPreferredUpdateRateNanos() > 0);
diff --git a/core/tests/coretests/src/android/widget/HorizontalScrollViewActivity.java b/core/tests/coretests/src/android/widget/HorizontalScrollViewActivity.java
new file mode 100644
index 000000000000..21013545008c
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/HorizontalScrollViewActivity.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.frameworks.coretests.R;
+
+/**
+ * An activity for testing the TextView widget.
+ */
+public class HorizontalScrollViewActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_horizontal_scroll_view);
+ }
+}
diff --git a/core/tests/coretests/src/android/widget/HorizontalScrollViewFunctionalTest.java b/core/tests/coretests/src/android/widget/HorizontalScrollViewFunctionalTest.java
new file mode 100644
index 000000000000..86f26e59e370
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/HorizontalScrollViewFunctionalTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import static org.junit.Assert.assertEquals;
+
+import android.platform.test.annotations.Presubmit;
+import android.util.PollingCheck;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+@Presubmit
+public class HorizontalScrollViewFunctionalTest {
+ private HorizontalScrollViewActivity mActivity;
+ private HorizontalScrollView mHorizontalScrollView;
+ @Rule
+ public ActivityTestRule<HorizontalScrollViewActivity> mActivityRule = new ActivityTestRule<>(
+ HorizontalScrollViewActivity.class);
+
+ @Before
+ public void setUp() throws Exception {
+ mActivity = mActivityRule.getActivity();
+ mHorizontalScrollView = mActivity.findViewById(R.id.horizontal_scroll_view);
+ }
+
+ @Test
+ public void testScrollAfterFlingTop() {
+ mHorizontalScrollView.scrollTo(100, 0);
+ mHorizontalScrollView.fling(-10000);
+ PollingCheck.waitFor(() -> mHorizontalScrollView.mEdgeGlowLeft.getDistance() > 0);
+ PollingCheck.waitFor(() -> mHorizontalScrollView.mEdgeGlowLeft.getDistance() == 0f);
+ assertEquals(0, mHorizontalScrollView.getScrollX());
+ }
+
+ @Test
+ public void testScrollAfterFlingBottom() {
+ int childWidth = mHorizontalScrollView.getChildAt(0).getWidth();
+ int maxScroll = childWidth - mHorizontalScrollView.getWidth();
+ mHorizontalScrollView.scrollTo(maxScroll - 100, 0);
+ mHorizontalScrollView.fling(10000);
+ PollingCheck.waitFor(() -> mHorizontalScrollView.mEdgeGlowRight.getDistance() > 0);
+ PollingCheck.waitFor(() -> mHorizontalScrollView.mEdgeGlowRight.getDistance() == 0f);
+ assertEquals(maxScroll, mHorizontalScrollView.getScrollX());
+ }
+}
+
diff --git a/core/java/android/view/selectiontoolbar/ShowInfo.aidl b/core/tests/coretests/src/android/widget/ScrollViewActivity.java
index dce9c15dce3e..899d63163aa4 100644
--- a/core/java/android/view/selectiontoolbar/ShowInfo.aidl
+++ b/core/tests/coretests/src/android/widget/ScrollViewActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,9 +14,21 @@
* limitations under the License.
*/
-package android.view.selectiontoolbar;
+package android.widget;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.frameworks.coretests.R;
/**
- * @hide
+ * An activity for testing the TextView widget.
*/
-parcelable ShowInfo;
+public class ScrollViewActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_scroll_view);
+ }
+}
diff --git a/core/tests/coretests/src/android/widget/ScrollViewFunctionalTest.java b/core/tests/coretests/src/android/widget/ScrollViewFunctionalTest.java
new file mode 100644
index 000000000000..a49bb6af13d2
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/ScrollViewFunctionalTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import static org.junit.Assert.assertEquals;
+
+import android.platform.test.annotations.Presubmit;
+import android.util.PollingCheck;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+@Presubmit
+public class ScrollViewFunctionalTest {
+ private ScrollViewActivity mActivity;
+ private ScrollView mScrollView;
+ @Rule
+ public ActivityTestRule<ScrollViewActivity> mActivityRule = new ActivityTestRule<>(
+ ScrollViewActivity.class);
+
+ @Before
+ public void setUp() throws Exception {
+ mActivity = mActivityRule.getActivity();
+ mScrollView = mActivity.findViewById(R.id.scroll_view);
+ }
+
+ @Test
+ public void testScrollAfterFlingTop() {
+ mScrollView.scrollTo(0, 100);
+ mScrollView.fling(-10000);
+ PollingCheck.waitFor(() -> mScrollView.mEdgeGlowTop.getDistance() > 0);
+ PollingCheck.waitFor(() -> mScrollView.mEdgeGlowTop.getDistance() == 0f);
+ assertEquals(0, mScrollView.getScrollY());
+ }
+
+ @Test
+ public void testScrollAfterFlingBottom() {
+ int childHeight = mScrollView.getChildAt(0).getHeight();
+ int maxScroll = childHeight - mScrollView.getHeight();
+ mScrollView.scrollTo(0, maxScroll - 100);
+ mScrollView.fling(10000);
+ PollingCheck.waitFor(() -> mScrollView.mEdgeGlowBottom.getDistance() > 0);
+ PollingCheck.waitFor(() -> mScrollView.mEdgeGlowBottom.getDistance() == 0f);
+ assertEquals(maxScroll, mScrollView.getScrollY());
+ }
+}
+
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index a6e74d0d6b94..68c0693fb23a 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -23,12 +23,12 @@ import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.atLeast;
-import static org.mockito.Mockito.atMost;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -254,18 +254,15 @@ public class WindowOnBackInvokedDispatcherTest {
callbackInfo1.getCallback().onBackStarted(mBackEvent);
waitForIdle();
- verify(mCallback1).onBackStarted(any(BackEvent.class));
- verifyZeroInteractions(mCallback2);
+ verify(mCallback1, times(1)).onBackStarted(any(BackEvent.class));
+ verify(mCallback2, never()).onBackStarted(any(BackEvent.class));
+ clearInvocations(mCallback1);
callbackInfo2.getCallback().onBackStarted(mBackEvent);
waitForIdle();
- verify(mCallback2).onBackStarted(any(BackEvent.class));
-
- // Calls sequence: BackProgressAnimator.onBackStarted() -> BackProgressAnimator.reset() ->
- // Spring.animateToFinalPosition(0). This causes a progress event to be fired.
- verify(mCallback1, atMost(1)).onBackProgressed(any(BackEvent.class));
- verifyNoMoreInteractions(mCallback1);
+ verify(mCallback1, never()).onBackStarted(any(BackEvent.class));
+ verify(mCallback2, times(1)).onBackStarted(any(BackEvent.class));
}
@Test
diff --git a/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java b/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java
index 7bd6f05d3775..a21c91782214 100644
--- a/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java
+++ b/core/tests/coretests/src/android/window/WindowTokenClientControllerTest.java
@@ -58,8 +58,6 @@ public class WindowTokenClientControllerTest {
@Mock
private WindowTokenClient mWindowTokenClient;
@Mock
- private IBinder mClientToken;
- @Mock
private IBinder mWindowToken;
// Can't mock final class.
private final Configuration mConfiguration = new Configuration();
@@ -70,7 +68,6 @@ public class WindowTokenClientControllerTest {
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- doReturn(mClientToken).when(mWindowTokenClient).asBinder();
mController = spy(WindowTokenClientController.createInstanceForTesting());
doReturn(mWindowManagerService).when(mController).getWindowManagerService();
mWindowContextInfo = new WindowContextInfo(mConfiguration, DEFAULT_DISPLAY);
@@ -205,7 +202,7 @@ public class WindowTokenClientControllerTest {
.attachWindowContextToWindowToken(any(), any(), any());
// No invoke if not attached.
- mController.onWindowContextInfoChanged(mClientToken, mWindowContextInfo);
+ mController.onWindowContextInfoChanged(mWindowTokenClient, mWindowContextInfo);
verify(mWindowTokenClient, never()).onConfigurationChanged(any(), anyInt());
@@ -216,7 +213,7 @@ public class WindowTokenClientControllerTest {
// Invoke onConfigurationChanged when onWindowContextInfoChanged
mController.onWindowContextInfoChanged(
- mClientToken, new WindowContextInfo(mConfiguration, DEFAULT_DISPLAY + 1));
+ mWindowTokenClient, new WindowContextInfo(mConfiguration, DEFAULT_DISPLAY + 1));
verify(mWindowTokenClient).onConfigurationChanged(mConfiguration, DEFAULT_DISPLAY + 1);
}
@@ -227,7 +224,7 @@ public class WindowTokenClientControllerTest {
.attachWindowContextToWindowToken(any(), any(), any());
// No invoke if not attached.
- mController.onWindowContextWindowRemoved(mClientToken);
+ mController.onWindowContextWindowRemoved(mWindowTokenClient);
verify(mWindowTokenClient, never()).onWindowTokenRemoved();
@@ -237,7 +234,7 @@ public class WindowTokenClientControllerTest {
verify(mWindowTokenClient, never()).onWindowTokenRemoved();
// Invoke onWindowTokenRemoved when onWindowContextWindowRemoved
- mController.onWindowContextWindowRemoved(mClientToken);
+ mController.onWindowContextWindowRemoved(mWindowTokenClient);
verify(mWindowTokenClient).onWindowTokenRemoved();
}
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index 2de1230cf706..cd5ec851e9eb 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -27,9 +27,7 @@ import static com.android.internal.accessibility.AccessibilityShortcutController
import static com.android.internal.accessibility.AccessibilityShortcutController.ONE_HANDED_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_COMPONENT_NAME;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.AdditionalMatchers.aryEq;
@@ -68,7 +66,6 @@ import android.provider.Settings;
import android.speech.tts.TextToSpeech;
import android.speech.tts.Voice;
import android.test.mock.MockContentResolver;
-import android.text.TextUtils;
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
@@ -76,7 +73,7 @@ import android.view.accessibility.IAccessibilityManager;
import android.widget.Toast;
import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.internal.R;
import com.android.internal.accessibility.AccessibilityShortcutController.FrameworkObjectProvider;
@@ -232,7 +229,7 @@ public class AccessibilityShortcutControllerTest {
throws Exception {
configureNoShortcutService();
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
- assertFalse(getController().isAccessibilityShortcutAvailable(false));
+ assertThat(getController().isAccessibilityShortcutAvailable(false)).isFalse();
}
@Test
@@ -240,7 +237,7 @@ public class AccessibilityShortcutControllerTest {
throws Exception {
configureValidShortcutService();
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
- assertTrue(getController().isAccessibilityShortcutAvailable(false));
+ assertThat(getController().isAccessibilityShortcutAvailable(false)).isTrue();
}
@Test
@@ -248,7 +245,7 @@ public class AccessibilityShortcutControllerTest {
throws Exception {
configureValidShortcutService();
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
- assertFalse(getController().isAccessibilityShortcutAvailable(true));
+ assertThat(getController().isAccessibilityShortcutAvailable(true)).isFalse();
}
@Test
@@ -256,7 +253,7 @@ public class AccessibilityShortcutControllerTest {
throws Exception {
configureValidShortcutService();
configureShortcutEnabled(ENABLED_INCLUDING_LOCK_SCREEN);
- assertTrue(getController().isAccessibilityShortcutAvailable(true));
+ assertThat(getController().isAccessibilityShortcutAvailable(true)).isTrue();
}
@Test
@@ -267,10 +264,14 @@ public class AccessibilityShortcutControllerTest {
configureShortcutEnabled(ENABLED_INCLUDING_LOCK_SCREEN);
Settings.Secure.putString(
mContentResolver, ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, null);
- Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
- assertFalse(getController().isAccessibilityShortcutAvailable(true));
- Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1);
- assertTrue(getController().isAccessibilityShortcutAvailable(true));
+ Settings.Secure.putInt(
+ mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.NOT_SHOWN);
+ assertThat(getController().isAccessibilityShortcutAvailable(true)).isFalse();
+ Settings.Secure.putInt(
+ mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.SHOWN);
+ assertThat(getController().isAccessibilityShortcutAvailable(true)).isTrue();
}
@Test
@@ -281,7 +282,9 @@ public class AccessibilityShortcutControllerTest {
AccessibilityShortcutController accessibilityShortcutController = getController();
configureNoShortcutService();
accessibilityShortcutController.onSettingsChanged();
- assertFalse(accessibilityShortcutController.isAccessibilityShortcutAvailable(false));
+ assertThat(
+ accessibilityShortcutController.isAccessibilityShortcutAvailable(false)
+ ).isFalse();
}
@Test
@@ -292,7 +295,9 @@ public class AccessibilityShortcutControllerTest {
AccessibilityShortcutController accessibilityShortcutController = getController();
configureValidShortcutService();
accessibilityShortcutController.onSettingsChanged();
- assertTrue(accessibilityShortcutController.isAccessibilityShortcutAvailable(false));
+ assertThat(
+ accessibilityShortcutController.isAccessibilityShortcutAvailable(false)
+ ).isTrue();
}
@Test
@@ -302,7 +307,9 @@ public class AccessibilityShortcutControllerTest {
AccessibilityShortcutController accessibilityShortcutController = getController();
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
accessibilityShortcutController.onSettingsChanged();
- assertTrue(accessibilityShortcutController.isAccessibilityShortcutAvailable(false));
+ assertThat(
+ accessibilityShortcutController.isAccessibilityShortcutAvailable(false)
+ ).isTrue();
}
@Test
@@ -313,7 +320,9 @@ public class AccessibilityShortcutControllerTest {
AccessibilityShortcutController accessibilityShortcutController = getController();
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
accessibilityShortcutController.onSettingsChanged();
- assertFalse(accessibilityShortcutController.isAccessibilityShortcutAvailable(true));
+ assertThat(
+ accessibilityShortcutController.isAccessibilityShortcutAvailable(true)
+ ).isFalse();
}
@Test
@@ -324,7 +333,9 @@ public class AccessibilityShortcutControllerTest {
AccessibilityShortcutController accessibilityShortcutController = getController();
configureShortcutEnabled(ENABLED_INCLUDING_LOCK_SCREEN);
accessibilityShortcutController.onSettingsChanged();
- assertTrue(accessibilityShortcutController.isAccessibilityShortcutAvailable(true));
+ assertThat(
+ accessibilityShortcutController.isAccessibilityShortcutAvailable(true)
+ ).isTrue();
}
@Test
@@ -341,11 +352,15 @@ public class AccessibilityShortcutControllerTest {
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
configureValidShortcutService();
AccessibilityShortcutController accessibilityShortcutController = getController();
- Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+ Settings.Secure.putInt(
+ mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.NOT_SHOWN);
accessibilityShortcutController.performAccessibilityShortcut();
- assertEquals(1, Settings.Secure.getInt(
- mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0));
+ assertThat(Settings.Secure.getInt(
+ mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.NOT_SHOWN)).isEqualTo(
+ AccessibilityShortcutController.DialogStatus.SHOWN);
verify(mResources).getString(
R.string.accessibility_shortcut_single_service_warning_title, PACKAGE_NAME_STRING);
verify(mAlertDialog).show();
@@ -357,11 +372,12 @@ public class AccessibilityShortcutControllerTest {
@Test
public void testOnAccessibilityShortcut_withDialogShowing_callsServer()
- throws Exception {
+ throws Exception {
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
configureValidShortcutService();
AccessibilityShortcutController accessibilityShortcutController = getController();
- Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+ Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.NOT_SHOWN);
accessibilityShortcutController.performAccessibilityShortcut();
accessibilityShortcutController.performAccessibilityShortcut();
verify(mToast).show();
@@ -374,11 +390,12 @@ public class AccessibilityShortcutControllerTest {
@Test
public void testOnAccessibilityShortcut_ifCanceledFirstTime_showsWarningDialog()
- throws Exception {
+ throws Exception {
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
configureValidShortcutService();
AccessibilityShortcutController accessibilityShortcutController = getController();
- Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+ Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.NOT_SHOWN);
accessibilityShortcutController.performAccessibilityShortcut();
ArgumentCaptor<AlertDialog.OnCancelListener> cancelListenerCaptor =
ArgumentCaptor.forClass(AlertDialog.OnCancelListener.class);
@@ -394,49 +411,98 @@ public class AccessibilityShortcutControllerTest {
public void testClickingDisableButtonInDialog_shouldClearShortcutId() throws Exception {
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
configureValidShortcutService();
- Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+ Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.NOT_SHOWN);
getController().performAccessibilityShortcut();
ArgumentCaptor<DialogInterface.OnClickListener> captor =
ArgumentCaptor.forClass(DialogInterface.OnClickListener.class);
verify(mAlertDialogBuilder).setPositiveButton(eq(R.string.accessibility_shortcut_off),
captor.capture());
- // Call the button callback, if one exists
- if (captor.getValue() != null) {
- captor.getValue().onClick(null, 0);
- }
- assertTrue(TextUtils.isEmpty(
- Settings.Secure.getString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE)));
- assertEquals(0, Settings.Secure.getInt(
- mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN));
+ captor.getValue().onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+ assertThat(
+ Settings.Secure.getString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE)
+ ).isEmpty();
+ assertThat(Settings.Secure.getInt(
+ mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN)).isEqualTo(
+ AccessibilityShortcutController.DialogStatus.NOT_SHOWN);
}
@Test
public void testClickingTurnOnButtonInDialog_shouldLeaveShortcutReady() throws Exception {
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
configureValidShortcutService();
- Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+ Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.NOT_SHOWN);
getController().performAccessibilityShortcut();
ArgumentCaptor<DialogInterface.OnClickListener> captor =
- ArgumentCaptor.forClass(DialogInterface.OnClickListener.class);
+ ArgumentCaptor.forClass(DialogInterface.OnClickListener.class);
verify(mAlertDialogBuilder).setNegativeButton(eq(R.string.accessibility_shortcut_on),
captor.capture());
- // Call the button callback, if one exists
- if (captor.getValue() != null) {
- captor.getValue().onClick(null, 0);
- }
- assertEquals(SERVICE_NAME_STRING,
- Settings.Secure.getString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE));
- assertEquals(1, Settings.Secure.getInt(
- mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN));
+ captor.getValue().onClick(null, DialogInterface.BUTTON_NEGATIVE);
+
+ assertThat(
+ Settings.Secure.getString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE)
+ ).isEqualTo(SERVICE_NAME_STRING);
+ assertThat(Settings.Secure.getInt(
+ mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN)).isEqualTo(
+ AccessibilityShortcutController.DialogStatus.SHOWN);
+ }
+
+ @Test
+ public void testTurnOnDefaultA11yServiceInDialog_defaultServiceShortcutTurnsOn()
+ throws Exception {
+ configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+ configureDefaultAccessibilityService();
+ Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.NOT_SHOWN);
+ getController().performAccessibilityShortcut();
+
+ ArgumentCaptor<DialogInterface.OnClickListener> captor =
+ ArgumentCaptor.forClass(DialogInterface.OnClickListener.class);
+ verify(mAlertDialogBuilder).setNegativeButton(eq(R.string.accessibility_shortcut_on),
+ captor.capture());
+ captor.getValue().onClick(null, DialogInterface.BUTTON_NEGATIVE);
+
+ assertThat(
+ Settings.Secure.getString(mContentResolver,
+ ACCESSIBILITY_SHORTCUT_TARGET_SERVICE)).isEqualTo(SERVICE_NAME_STRING);
+ assertThat(Settings.Secure.getInt(
+ mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN)).isEqualTo(
+ AccessibilityShortcutController.DialogStatus.SHOWN);
+ }
+
+ @Test
+ public void testTurnOffDefaultA11yServiceInDialog_defaultServiceShortcutTurnsOff()
+ throws Exception {
+ configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+ configureDefaultAccessibilityService();
+ Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.NOT_SHOWN);
+ getController().performAccessibilityShortcut();
+
+ ArgumentCaptor<DialogInterface.OnClickListener> captor =
+ ArgumentCaptor.forClass(DialogInterface.OnClickListener.class);
+ verify(mAlertDialogBuilder).setPositiveButton(eq(R.string.accessibility_shortcut_off),
+ captor.capture());
+ captor.getValue().onClick(null, DialogInterface.BUTTON_POSITIVE);
+
+ assertThat(
+ Settings.Secure.getString(mContentResolver,
+ ACCESSIBILITY_SHORTCUT_TARGET_SERVICE)).isEmpty();
+ assertThat(Settings.Secure.getInt(
+ mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN)).isEqualTo(
+ AccessibilityShortcutController.DialogStatus.NOT_SHOWN);
}
@Test
public void testOnAccessibilityShortcut_afterDialogShown_shouldCallServer() throws Exception {
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
configureValidShortcutService();
- Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1);
+ Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.SHOWN);
getController().performAccessibilityShortcut();
verifyZeroInteractions(mAlertDialogBuilder, mAlertDialog);
@@ -464,10 +530,10 @@ public class AccessibilityShortcutControllerTest {
frameworkFeatureMap =
AccessibilityShortcutController.getFrameworkShortcutFeaturesMap();
- assertTrue(frameworkFeatureMap.containsKey(COLOR_INVERSION_COMPONENT_NAME));
- assertTrue(frameworkFeatureMap.containsKey(DALTONIZER_COMPONENT_NAME));
- assertTrue(frameworkFeatureMap.containsKey(REDUCE_BRIGHT_COLORS_COMPONENT_NAME));
- assertTrue(frameworkFeatureMap.containsKey(ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME));
+ assertThat(frameworkFeatureMap).containsKey(COLOR_INVERSION_COMPONENT_NAME);
+ assertThat(frameworkFeatureMap).containsKey(DALTONIZER_COMPONENT_NAME);
+ assertThat(frameworkFeatureMap).containsKey(REDUCE_BRIGHT_COLORS_COMPONENT_NAME);
+ assertThat(frameworkFeatureMap).containsKey(ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME);
}
@Test
@@ -478,7 +544,7 @@ public class AccessibilityShortcutControllerTest {
frameworkFeatureMap =
AccessibilityShortcutController.getFrameworkShortcutFeaturesMap();
- assertTrue(frameworkFeatureMap.containsKey(ONE_HANDED_COMPONENT_NAME));
+ assertThat(frameworkFeatureMap).containsKey(ONE_HANDED_COMPONENT_NAME);
}
@Test
@@ -489,7 +555,7 @@ public class AccessibilityShortcutControllerTest {
frameworkFeatureMap =
AccessibilityShortcutController.getFrameworkShortcutFeaturesMap();
- assertFalse(frameworkFeatureMap.containsKey(ONE_HANDED_COMPONENT_NAME));
+ assertThat(frameworkFeatureMap).doesNotContainKey(ONE_HANDED_COMPONENT_NAME);
}
@Test
@@ -498,7 +564,8 @@ public class AccessibilityShortcutControllerTest {
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
configureValidShortcutService();
when(mServiceInfo.loadSummary(any())).thenReturn(null);
- Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1);
+ Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.SHOWN);
getController().performAccessibilityShortcut();
verify(mAccessibilityManagerService).performAccessibilityShortcut(null);
}
@@ -508,7 +575,8 @@ public class AccessibilityShortcutControllerTest {
throws Exception {
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
configureFirstFrameworkFeature();
- Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1);
+ Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.SHOWN);
getController().performAccessibilityShortcut();
verifyZeroInteractions(mToast);
@@ -523,7 +591,8 @@ public class AccessibilityShortcutControllerTest {
configureApplicationTargetSdkVersion(Build.VERSION_CODES.R);
configureRequestAccessibilityButton();
configureEnabledService();
- Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1);
+ Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.SHOWN);
getController().performAccessibilityShortcut();
verifyZeroInteractions(mToast);
@@ -538,7 +607,8 @@ public class AccessibilityShortcutControllerTest {
configureTtsSpokenPromptEnabled();
configureHandlerCallbackInvocation();
AccessibilityShortcutController accessibilityShortcutController = getController();
- Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+ Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.NOT_SHOWN);
accessibilityShortcutController.performAccessibilityShortcut();
verify(mAlertDialog).show();
@@ -563,7 +633,8 @@ public class AccessibilityShortcutControllerTest {
configureTtsSpokenPromptEnabled();
configureHandlerCallbackInvocation();
AccessibilityShortcutController accessibilityShortcutController = getController();
- Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+ Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.NOT_SHOWN);
accessibilityShortcutController.performAccessibilityShortcut();
verify(mAlertDialog).show();
@@ -583,7 +654,8 @@ public class AccessibilityShortcutControllerTest {
configureTtsSpokenPromptEnabled();
configureHandlerCallbackInvocation();
AccessibilityShortcutController accessibilityShortcutController = getController();
- Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+ Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ AccessibilityShortcutController.DialogStatus.NOT_SHOWN);
Set<String> features = new HashSet<>();
features.add(TextToSpeech.Engine.KEY_FEATURE_NOT_INSTALLED);
doReturn(features, Collections.emptySet()).when(mVoice).getFeatures();
@@ -682,4 +754,13 @@ public class AccessibilityShortcutControllerTest {
accessibilityShortcutController.mFrameworkObjectProvider = mFrameworkObjectProvider;
return accessibilityShortcutController;
}
+
+ private void configureDefaultAccessibilityService() throws Exception {
+ when(mAccessibilityManagerService
+ .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY))
+ .thenReturn(Collections.singletonList(SERVICE_NAME_STRING));
+
+ when(mResources.getString(R.string.config_defaultAccessibilityService)).thenReturn(
+ SERVICE_NAME_STRING);
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/content/OWNERS b/core/tests/coretests/src/com/android/internal/content/OWNERS
index dd9ede53239c..4bb83438b193 100644
--- a/core/tests/coretests/src/com/android/internal/content/OWNERS
+++ b/core/tests/coretests/src/com/android/internal/content/OWNERS
@@ -1,4 +1,2 @@
-per-file PackageMonitorTest.java = file:/core/java/android/content/pm/OWNERS
-
per-file Overlay* = file:/core/java/android/content/res/OWNERS
diff --git a/core/tests/packagemonitortests/Android.bp b/core/tests/packagemonitortests/Android.bp
new file mode 100644
index 000000000000..453b476edbc0
--- /dev/null
+++ b/core/tests/packagemonitortests/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "FrameworksCorePackageMonitorTests",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "androidx.test.runner",
+ "compatibility-device-util-axt",
+ "frameworks-base-testutils",
+ "mockito-target-minus-junit4",
+ "truth-prebuilt",
+ ],
+ libs: ["android.test.runner"],
+ platform_apis: true,
+ certificate: "platform",
+ test_suites: ["device-tests"],
+ data: [
+ ":TestVisibilityApp",
+ ],
+}
diff --git a/core/tests/packagemonitortests/AndroidManifest.xml b/core/tests/packagemonitortests/AndroidManifest.xml
new file mode 100644
index 000000000000..500a3e192077
--- /dev/null
+++ b/core/tests/packagemonitortests/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.packagemonitor">
+
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.packagemonitor"
+ android:label="Frameworks PackageMonitor Core Tests" />
+</manifest>
diff --git a/core/tests/packagemonitortests/AndroidTest.xml b/core/tests/packagemonitortests/AndroidTest.xml
new file mode 100644
index 000000000000..898dc1877b4b
--- /dev/null
+++ b/core/tests/packagemonitortests/AndroidTest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<configuration description="Runs Frameworks Core Tests.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="FrameworksCorePackageMonitorTests.apk" />
+ </target_preparer>
+
+ <!-- Create place to store apks -->
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="mkdir -p /data/local/tmp/contenttests" />
+ <option name="teardown-command" value="rm -rf /data/local/tmp/contenttests"/>
+ </target_preparer>
+ <!-- Load additional APKs onto device -->
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="push" value="TestVisibilityApp.apk->/data/local/tmp/contenttests/TestVisibilityApp.apk" />
+ <option name="cleanup" value="true" />
+ </target_preparer>
+
+ <option name="test-tag" value="FrameworksCorePackageMonitorTests" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.frameworks.packagemonitor" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
diff --git a/core/tests/packagemonitortests/OWNERS b/core/tests/packagemonitortests/OWNERS
new file mode 100644
index 000000000000..d825dfd7cf00
--- /dev/null
+++ b/core/tests/packagemonitortests/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/core/tests/coretests/src/com/android/internal/content/PackageMonitorTest.java b/core/tests/packagemonitortests/src/com/android/internal/content/PackageMonitorTest.java
index 7ccbf1d25674..e082c25fa499 100644
--- a/core/tests/coretests/src/com/android/internal/content/PackageMonitorTest.java
+++ b/core/tests/packagemonitortests/src/com/android/internal/content/PackageMonitorTest.java
@@ -44,10 +44,10 @@ import org.mockito.MockitoAnnotations;
*/
@RunWith(AndroidJUnit4.class)
public class PackageMonitorTest {
-
private static final String FAKE_PACKAGE_NAME = "com.android.internal.content.fakeapp";
private static final int FAKE_PACKAGE_UID = 123;
private static final int FAKE_USER_ID = 0;
+ private static final int WAIT_CALLBACK_CALLED_IN_MS = 300;
@Mock
Context mMockContext;
diff --git a/core/tests/packagemonitortests/src/com/android/internal/content/PackageMonitorVisibilityTest.java b/core/tests/packagemonitortests/src/com/android/internal/content/PackageMonitorVisibilityTest.java
new file mode 100644
index 000000000000..a310edceb3b3
--- /dev/null
+++ b/core/tests/packagemonitortests/src/com/android/internal/content/PackageMonitorVisibilityTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.content;
+
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A test to verify PackageMonitor implementation respects the app visibility.
+ */
+@RunWith(AndroidJUnit4.class)
+public class PackageMonitorVisibilityTest {
+ private static final String TEST_DATA_PATH = "/data/local/tmp/contenttests/";
+ private static final String TEAT_APK_PATH =
+ TEST_DATA_PATH + "TestVisibilityApp.apk";
+ private static final String TEAT_APK_PACKAGE_NAME = "com.example.android.testvisibilityapp";
+ private static final int WAIT_CALLBACK_CALLED_IN_SECONDS = 1;
+ @Test
+ public void testPackageMonitorPackageVisible() throws Exception {
+ TestVisibilityPackageMonitor testPackageMonitor = new TestVisibilityPackageMonitor();
+
+ try {
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ testPackageMonitor.register(context, UserHandle.ALL,
+ new Handler(Looper.getMainLooper()));
+
+ installTestPackage(true /* forceQueryable */);
+ boolean result = testPackageMonitor.mCallbackCountDownLatch.await(
+ WAIT_CALLBACK_CALLED_IN_SECONDS, TimeUnit.SECONDS);
+
+ int expectedUid = context.getPackageManager().getPackageUid(TEAT_APK_PACKAGE_NAME,
+ PackageManager.PackageInfoFlags.of(0));
+ assertThat(result).isTrue();
+ assertThat(testPackageMonitor.mAddedPackageName).isEqualTo(TEAT_APK_PACKAGE_NAME);
+ assertThat(testPackageMonitor.mAddedPackageUid).isEqualTo(expectedUid);
+ } finally {
+ testPackageMonitor.unregister();
+ uninstallTestPackage();
+ }
+ }
+
+ @Test
+ public void testPackageMonitorPackageNotVisible() throws Exception {
+ TestVisibilityPackageMonitor testPackageMonitor = new TestVisibilityPackageMonitor();
+
+ try {
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ testPackageMonitor.register(context, UserHandle.ALL,
+ new Handler(Looper.getMainLooper()));
+
+ installTestPackage(false /* forceQueryable */);
+ boolean result = testPackageMonitor.mCallbackCountDownLatch.await(
+ WAIT_CALLBACK_CALLED_IN_SECONDS, TimeUnit.SECONDS);
+
+ assertThat(result).isFalse();
+ } finally {
+ testPackageMonitor.unregister();
+ uninstallTestPackage();
+ }
+ }
+
+ private static void installTestPackage(boolean forceQueryable) {
+ final StringBuilder cmd = new StringBuilder("pm install ");
+ if (forceQueryable) {
+ cmd.append("--force-queryable ");
+ }
+ cmd.append(TEAT_APK_PATH);
+ final String result = runShellCommand(cmd.toString());
+ assertThat(result.trim()).contains("Success");
+ }
+
+ private static void uninstallTestPackage() {
+ runShellCommand("pm uninstall " + TEAT_APK_PACKAGE_NAME);
+ }
+
+ private static class TestVisibilityPackageMonitor extends PackageMonitor {
+ String mAddedPackageName;
+ int mAddedPackageUid;
+ CountDownLatch mCallbackCountDownLatch = new CountDownLatch(1);
+
+ @Override
+ public void onPackageAdded(String packageName, int uid) {
+ if (!TEAT_APK_PACKAGE_NAME.equals(packageName)) {
+ return;
+ }
+ mAddedPackageName = packageName;
+ mAddedPackageUid = uid;
+ mCallbackCountDownLatch.countDown();
+ }
+ }
+}
diff --git a/core/tests/packagemonitortests/testapp/TestVisibilityApp/Android.bp b/core/tests/packagemonitortests/testapp/TestVisibilityApp/Android.bp
new file mode 100644
index 000000000000..c0e98fcc595d
--- /dev/null
+++ b/core/tests/packagemonitortests/testapp/TestVisibilityApp/Android.bp
@@ -0,0 +1,27 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+ name: "TestVisibilityApp",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+ dex_preopt: {
+ enabled: false,
+ },
+ test_suites: ["device-tests"],
+}
diff --git a/core/tests/packagemonitortests/testapp/TestVisibilityApp/AndroidManifest.xml b/core/tests/packagemonitortests/testapp/TestVisibilityApp/AndroidManifest.xml
new file mode 100644
index 000000000000..0ba5058be979
--- /dev/null
+++ b/core/tests/packagemonitortests/testapp/TestVisibilityApp/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.testvisibilityapp">
+ <application android:label="testvisibilityapp">
+ <activity android:name="DummyActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/core/tests/packagemonitortests/testapp/TestVisibilityApp/res/layout/dummy_activity.xml b/core/tests/packagemonitortests/testapp/TestVisibilityApp/res/layout/dummy_activity.xml
new file mode 100644
index 000000000000..9887dc7117d1
--- /dev/null
+++ b/core/tests/packagemonitortests/testapp/TestVisibilityApp/res/layout/dummy_activity.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<EditText xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/text"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:textSize="18sp"
+ android:autoText="true"
+ android:capitalize="sentences"
+ android:text="@string/activity_text_text" />
+
diff --git a/core/tests/packagemonitortests/testapp/TestVisibilityApp/res/values/strings.xml b/core/tests/packagemonitortests/testapp/TestVisibilityApp/res/values/strings.xml
new file mode 100644
index 000000000000..5771bd50cfe7
--- /dev/null
+++ b/core/tests/packagemonitortests/testapp/TestVisibilityApp/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+
+ <string name="activity_text_text">Hello</string>
+
+</resources>
diff --git a/core/tests/packagemonitortests/testapp/TestVisibilityApp/src/com/example/android/testvisibilityapp/DummyActivity.java b/core/tests/packagemonitortests/testapp/TestVisibilityApp/src/com/example/android/testvisibilityapp/DummyActivity.java
new file mode 100644
index 000000000000..e74454e938b9
--- /dev/null
+++ b/core/tests/packagemonitortests/testapp/TestVisibilityApp/src/com/example/android/testvisibilityapp/DummyActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.testvisibilityapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+public class DummyActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ View view = getLayoutInflater().inflate(R.layout.dummy_activity, null);
+ setContentView(view);
+ }
+}
+
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index c6a9033210e3..43683ffad432 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -87,6 +87,5 @@
<permission name="android.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS" />
<permission name="android.permission.READ_SEARCH_INDEXABLES" />
<permission name="android.permission.ACCESS_AMBIENT_CONTEXT_EVENT"/>
- <permission name="android.permission.QUERY_CLONED_APPS"/>
</privapp-permissions>
</permissions>
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 99bebb8b9812..a2319a53a659 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -199,6 +199,8 @@ public abstract class ColorSpace {
private static final float[] SRGB_PRIMARIES = { 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f };
private static final float[] NTSC_1953_PRIMARIES = { 0.67f, 0.33f, 0.21f, 0.71f, 0.14f, 0.08f };
+ private static final float[] DCI_P3_PRIMARIES =
+ { 0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f };
private static final float[] BT2020_PRIMARIES =
{ 0.708f, 0.292f, 0.170f, 0.797f, 0.131f, 0.046f };
/**
@@ -211,6 +213,9 @@ public abstract class ColorSpace {
private static final Rgb.TransferParameters SRGB_TRANSFER_PARAMETERS =
new Rgb.TransferParameters(1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4);
+ private static final Rgb.TransferParameters SMPTE_170M_TRANSFER_PARAMETERS =
+ new Rgb.TransferParameters(1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081, 1 / 0.45);
+
// HLG transfer with an SDR whitepoint of 203 nits
private static final Rgb.TransferParameters BT2020_HLG_TRANSFER_PARAMETERS =
new Rgb.TransferParameters(2.0, 2.0, 1 / 0.17883277, 0.28466892, 0.55991073,
@@ -1559,10 +1564,10 @@ public abstract class ColorSpace {
DataSpace.DATASPACE_SCRGB_LINEAR, Named.LINEAR_EXTENDED_SRGB.ordinal());
sNamedColorSpaces[Named.BT709.ordinal()] = new ColorSpace.Rgb(
"Rec. ITU-R BT.709-5",
- new float[] { 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f },
+ SRGB_PRIMARIES,
ILLUMINANT_D65,
null,
- new Rgb.TransferParameters(1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081, 1 / 0.45),
+ SMPTE_170M_TRANSFER_PARAMETERS,
Named.BT709.ordinal()
);
sDataToColorSpaces.put(DataSpace.DATASPACE_BT709, Named.BT709.ordinal());
@@ -1577,7 +1582,7 @@ public abstract class ColorSpace {
sDataToColorSpaces.put(DataSpace.DATASPACE_BT2020, Named.BT2020.ordinal());
sNamedColorSpaces[Named.DCI_P3.ordinal()] = new ColorSpace.Rgb(
"SMPTE RP 431-2-2007 DCI (P3)",
- new float[] { 0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f },
+ DCI_P3_PRIMARIES,
new float[] { 0.314f, 0.351f },
2.6,
0.0f, 1.0f,
@@ -1586,7 +1591,7 @@ public abstract class ColorSpace {
sDataToColorSpaces.put(DataSpace.DATASPACE_DCI_P3, Named.DCI_P3.ordinal());
sNamedColorSpaces[Named.DISPLAY_P3.ordinal()] = new ColorSpace.Rgb(
"Display P3",
- new float[] { 0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f },
+ DCI_P3_PRIMARIES,
ILLUMINANT_D65,
null,
SRGB_TRANSFER_PARAMETERS,
@@ -1598,7 +1603,7 @@ public abstract class ColorSpace {
NTSC_1953_PRIMARIES,
ILLUMINANT_C,
null,
- new Rgb.TransferParameters(1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081, 1 / 0.45),
+ SMPTE_170M_TRANSFER_PARAMETERS,
Named.NTSC_1953.ordinal()
);
sNamedColorSpaces[Named.SMPTE_C.ordinal()] = new ColorSpace.Rgb(
@@ -1606,7 +1611,7 @@ public abstract class ColorSpace {
new float[] { 0.630f, 0.340f, 0.310f, 0.595f, 0.155f, 0.070f },
ILLUMINANT_D65,
null,
- new Rgb.TransferParameters(1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081, 1 / 0.45),
+ SMPTE_170M_TRANSFER_PARAMETERS,
Named.SMPTE_C.ordinal()
);
sNamedColorSpaces[Named.ADOBE_RGB.ordinal()] = new ColorSpace.Rgb(
@@ -3057,7 +3062,7 @@ public abstract class ColorSpace {
* primaries for such a ColorSpace does not make sense, so we use a special
* set of primaries that are all 1s.</p>
*
- * @return A new non-null array of 2 floats
+ * @return A new non-null array of 6 floats
*
* @see #getPrimaries(float[])
*/
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 381e9d472f0f..08b7bb89d10c 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
@@ -25,6 +25,7 @@ import android.window.TaskFragmentParentInfo;
import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.window.extensions.core.util.function.Function;
/**
@@ -186,10 +187,21 @@ class SplitContainer {
return (mSplitRule instanceof SplitPlaceholderRule);
}
- @NonNull
- SplitInfo toSplitInfo() {
- return new SplitInfo(mPrimaryContainer.toActivityStack(),
- mSecondaryContainer.toActivityStack(), mCurrentSplitAttributes, mToken);
+ /**
+ * Returns the SplitInfo representing this container.
+ *
+ * @return the SplitInfo representing this container if the underlying TaskFragmentContainers
+ * are stable, or {@code null} if any TaskFragmentContainer is in an intermediate state.
+ */
+ @Nullable
+ SplitInfo toSplitInfoIfStable() {
+ final ActivityStack primaryActivityStack = mPrimaryContainer.toActivityStackIfStable();
+ final ActivityStack secondaryActivityStack = mSecondaryContainer.toActivityStackIfStable();
+ if (primaryActivityStack == null || secondaryActivityStack == null) {
+ return null;
+ }
+ return new SplitInfo(primaryActivityStack, secondaryActivityStack,
+ mCurrentSplitAttributes, mToken);
}
static boolean shouldFinishPrimaryWithSecondary(@NonNull SplitRule splitRule) {
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 f95f3ffb4df3..3d72963944c2 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -1908,8 +1908,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
if (mEmbeddingCallback == null || !readyToReportToClient()) {
return;
}
- final List<SplitInfo> currentSplitStates = getActiveSplitStates();
- if (mLastReportedSplitStates.equals(currentSplitStates)) {
+ final List<SplitInfo> currentSplitStates = getActiveSplitStatesIfStable();
+ if (currentSplitStates == null || mLastReportedSplitStates.equals(currentSplitStates)) {
return;
}
mLastReportedSplitStates.clear();
@@ -1919,13 +1919,21 @@ 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 all the containers are in
+ * a stable state, or {@code null} otherwise.
*/
@GuardedBy("mLock")
- @NonNull
- private List<SplitInfo> getActiveSplitStates() {
+ @Nullable
+ private List<SplitInfo> getActiveSplitStatesIfStable() {
final List<SplitInfo> splitStates = new ArrayList<>();
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
- mTaskContainers.valueAt(i).getSplitStates(splitStates);
+ final List<SplitInfo> taskSplitStates =
+ mTaskContainers.valueAt(i).getSplitStatesIfStable();
+ if (taskSplitStates == null) {
+ return null;
+ }
+ splitStates.addAll(taskSplitStates);
}
return splitStates;
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index 969e3ed5b9b6..fa1eb9e1d167 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -329,11 +329,23 @@ class TaskContainer {
}
}
- /** Adds the descriptors of split states in this Task to {@code outSplitStates}. */
- void getSplitStates(@NonNull List<SplitInfo> outSplitStates) {
+ /**
+ * Gets the descriptors of split states in this Task.
+ *
+ * @return a list of {@code SplitInfo} if all the SplitContainers are stable, or {@code null} if
+ * any SplitContainer is in an intermediate state.
+ */
+ @Nullable
+ List<SplitInfo> getSplitStatesIfStable() {
+ final List<SplitInfo> splitStates = new ArrayList<>();
for (SplitContainer container : mSplitContainers) {
- outSplitStates.add(container.toSplitInfo());
+ final SplitInfo splitInfo = container.toSplitInfoIfStable();
+ if (splitInfo == null) {
+ return null;
+ }
+ splitStates.add(splitInfo);
}
+ return splitStates;
}
/** A wrapper class which contains the information of {@link TaskContainer} */
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 61df335515b8..0a694b5c3b64 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -217,6 +217,30 @@ class TaskFragmentContainer {
/** List of non-finishing activities that belong to this container and live in this process. */
@NonNull
List<Activity> collectNonFinishingActivities() {
+ final List<Activity> activities = collectNonFinishingActivities(false /* checkIfStable */);
+ if (activities == null) {
+ throw new IllegalStateException(
+ "Result activities should never be null when checkIfstable is false.");
+ }
+ return activities;
+ }
+
+ /**
+ * Collects non-finishing activities that belong to this container and live in this process.
+ *
+ * @param checkIfStable if {@code true}, returns {@code null} when the container is in an
+ * intermediate state.
+ * @return List of non-finishing activities that belong to this container and live in this
+ * process, {@code null} if checkIfStable is {@code true} and the container is in an
+ * intermediate state.
+ */
+ @Nullable
+ List<Activity> collectNonFinishingActivities(boolean checkIfStable) {
+ if (checkIfStable
+ && (mInfo == null || mInfo.isEmpty() || !mPendingAppearedActivities.isEmpty())) {
+ return null;
+ }
+
final List<Activity> allActivities = new ArrayList<>();
if (mInfo != null) {
// Add activities reported from the server.
@@ -224,6 +248,15 @@ class TaskFragmentContainer {
final Activity activity = mController.getActivity(token);
if (activity != null && !activity.isFinishing()) {
allActivities.add(activity);
+ } else {
+ if (checkIfStable) {
+ // Return null except for a special case when the activity is started in
+ // background.
+ if (activity == null && !mTaskContainer.isVisible()) {
+ continue;
+ }
+ return null;
+ }
}
}
}
@@ -277,9 +310,19 @@ class TaskFragmentContainer {
return false;
}
- @NonNull
- ActivityStack toActivityStack() {
- return new ActivityStack(collectNonFinishingActivities(), isEmpty(), mToken);
+ /**
+ * Returns the ActivityStack representing this container.
+ *
+ * @return ActivityStack representing this container if it is in a stable state. {@code null} if
+ * in an intermediate state.
+ */
+ @Nullable
+ ActivityStack toActivityStackIfStable() {
+ final List<Activity> activities = collectNonFinishingActivities(true /* checkIfStable */);
+ if (activities == null) {
+ return null;
+ }
+ return new ActivityStack(activities, isEmpty(), mToken);
}
/** Adds the activity that will be reparented to this container. */
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 9af1fe916279..b504b0c0d138 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -1251,6 +1251,34 @@ public class SplitControllerTest {
}
@Test
+ public void testSplitInfoCallback_NotReportSplitIfUnstable() {
+ final Activity r0 = createMockActivity();
+ final Activity r1 = createMockActivity();
+ addSplitTaskFragments(r0, r1);
+
+ // Should report new SplitInfo list if stable.
+ mSplitController.updateCallbackIfNecessary();
+ assertEquals(1, mSplitInfos.size());
+
+ // Should not report new SplitInfo list if unstable, e.g. any Activity is finishing.
+ mSplitInfos.clear();
+ final Activity r2 = createMockActivity();
+ final Activity r3 = createMockActivity();
+ doReturn(true).when(r2).isFinishing();
+ addSplitTaskFragments(r2, r3);
+
+ mSplitController.updateCallbackIfNecessary();
+ assertTrue(mSplitInfos.isEmpty());
+
+ // Should report SplitInfo list if it becomes stable again.
+ mSplitInfos.clear();
+ doReturn(false).when(r2).isFinishing();
+
+ mSplitController.updateCallbackIfNecessary();
+ assertEquals(2, mSplitInfos.size());
+ }
+
+ @Test
public void testSplitInfoCallback_reportSplitInMultipleTasks() {
final int taskId0 = 1;
final int taskId1 = 2;
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
index 000c65a75c81..21889960a8b2 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
@@ -48,6 +48,8 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
+
/**
* Test class for {@link TaskContainer}.
*
@@ -165,4 +167,35 @@ public class TaskContainerTest {
doReturn(activity1).when(tf1).getTopNonFinishingActivity();
assertEquals(activity1, taskContainer.getTopNonFinishingActivity());
}
+
+ @Test
+ public void testGetSplitStatesIfStable() {
+ final TaskContainer taskContainer = createTestTaskContainer();
+
+ final SplitContainer splitContainer0 = mock(SplitContainer.class);
+ final SplitContainer splitContainer1 = mock(SplitContainer.class);
+ final SplitInfo splitInfo0 = mock(SplitInfo.class);
+ final SplitInfo splitInfo1 = mock(SplitInfo.class);
+ taskContainer.addSplitContainer(splitContainer0);
+ taskContainer.addSplitContainer(splitContainer1);
+
+ // When all the SplitContainers are stable, getSplitStatesIfStable() returns the list of
+ // SplitInfo representing the SplitContainers.
+ doReturn(splitInfo0).when(splitContainer0).toSplitInfoIfStable();
+ doReturn(splitInfo1).when(splitContainer1).toSplitInfoIfStable();
+
+ List<SplitInfo> splitInfoList = taskContainer.getSplitStatesIfStable();
+
+ assertEquals(2, splitInfoList.size());
+ assertEquals(splitInfo0, splitInfoList.get(0));
+ assertEquals(splitInfo1, splitInfoList.get(1));
+
+ // When any SplitContainer is in an intermediate state, getSplitStatesIfStable() returns
+ // null.
+ doReturn(null).when(splitContainer0).toSplitInfoIfStable();
+
+ splitInfoList = taskContainer.getSplitStatesIfStable();
+
+ assertNull(splitInfoList);
+ }
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
index 78b85e642c13..cc00a49604ee 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
@@ -321,6 +321,32 @@ public class TaskFragmentContainerTest {
}
@Test
+ public void testCollectNonFinishingActivities_checkIfStable() {
+ final TaskContainer taskContainer = createTestTaskContainer();
+ final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
+ mIntent, taskContainer, mController, null /* pairedPrimaryContainer */);
+
+ // In case mInfo is null, collectNonFinishingActivities(true) should return null.
+ List<Activity> activities =
+ container.collectNonFinishingActivities(true /* checkIfStable */);
+ assertNull(activities);
+
+ // collectNonFinishingActivities(true) should return proper value when the container is in a
+ // stable state.
+ final List<IBinder> runningActivities = Lists.newArrayList(mActivity.getActivityToken());
+ doReturn(runningActivities).when(mInfo).getActivities();
+ container.setInfo(mTransaction, mInfo);
+ activities = container.collectNonFinishingActivities(true /* checkIfStable */);
+ assertEquals(1, activities.size());
+
+ // In case any activity is finishing, collectNonFinishingActivities(true) should return
+ // null.
+ doReturn(true).when(mActivity).isFinishing();
+ activities = container.collectNonFinishingActivities(true /* checkIfStable */);
+ assertNull(activities);
+ }
+
+ @Test
public void testAddPendingActivity() {
final TaskContainer taskContainer = createTestTaskContainer();
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
index 57d374b2b8f5..06ce37148eaf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
@@ -186,6 +186,6 @@ public class ActivityEmbeddingController implements Transitions.TransitionHandle
if (callback == null) {
throw new IllegalStateException("No finish callback found");
}
- callback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ callback.onTransitionFinished(null /* wct */);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index ee6996d3d23d..2c100653dae0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -661,14 +661,26 @@ public class BubblePositioner {
final boolean startOnLeft =
mContext.getResources().getConfiguration().getLayoutDirection()
!= LAYOUT_DIRECTION_RTL;
- final float startingVerticalOffset = mContext.getResources().getDimensionPixelOffset(
- R.dimen.bubble_stack_starting_offset_y);
- // TODO: placement bug here because mPositionRect doesn't handle the overhanging edge
- return new BubbleStackView.RelativeStackPosition(
- startOnLeft,
- startingVerticalOffset / mPositionRect.height())
- .getAbsolutePositionInRegion(getAllowableStackPositionRegion(
- 1 /* default starts with 1 bubble */));
+ final RectF allowableStackPositionRegion = getAllowableStackPositionRegion(
+ 1 /* default starts with 1 bubble */);
+ if (isLargeScreen()) {
+ // We want the stack to be visually centered on the edge, so we need to base it
+ // of a rect that includes insets.
+ final float desiredY = mScreenRect.height() / 2f - (mBubbleSize / 2f);
+ final float offset = desiredY / mScreenRect.height();
+ return new BubbleStackView.RelativeStackPosition(
+ startOnLeft,
+ offset)
+ .getAbsolutePositionInRegion(allowableStackPositionRegion);
+ } else {
+ final float startingVerticalOffset = mContext.getResources().getDimensionPixelOffset(
+ R.dimen.bubble_stack_starting_offset_y);
+ // TODO: placement bug here because mPositionRect doesn't handle the overhanging edge
+ return new BubbleStackView.RelativeStackPosition(
+ startOnLeft,
+ startingVerticalOffset / mPositionRect.height())
+ .getAbsolutePositionInRegion(allowableStackPositionRegion);
+ }
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/LegacySizeSpecSource.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/LegacySizeSpecSource.kt
new file mode 100644
index 000000000000..fd000ee1d24f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/LegacySizeSpecSource.kt
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common.pip
+
+import android.content.Context
+import android.content.res.Resources
+import android.graphics.PointF
+import android.util.Size
+import com.android.wm.shell.R
+import com.android.wm.shell.pip.PipDisplayLayoutState
+
+class LegacySizeSpecSource(
+ private val context: Context,
+ private val pipDisplayLayoutState: PipDisplayLayoutState
+) : SizeSpecSource {
+
+ private var mDefaultMinSize = 0
+ /** The absolute minimum an overridden size's edge can be */
+ private var mOverridableMinSize = 0
+ /** The preferred minimum (and default minimum) size specified by apps. */
+ private var mOverrideMinSize: Size? = null
+
+ private var mDefaultSizePercent = 0f
+ private var mMinimumSizePercent = 0f
+ private var mMaxAspectRatioForMinSize = 0f
+ private var mMinAspectRatioForMinSize = 0f
+
+ init {
+ reloadResources()
+ }
+
+ private fun reloadResources() {
+ val res: Resources = context.getResources()
+
+ mDefaultMinSize = res.getDimensionPixelSize(
+ R.dimen.default_minimal_size_pip_resizable_task)
+ mOverridableMinSize = res.getDimensionPixelSize(
+ R.dimen.overridable_minimal_size_pip_resizable_task)
+
+ mDefaultSizePercent = res.getFloat(R.dimen.config_pictureInPictureDefaultSizePercent)
+ mMinimumSizePercent = res.getFraction(R.fraction.config_pipShortestEdgePercent, 1, 1)
+
+ mMaxAspectRatioForMinSize = res.getFloat(
+ R.dimen.config_pictureInPictureAspectRatioLimitForMinSize)
+ mMinAspectRatioForMinSize = 1f / mMaxAspectRatioForMinSize
+ }
+
+ override fun onConfigurationChanged() {
+ reloadResources()
+ }
+
+ override fun getMaxSize(aspectRatio: Float): Size {
+ val insetBounds = pipDisplayLayoutState.insetBounds
+
+ val shorterLength: Int = Math.min(getDisplayBounds().width(),
+ getDisplayBounds().height())
+ val totalHorizontalPadding: Int = (insetBounds.left +
+ (getDisplayBounds().width() - insetBounds.right))
+ val totalVerticalPadding: Int = (insetBounds.top +
+ (getDisplayBounds().height() - insetBounds.bottom))
+
+ return if (aspectRatio > 1f) {
+ val maxWidth = Math.max(getDefaultSize(aspectRatio).width,
+ shorterLength - totalHorizontalPadding)
+ val maxHeight = (maxWidth / aspectRatio).toInt()
+ Size(maxWidth, maxHeight)
+ } else {
+ val maxHeight = Math.max(getDefaultSize(aspectRatio).height,
+ shorterLength - totalVerticalPadding)
+ val maxWidth = (maxHeight * aspectRatio).toInt()
+ Size(maxWidth, maxHeight)
+ }
+ }
+
+ override fun getDefaultSize(aspectRatio: Float): Size {
+ if (mOverrideMinSize != null) {
+ return getMinSize(aspectRatio)
+ }
+ val smallestDisplaySize: Int = Math.min(getDisplayBounds().width(),
+ getDisplayBounds().height())
+ val minSize = Math.max(getMinEdgeSize().toFloat(),
+ smallestDisplaySize * mDefaultSizePercent).toInt()
+ val width: Int
+ val height: Int
+ if (aspectRatio <= mMinAspectRatioForMinSize ||
+ aspectRatio > mMaxAspectRatioForMinSize) {
+ // Beyond these points, we can just use the min size as the shorter edge
+ if (aspectRatio <= 1) {
+ // Portrait, width is the minimum size
+ width = minSize
+ height = Math.round(width / aspectRatio)
+ } else {
+ // Landscape, height is the minimum size
+ height = minSize
+ width = Math.round(height * aspectRatio)
+ }
+ } else {
+ // Within these points, ensure that the bounds fit within the radius of the limits
+ // at the points
+ val widthAtMaxAspectRatioForMinSize: Float = mMaxAspectRatioForMinSize * minSize
+ val radius = PointF.length(widthAtMaxAspectRatioForMinSize, minSize.toFloat())
+ height = Math.round(Math.sqrt((radius * radius /
+ (aspectRatio * aspectRatio + 1)).toDouble())).toInt()
+ width = Math.round(height * aspectRatio)
+ }
+ return Size(width, height)
+ }
+
+ override fun getMinSize(aspectRatio: Float): Size {
+ if (mOverrideMinSize != null) {
+ return adjustOverrideMinSizeToAspectRatio(aspectRatio)!!
+ }
+ val shorterLength: Int = Math.min(getDisplayBounds().width(),
+ getDisplayBounds().height())
+ val minWidth: Int
+ val minHeight: Int
+ if (aspectRatio > 1f) {
+ minWidth = Math.min(getDefaultSize(aspectRatio).width.toFloat(),
+ shorterLength * mMinimumSizePercent).toInt()
+ minHeight = (minWidth / aspectRatio).toInt()
+ } else {
+ minHeight = Math.min(getDefaultSize(aspectRatio).height.toFloat(),
+ shorterLength * mMinimumSizePercent).toInt()
+ minWidth = (minHeight * aspectRatio).toInt()
+ }
+ return Size(minWidth, minHeight)
+ }
+
+ override fun getSizeForAspectRatio(size: Size, aspectRatio: Float): Size {
+ val smallestSize = Math.min(size.width, size.height)
+ val minSize = Math.max(getMinEdgeSize(), smallestSize)
+ val width: Int
+ val height: Int
+ if (aspectRatio <= 1) {
+ // Portrait, width is the minimum size.
+ width = minSize
+ height = Math.round(width / aspectRatio)
+ } else {
+ // Landscape, height is the minimum size
+ height = minSize
+ width = Math.round(height * aspectRatio)
+ }
+ return Size(width, height)
+ }
+
+ private fun getDisplayBounds() = pipDisplayLayoutState.displayBounds
+
+ /** Sets the preferred size of PIP as specified by the activity in PIP mode. */
+ override fun setOverrideMinSize(overrideMinSize: Size?) {
+ mOverrideMinSize = overrideMinSize
+ }
+
+ /** Returns the preferred minimal size specified by the activity in PIP. */
+ override fun getOverrideMinSize(): Size? {
+ val overrideMinSize = mOverrideMinSize ?: return null
+ return if (overrideMinSize.width < mOverridableMinSize ||
+ overrideMinSize.height < mOverridableMinSize) {
+ Size(mOverridableMinSize, mOverridableMinSize)
+ } else {
+ overrideMinSize
+ }
+ }
+
+ private fun getMinEdgeSize(): Int {
+ return if (mOverrideMinSize == null) mDefaultMinSize else getOverrideMinEdgeSize()
+ }
+
+ /**
+ * Returns the adjusted overridden min size if it is set; otherwise, returns null.
+ *
+ *
+ * Overridden min size needs to be adjusted in its own way while making sure that the target
+ * aspect ratio is maintained
+ *
+ * @param aspectRatio target aspect ratio
+ */
+ private fun adjustOverrideMinSizeToAspectRatio(aspectRatio: Float): Size? {
+ val size = getOverrideMinSize() ?: return null
+ val sizeAspectRatio = size.width / size.height.toFloat()
+ return if (sizeAspectRatio > aspectRatio) {
+ // Size is wider, fix the width and increase the height
+ Size(size.width, (size.width / aspectRatio).toInt())
+ } else {
+ // Size is taller, fix the height and adjust the width.
+ Size((size.height * aspectRatio).toInt(), size.height)
+ }
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PhoneSizeSpecSource.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PhoneSizeSpecSource.kt
new file mode 100644
index 000000000000..c5630686f528
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PhoneSizeSpecSource.kt
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common.pip
+
+import android.content.Context
+import android.content.res.Resources
+import android.os.SystemProperties
+import android.util.Size
+import com.android.wm.shell.R
+import com.android.wm.shell.pip.PipDisplayLayoutState
+import java.io.PrintWriter
+
+class PhoneSizeSpecSource(
+ private val context: Context,
+ private val pipDisplayLayoutState: PipDisplayLayoutState
+) : SizeSpecSource {
+ private var DEFAULT_OPTIMIZED_ASPECT_RATIO = 9f / 16
+
+ private var mDefaultMinSize = 0
+ /** The absolute minimum an overridden size's edge can be */
+ private var mOverridableMinSize = 0
+ /** The preferred minimum (and default minimum) size specified by apps. */
+ private var mOverrideMinSize: Size? = null
+
+
+ /** Default and minimum percentages for the PIP size logic. */
+ private val mDefaultSizePercent: Float
+ private val mMinimumSizePercent: Float
+
+ /** Aspect ratio that the PIP size spec logic optimizes for. */
+ private var mOptimizedAspectRatio = 0f
+
+ init {
+ mDefaultSizePercent = SystemProperties
+ .get("com.android.wm.shell.pip.phone.def_percentage", "0.6").toFloat()
+ mMinimumSizePercent = SystemProperties
+ .get("com.android.wm.shell.pip.phone.min_percentage", "0.5").toFloat()
+
+ reloadResources()
+ }
+
+ private fun reloadResources() {
+ val res: Resources = context.getResources()
+
+ mDefaultMinSize = res.getDimensionPixelSize(
+ R.dimen.default_minimal_size_pip_resizable_task)
+ mOverridableMinSize = res.getDimensionPixelSize(
+ R.dimen.overridable_minimal_size_pip_resizable_task)
+
+ val requestedOptAspRatio = res.getFloat(R.dimen.config_pipLargeScreenOptimizedAspectRatio)
+ // make sure the optimized aspect ratio is valid with a default value to fall back to
+ mOptimizedAspectRatio = if (requestedOptAspRatio > 1) {
+ DEFAULT_OPTIMIZED_ASPECT_RATIO
+ } else {
+ requestedOptAspRatio
+ }
+ }
+
+ override fun onConfigurationChanged() {
+ reloadResources()
+ }
+
+ /**
+ * Calculates the max size of PIP.
+ *
+ * Optimizes for 16:9 aspect ratios, making them take full length of shortest display edge.
+ * As aspect ratio approaches values close to 1:1, the logic does not let PIP occupy the
+ * whole screen. A linear function is used to calculate these sizes.
+ *
+ * @param aspectRatio aspect ratio of the PIP window
+ * @return dimensions of the max size of the PIP
+ */
+ override fun getMaxSize(aspectRatio: Float): Size {
+ val insetBounds = pipDisplayLayoutState.insetBounds
+ val displayBounds = pipDisplayLayoutState.displayBounds
+
+ val totalHorizontalPadding: Int = (insetBounds.left +
+ (displayBounds.width() - insetBounds.right))
+ val totalVerticalPadding: Int = (insetBounds.top +
+ (displayBounds.height() - insetBounds.bottom))
+ val shorterLength: Int = Math.min(displayBounds.width() - totalHorizontalPadding,
+ displayBounds.height() - totalVerticalPadding)
+ var maxWidth: Int
+ val maxHeight: Int
+
+ // use the optimized max sizing logic only within a certain aspect ratio range
+ if (aspectRatio >= mOptimizedAspectRatio && aspectRatio <= 1 / mOptimizedAspectRatio) {
+ // this formula and its derivation is explained in b/198643358#comment16
+ maxWidth = Math.round(mOptimizedAspectRatio * shorterLength +
+ shorterLength * (aspectRatio - mOptimizedAspectRatio) / (1 + aspectRatio))
+ // make sure the max width doesn't go beyond shorter screen length after rounding
+ maxWidth = Math.min(maxWidth, shorterLength)
+ maxHeight = Math.round(maxWidth / aspectRatio)
+ } else {
+ if (aspectRatio > 1f) {
+ maxWidth = shorterLength
+ maxHeight = Math.round(maxWidth / aspectRatio)
+ } else {
+ maxHeight = shorterLength
+ maxWidth = Math.round(maxHeight * aspectRatio)
+ }
+ }
+ return Size(maxWidth, maxHeight)
+ }
+
+ /**
+ * Decreases the dimensions by a percentage relative to max size to get default size.
+ *
+ * @param aspectRatio aspect ratio of the PIP window
+ * @return dimensions of the default size of the PIP
+ */
+ override fun getDefaultSize(aspectRatio: Float): Size {
+ val minSize = getMinSize(aspectRatio)
+ if (mOverrideMinSize != null) {
+ return minSize
+ }
+ val maxSize = getMaxSize(aspectRatio)
+ val defaultWidth = Math.max(Math.round(maxSize.width * mDefaultSizePercent),
+ minSize.width)
+ val defaultHeight = Math.round(defaultWidth / aspectRatio)
+ return Size(defaultWidth, defaultHeight)
+ }
+
+ /**
+ * Decreases the dimensions by a certain percentage relative to max size to get min size.
+ *
+ * @param aspectRatio aspect ratio of the PIP window
+ * @return dimensions of the min size of the PIP
+ */
+ override fun getMinSize(aspectRatio: Float): Size {
+ // if there is an overridden min size provided, return that
+ if (mOverrideMinSize != null) {
+ return adjustOverrideMinSizeToAspectRatio(aspectRatio)!!
+ }
+ val maxSize = getMaxSize(aspectRatio)
+ var minWidth = Math.round(maxSize.width * mMinimumSizePercent)
+ var minHeight = Math.round(maxSize.height * mMinimumSizePercent)
+
+ // make sure the calculated min size is not smaller than the allowed default min size
+ if (aspectRatio > 1f) {
+ minHeight = Math.max(minHeight, mDefaultMinSize)
+ minWidth = Math.round(minHeight * aspectRatio)
+ } else {
+ minWidth = Math.max(minWidth, mDefaultMinSize)
+ minHeight = Math.round(minWidth / aspectRatio)
+ }
+ return Size(minWidth, minHeight)
+ }
+
+ /**
+ * Returns the size for target aspect ratio making sure new size conforms with the rules.
+ *
+ *
+ * Recalculates the dimensions such that the target aspect ratio is achieved, while
+ * maintaining the same maximum size to current size ratio.
+ *
+ * @param size current size
+ * @param aspectRatio target aspect ratio
+ */
+ override fun getSizeForAspectRatio(size: Size, aspectRatio: Float): Size {
+ if (size == mOverrideMinSize) {
+ return adjustOverrideMinSizeToAspectRatio(aspectRatio)!!
+ }
+
+ val currAspectRatio = size.width.toFloat() / size.height
+
+ // getting the percentage of the max size that current size takes
+ val currentMaxSize = getMaxSize(currAspectRatio)
+ val currentPercent = size.width.toFloat() / currentMaxSize.width
+
+ // getting the max size for the target aspect ratio
+ val updatedMaxSize = getMaxSize(aspectRatio)
+ var width = Math.round(updatedMaxSize.width * currentPercent)
+ var height = Math.round(updatedMaxSize.height * currentPercent)
+
+ // adjust the dimensions if below allowed min edge size
+ val minEdgeSize =
+ if (mOverrideMinSize == null) mDefaultMinSize else getOverrideMinEdgeSize()
+
+ if (width < minEdgeSize && aspectRatio <= 1) {
+ width = minEdgeSize
+ height = Math.round(width / aspectRatio)
+ } else if (height < minEdgeSize && aspectRatio > 1) {
+ height = minEdgeSize
+ width = Math.round(height * aspectRatio)
+ }
+
+ // reduce the dimensions of the updated size to the calculated percentage
+ return Size(width, height)
+ }
+
+ /** Sets the preferred size of PIP as specified by the activity in PIP mode. */
+ override fun setOverrideMinSize(overrideMinSize: Size?) {
+ mOverrideMinSize = overrideMinSize
+ }
+
+ /** Returns the preferred minimal size specified by the activity in PIP. */
+ override fun getOverrideMinSize(): Size? {
+ val overrideMinSize = mOverrideMinSize ?: return null
+ return if (overrideMinSize.width < mOverridableMinSize ||
+ overrideMinSize.height < mOverridableMinSize) {
+ Size(mOverridableMinSize, mOverridableMinSize)
+ } else {
+ overrideMinSize
+ }
+ }
+
+ /**
+ * Returns the adjusted overridden min size if it is set; otherwise, returns null.
+ *
+ *
+ * Overridden min size needs to be adjusted in its own way while making sure that the target
+ * aspect ratio is maintained
+ *
+ * @param aspectRatio target aspect ratio
+ */
+ private fun adjustOverrideMinSizeToAspectRatio(aspectRatio: Float): Size? {
+ val size = getOverrideMinSize() ?: return null
+ val sizeAspectRatio = size.width / size.height.toFloat()
+ return if (sizeAspectRatio > aspectRatio) {
+ // Size is wider, fix the width and increase the height
+ Size(size.width, (size.width / aspectRatio).toInt())
+ } else {
+ // Size is taller, fix the height and adjust the width.
+ Size((size.height * aspectRatio).toInt(), size.height)
+ }
+ }
+
+ override fun dump(pw: PrintWriter, prefix: String) {
+ val innerPrefix = "$prefix "
+ pw.println(innerPrefix + "mOverrideMinSize=" + mOverrideMinSize)
+ pw.println(innerPrefix + "mOverridableMinSize=" + mOverridableMinSize)
+ pw.println(innerPrefix + "mDefaultMinSize=" + mDefaultMinSize)
+ pw.println(innerPrefix + "mDefaultSizePercent=" + mDefaultSizePercent)
+ pw.println(innerPrefix + "mMinimumSizePercent=" + mMinimumSizePercent)
+ pw.println(innerPrefix + "mOptimizedAspectRatio=" + mOptimizedAspectRatio)
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/SizeSpecSource.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/SizeSpecSource.kt
new file mode 100644
index 000000000000..7b3b9efb0de0
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/SizeSpecSource.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common.pip
+
+import android.util.Size
+import java.io.PrintWriter
+
+interface SizeSpecSource {
+ /** Returns max size allowed for the PIP window */
+ fun getMaxSize(aspectRatio: Float): Size
+
+ /** Returns default size for the PIP window */
+ fun getDefaultSize(aspectRatio: Float): Size
+
+ /** Returns min size allowed for the PIP window */
+ fun getMinSize(aspectRatio: Float): Size
+
+ /** Returns the adjusted size based on current size and target aspect ratio */
+ fun getSizeForAspectRatio(size: Size, aspectRatio: Float): Size
+
+ /** Overrides the minimum pip size requested by the app */
+ fun setOverrideMinSize(overrideMinSize: Size?)
+
+ /** Returns the minimum pip size requested by the app */
+ fun getOverrideMinSize(): Size?
+
+ /** Returns the minimum edge size of the override minimum size, or 0 if not set. */
+ fun getOverrideMinEdgeSize(): Int {
+ val overrideMinSize = getOverrideMinSize() ?: return 0
+ return Math.min(overrideMinSize.width, overrideMinSize.height)
+ }
+
+ fun onConfigurationChanged() {}
+
+ /** Dumps the internal state of the size spec */
+ fun dump(pw: PrintWriter, prefix: String) {}
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index e8fa638bea31..d3fada37a685 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -722,10 +722,6 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
return bounds.width() > bounds.height();
}
- public boolean isDensityChanged(int densityDpi) {
- return mDensity != densityDpi;
- }
-
/**
* Return if this layout is landscape.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
index 16c39601e0bf..54be90197e47 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
@@ -30,6 +30,8 @@ import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TabletopModeController;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
+import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.dagger.WMShellBaseModule;
import com.android.wm.shell.dagger.WMSingleton;
import com.android.wm.shell.onehanded.OneHandedController;
@@ -53,7 +55,6 @@ import com.android.wm.shell.pip.phone.PhonePipKeepClearAlgorithm;
import com.android.wm.shell.pip.phone.PhonePipMenuController;
import com.android.wm.shell.pip.phone.PipController;
import com.android.wm.shell.pip.phone.PipMotionHelper;
-import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.sysui.ShellCommandHandler;
@@ -87,7 +88,6 @@ public abstract class Pip1Module {
PipBoundsAlgorithm pipBoundsAlgorithm,
PhonePipKeepClearAlgorithm pipKeepClearAlgorithm,
PipBoundsState pipBoundsState,
- PipSizeSpecHandler pipSizeSpecHandler,
PipDisplayLayoutState pipDisplayLayoutState,
PipMotionHelper pipMotionHelper,
PipMediaController pipMediaController,
@@ -110,8 +110,7 @@ public abstract class Pip1Module {
context, shellInit, shellCommandHandler, shellController,
displayController, pipAnimationController, pipAppOpsListener,
pipBoundsAlgorithm,
- pipKeepClearAlgorithm, pipBoundsState, pipSizeSpecHandler,
- pipDisplayLayoutState,
+ pipKeepClearAlgorithm, pipBoundsState, pipDisplayLayoutState,
pipMotionHelper, pipMediaController, phonePipMenuController, pipTaskOrganizer,
pipTransitionState, pipTouchHandler, pipTransitionController,
windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
@@ -123,8 +122,8 @@ public abstract class Pip1Module {
@WMSingleton
@Provides
static PipBoundsState providePipBoundsState(Context context,
- PipSizeSpecHandler pipSizeSpecHandler, PipDisplayLayoutState pipDisplayLayoutState) {
- return new PipBoundsState(context, pipSizeSpecHandler, pipDisplayLayoutState);
+ SizeSpecSource sizeSpecSource, PipDisplayLayoutState pipDisplayLayoutState) {
+ return new PipBoundsState(context, sizeSpecSource, pipDisplayLayoutState);
}
@WMSingleton
@@ -141,19 +140,12 @@ public abstract class Pip1Module {
@WMSingleton
@Provides
- static PipSizeSpecHandler providePipSizeSpecHelper(Context context,
- PipDisplayLayoutState pipDisplayLayoutState) {
- return new PipSizeSpecHandler(context, pipDisplayLayoutState);
- }
-
- @WMSingleton
- @Provides
static PipBoundsAlgorithm providesPipBoundsAlgorithm(Context context,
PipBoundsState pipBoundsState, PipSnapAlgorithm pipSnapAlgorithm,
PhonePipKeepClearAlgorithm pipKeepClearAlgorithm,
- PipSizeSpecHandler pipSizeSpecHandler) {
+ PipDisplayLayoutState pipDisplayLayoutState, SizeSpecSource sizeSpecSource) {
return new PipBoundsAlgorithm(context, pipBoundsState, pipSnapAlgorithm,
- pipKeepClearAlgorithm, pipSizeSpecHandler);
+ pipKeepClearAlgorithm, pipDisplayLayoutState, sizeSpecSource);
}
// Handler is used by Icon.loadDrawableAsync
@@ -177,14 +169,14 @@ public abstract class Pip1Module {
PhonePipMenuController menuPhoneController,
PipBoundsAlgorithm pipBoundsAlgorithm,
PipBoundsState pipBoundsState,
- PipSizeSpecHandler pipSizeSpecHandler,
+ SizeSpecSource sizeSpecSource,
PipTaskOrganizer pipTaskOrganizer,
PipMotionHelper pipMotionHelper,
FloatingContentCoordinator floatingContentCoordinator,
PipUiEventLogger pipUiEventLogger,
@ShellMainThread ShellExecutor mainExecutor) {
return new PipTouchHandler(context, shellInit, menuPhoneController, pipBoundsAlgorithm,
- pipBoundsState, pipSizeSpecHandler, pipTaskOrganizer, pipMotionHelper,
+ pipBoundsState, sizeSpecSource, pipTaskOrganizer, pipMotionHelper,
floatingContentCoordinator, pipUiEventLogger, mainExecutor);
}
@@ -243,6 +235,13 @@ public abstract class Pip1Module {
@WMSingleton
@Provides
+ static SizeSpecSource provideSizeSpecSource(Context context,
+ PipDisplayLayoutState pipDisplayLayoutState) {
+ return new PhoneSizeSpecSource(context, pipDisplayLayoutState);
+ }
+
+ @WMSingleton
+ @Provides
static PipAppOpsListener providePipAppOpsListener(Context context,
PipTouchHandler pipTouchHandler,
@ShellMainThread ShellExecutor mainExecutor) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java
index 360bf8b70fca..52c6d2008a9d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java
@@ -28,6 +28,8 @@ import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.common.pip.LegacySizeSpecSource;
+import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.dagger.WMShellBaseModule;
import com.android.wm.shell.dagger.WMSingleton;
import com.android.wm.shell.pip.Pip;
@@ -42,7 +44,6 @@ import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.PipTransitionState;
import com.android.wm.shell.pip.PipUiEventLogger;
-import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
import com.android.wm.shell.pip.tv.TvPipBoundsAlgorithm;
import com.android.wm.shell.pip.tv.TvPipBoundsController;
import com.android.wm.shell.pip.tv.TvPipBoundsState;
@@ -138,23 +139,23 @@ public abstract class TvPipModule {
@Provides
static TvPipBoundsAlgorithm provideTvPipBoundsAlgorithm(Context context,
TvPipBoundsState tvPipBoundsState, PipSnapAlgorithm pipSnapAlgorithm,
- PipSizeSpecHandler pipSizeSpecHandler) {
+ PipDisplayLayoutState pipDisplayLayoutState, SizeSpecSource sizeSpecSource) {
return new TvPipBoundsAlgorithm(context, tvPipBoundsState, pipSnapAlgorithm,
- pipSizeSpecHandler);
+ pipDisplayLayoutState, sizeSpecSource);
}
@WMSingleton
@Provides
static TvPipBoundsState provideTvPipBoundsState(Context context,
- PipSizeSpecHandler pipSizeSpecHandler, PipDisplayLayoutState pipDisplayLayoutState) {
- return new TvPipBoundsState(context, pipSizeSpecHandler, pipDisplayLayoutState);
+ SizeSpecSource sizeSpecSource, PipDisplayLayoutState pipDisplayLayoutState) {
+ return new TvPipBoundsState(context, sizeSpecSource, pipDisplayLayoutState);
}
@WMSingleton
@Provides
- static PipSizeSpecHandler providePipSizeSpecHelper(Context context,
+ static SizeSpecSource provideSizeSpecSource(Context context,
PipDisplayLayoutState pipDisplayLayoutState) {
- return new PipSizeSpecHandler(context, pipDisplayLayoutState);
+ return new LegacySizeSpecSource(context, pipDisplayLayoutState);
}
// Handler needed for loadDrawableAsync() in PipControlsViewController
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
index 16b23935559c..024465b281b8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
@@ -241,7 +241,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
public void onAnimationEnd(Animator animation) {
mDesktopModeWindowDecoration.hideResizeVeil();
mTransitions.getMainExecutor().execute(
- () -> finishCallback.onTransitionFinished(null, null));
+ () -> finishCallback.onTransitionFinished(null));
}
});
animator.start();
@@ -271,8 +271,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
startT.apply();
- mTransitions.getMainExecutor().execute(
- () -> finishCallback.onTransitionFinished(null, null));
+ mTransitions.getMainExecutor().execute(() -> finishCallback.onTransitionFinished(null));
return true;
}
@@ -324,7 +323,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
mOnAnimationFinishedCallback.accept(finishT);
}
mTransitions.getMainExecutor().execute(
- () -> finishCallback.onTransitionFinished(null, null));
+ () -> finishCallback.onTransitionFinished(null));
}
});
@@ -378,7 +377,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
mOnAnimationFinishedCallback.accept(finishT);
}
mTransitions.getMainExecutor().execute(
- () -> finishCallback.onTransitionFinished(null, null));
+ () -> finishCallback.onTransitionFinished(null));
}
});
animator.start();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
index 3ad5edf0e604..7342bd1ae5de 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
@@ -168,7 +168,7 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH
mOnAnimationFinishedCallback.accept(finishT);
}
mTransitions.getMainExecutor().execute(
- () -> finishCallback.onTransitionFinished(null, null));
+ () -> finishCallback.onTransitionFinished(null));
}
});
animator.start();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt
index 94788e45e2b6..b9cb5c75aaf0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt
@@ -104,7 +104,7 @@ class ToggleResizeDesktopTaskTransitionHandler(
.setWindowCrop(leash, endBounds.width(), endBounds.height())
.show(leash)
windowDecor.hideResizeVeil()
- finishCallback.onTransitionFinished(null, null)
+ finishCallback.onTransitionFinished(null)
boundsAnimator = null
}
)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
index 55e34fe3d836..84027753435b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
@@ -130,7 +130,7 @@ public class FreeformTaskTransitionHandler
if (!animations.isEmpty()) return;
mMainExecutor.execute(() -> {
mAnimations.remove(transition);
- finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ finishCallback.onTransitionFinished(null /* wct */);
});
};
for (TransitionInfo.Change change : info.getChanges()) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
index 56bd188a0d7d..2ef92adb90f5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
@@ -19,7 +19,6 @@ package com.android.wm.shell.keyguard;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.view.WindowManager.KEYGUARD_VISIBILITY_TRANSIT_FLAGS;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_APPEARING;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_OCCLUDING;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_UNOCCLUDING;
import static android.view.WindowManager.TRANSIT_SLEEP;
@@ -169,7 +168,7 @@ public class KeyguardTransitionHandler implements Transitions.TransitionHandler
// Post our finish callback to let startAnimation finish first.
mMainExecutor.executeDelayed(() -> {
mStartedTransitions.remove(transition);
- finishCallback.onTransitionFinished(wct, null);
+ finishCallback.onTransitionFinished(wct);
}, 0);
}
});
@@ -206,7 +205,7 @@ public class KeyguardTransitionHandler implements Transitions.TransitionHandler
// implementing an AIDL interface.
Log.wtf(TAG, "RemoteException thrown from KeyguardService transition", e);
}
- nextFinishCallback.onTransitionFinished(null, null);
+ nextFinishCallback.onTransitionFinished(null);
} else if (nextInfo.getType() == TRANSIT_SLEEP) {
// An empty SLEEP transition comes in as a signal to abort transitions whenever a sleep
// token is held. In cases where keyguard is showing, we are running the animation for
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
index f51eb5299dd9..ac711eafe3ef 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
@@ -28,7 +28,7 @@ import android.util.Size;
import android.view.Gravity;
import com.android.wm.shell.R;
-import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
+import com.android.wm.shell.common.pip.SizeSpecSource;
import java.io.PrintWriter;
@@ -41,7 +41,8 @@ public class PipBoundsAlgorithm {
private static final float INVALID_SNAP_FRACTION = -1f;
@NonNull private final PipBoundsState mPipBoundsState;
- @NonNull protected final PipSizeSpecHandler mPipSizeSpecHandler;
+ @NonNull protected final PipDisplayLayoutState mPipDisplayLayoutState;
+ @NonNull protected final SizeSpecSource mSizeSpecSource;
private final PipSnapAlgorithm mSnapAlgorithm;
private final PipKeepClearAlgorithmInterface mPipKeepClearAlgorithm;
@@ -53,11 +54,13 @@ public class PipBoundsAlgorithm {
public PipBoundsAlgorithm(Context context, @NonNull PipBoundsState pipBoundsState,
@NonNull PipSnapAlgorithm pipSnapAlgorithm,
@NonNull PipKeepClearAlgorithmInterface pipKeepClearAlgorithm,
- @NonNull PipSizeSpecHandler pipSizeSpecHandler) {
+ @NonNull PipDisplayLayoutState pipDisplayLayoutState,
+ @NonNull SizeSpecSource sizeSpecSource) {
mPipBoundsState = pipBoundsState;
mSnapAlgorithm = pipSnapAlgorithm;
mPipKeepClearAlgorithm = pipKeepClearAlgorithm;
- mPipSizeSpecHandler = pipSizeSpecHandler;
+ mPipDisplayLayoutState = pipDisplayLayoutState;
+ mSizeSpecSource = sizeSpecSource;
reloadResources(context);
// Initialize the aspect ratio to the default aspect ratio. Don't do this in reload
// resources as it would clobber mAspectRatio when entering PiP from fullscreen which
@@ -74,11 +77,6 @@ public class PipBoundsAlgorithm {
R.dimen.config_pictureInPictureDefaultAspectRatio);
mDefaultStackGravity = res.getInteger(
R.integer.config_defaultPictureInPictureGravity);
- final String screenEdgeInsetsDpString = res.getString(
- R.string.config_defaultPictureInPictureScreenEdgeInsets);
- final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
- ? Size.parseSize(screenEdgeInsetsDpString)
- : null;
mMinAspectRatio = res.getFloat(
com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
mMaxAspectRatio = res.getFloat(
@@ -160,8 +158,8 @@ public class PipBoundsAlgorithm {
// If either dimension is smaller than the allowed minimum, adjust them
// according to mOverridableMinSize
return new Size(
- Math.max(windowLayout.minWidth, mPipSizeSpecHandler.getOverrideMinEdgeSize()),
- Math.max(windowLayout.minHeight, mPipSizeSpecHandler.getOverrideMinEdgeSize()));
+ Math.max(windowLayout.minWidth, getOverrideMinEdgeSize()),
+ Math.max(windowLayout.minHeight, getOverrideMinEdgeSize()));
}
return null;
}
@@ -255,10 +253,10 @@ public class PipBoundsAlgorithm {
final Size size;
if (useCurrentMinEdgeSize || useCurrentSize) {
// Use the existing size but adjusted to the new aspect ratio.
- size = mPipSizeSpecHandler.getSizeForAspectRatio(
+ size = mSizeSpecSource.getSizeForAspectRatio(
new Size(stackBounds.width(), stackBounds.height()), aspectRatio);
} else {
- size = mPipSizeSpecHandler.getDefaultSize(aspectRatio);
+ size = mSizeSpecSource.getDefaultSize(aspectRatio);
}
final int left = (int) (stackBounds.centerX() - size.getWidth() / 2f);
@@ -287,7 +285,7 @@ public class PipBoundsAlgorithm {
getInsetBounds(insetBounds);
// Calculate the default size
- defaultSize = mPipSizeSpecHandler.getDefaultSize(mDefaultAspectRatio);
+ defaultSize = mSizeSpecSource.getDefaultSize(mDefaultAspectRatio);
// Now that we have the default size, apply the snap fraction if valid or position the
// bounds using the default gravity.
@@ -309,7 +307,11 @@ public class PipBoundsAlgorithm {
* Populates the bounds on the screen that the PIP can be visible in.
*/
public void getInsetBounds(Rect outRect) {
- outRect.set(mPipSizeSpecHandler.getInsetBounds());
+ outRect.set(mPipDisplayLayoutState.getInsetBounds());
+ }
+
+ private int getOverrideMinEdgeSize() {
+ return mSizeSpecSource.getOverrideMinEdgeSize();
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
index 9a775dff1f69..279ffc50e07e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
@@ -36,7 +36,7 @@ import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.TriConsumer;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
+import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.io.PrintWriter;
@@ -87,7 +87,7 @@ public class PipBoundsState {
private int mStashOffset;
private @Nullable PipReentryState mPipReentryState;
private final LauncherState mLauncherState = new LauncherState();
- private final @Nullable PipSizeSpecHandler mPipSizeSpecHandler;
+ private final @NonNull SizeSpecSource mSizeSpecSource;
private @Nullable ComponentName mLastPipComponentName;
private final @NonNull MotionBoundsState mMotionBoundsState = new MotionBoundsState();
private boolean mIsImeShowing;
@@ -127,17 +127,20 @@ public class PipBoundsState {
private @Nullable TriConsumer<Boolean, Integer, Boolean> mOnShelfVisibilityChangeCallback;
private List<Consumer<Rect>> mOnPipExclusionBoundsChangeCallbacks = new ArrayList<>();
- public PipBoundsState(@NonNull Context context, PipSizeSpecHandler pipSizeSpecHandler,
- PipDisplayLayoutState pipDisplayLayoutState) {
+ public PipBoundsState(@NonNull Context context, @NonNull SizeSpecSource sizeSpecSource,
+ @NonNull PipDisplayLayoutState pipDisplayLayoutState) {
mContext = context;
reloadResources();
- mPipSizeSpecHandler = pipSizeSpecHandler;
+ mSizeSpecSource = sizeSpecSource;
mPipDisplayLayoutState = pipDisplayLayoutState;
}
/** Reloads the resources. */
public void onConfigurationChanged() {
reloadResources();
+
+ // update the size spec resources upon config change too
+ mSizeSpecSource.onConfigurationChanged();
}
private void reloadResources() {
@@ -319,7 +322,7 @@ public class PipBoundsState {
/** Sets the preferred size of PIP as specified by the activity in PIP mode. */
public void setOverrideMinSize(@Nullable Size overrideMinSize) {
final boolean changed = !Objects.equals(overrideMinSize, getOverrideMinSize());
- mPipSizeSpecHandler.setOverrideMinSize(overrideMinSize);
+ mSizeSpecSource.setOverrideMinSize(overrideMinSize);
if (changed && mOnMinimalSizeChangeCallback != null) {
mOnMinimalSizeChangeCallback.run();
}
@@ -328,12 +331,12 @@ public class PipBoundsState {
/** Returns the preferred minimal size specified by the activity in PIP. */
@Nullable
public Size getOverrideMinSize() {
- return mPipSizeSpecHandler.getOverrideMinSize();
+ return mSizeSpecSource.getOverrideMinSize();
}
/** Returns the minimum edge size of the override minimum size, or 0 if not set. */
public int getOverrideMinEdgeSize() {
- return mPipSizeSpecHandler.getOverrideMinEdgeSize();
+ return mSizeSpecSource.getOverrideMinEdgeSize();
}
/** Get the state of the bounds in motion. */
@@ -613,5 +616,6 @@ public class PipBoundsState {
}
mLauncherState.dump(pw, innerPrefix);
mMotionBoundsState.dump(pw, innerPrefix);
+ mSizeSpecSource.dump(pw, innerPrefix);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipDisplayLayoutState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipDisplayLayoutState.java
index 0f76af48199f..456f85b52da4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipDisplayLayoutState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipDisplayLayoutState.java
@@ -16,12 +16,18 @@
package com.android.wm.shell.pip;
+import static com.android.wm.shell.pip.PipUtils.dpToPx;
+
import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Point;
import android.graphics.Rect;
+import android.util.Size;
import android.view.Surface;
import androidx.annotation.NonNull;
+import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.dagger.WMSingleton;
@@ -40,13 +46,51 @@ public class PipDisplayLayoutState {
private int mDisplayId;
@NonNull private DisplayLayout mDisplayLayout;
+ private Point mScreenEdgeInsets = null;
+
@Inject
public PipDisplayLayoutState(Context context) {
mContext = context;
mDisplayLayout = new DisplayLayout();
+ reloadResources();
+ }
+
+ /** Responds to configuration change. */
+ public void onConfigurationChanged() {
+ reloadResources();
+ }
+
+ private void reloadResources() {
+ Resources res = mContext.getResources();
+
+ final String screenEdgeInsetsDpString = res.getString(
+ R.string.config_defaultPictureInPictureScreenEdgeInsets);
+ final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
+ ? Size.parseSize(screenEdgeInsetsDpString)
+ : null;
+ mScreenEdgeInsets = screenEdgeInsetsDp == null ? new Point()
+ : new Point(dpToPx(screenEdgeInsetsDp.getWidth(), res.getDisplayMetrics()),
+ dpToPx(screenEdgeInsetsDp.getHeight(), res.getDisplayMetrics()));
+ }
+
+ public Point getScreenEdgeInsets() {
+ return mScreenEdgeInsets;
+ }
+
+ /**
+ * Returns the inset bounds the PIP window can be visible in.
+ */
+ public Rect getInsetBounds() {
+ Rect insetBounds = new Rect();
+ Rect insets = getDisplayLayout().stableInsets();
+ insetBounds.set(insets.left + getScreenEdgeInsets().x,
+ insets.top + getScreenEdgeInsets().y,
+ getDisplayLayout().width() - insets.right - getScreenEdgeInsets().x,
+ getDisplayLayout().height() - insets.bottom - getScreenEdgeInsets().y);
+ return insetBounds;
}
- /** Update the display layout. */
+ /** Set the display layout. */
public void setDisplayLayout(@NonNull DisplayLayout displayLayout) {
mDisplayLayout.set(displayLayout);
}
@@ -87,5 +131,6 @@ public class PipDisplayLayoutState {
pw.println(prefix + TAG);
pw.println(innerPrefix + "mDisplayId=" + mDisplayId);
pw.println(innerPrefix + "getDisplayBounds=" + getDisplayBounds());
+ pw.println(innerPrefix + "mScreenEdgeInsets=" + mScreenEdgeInsets);
}
}
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 208f9b7432bf..0d55018ba580 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
@@ -592,7 +592,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
SplitScreenController split = mSplitScreenOptional.get();
if (split.isTaskInSplitScreen(mTaskInfo.lastParentTaskIdBeforePip)) {
split.prepareExitSplitScreen(wct, split.getStageOfTask(
- mTaskInfo.lastParentTaskIdBeforePip));
+ mTaskInfo.lastParentTaskIdBeforePip),
+ SplitScreenController.EXIT_REASON_APP_FINISHED);
}
}
mPipTransitionController.startExitTransition(TRANSIT_EXIT_PIP, wct, destinationBounds);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index e3d53fc415db..2563d984b793 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -447,7 +447,7 @@ public class PipTransition extends PipTransitionController {
// handler if there is a pending PiP animation.
final Transitions.TransitionFinishCallback finishCallback = mFinishCallback;
mFinishCallback = null;
- finishCallback.onTransitionFinished(wct, null /* callback */);
+ finishCallback.onTransitionFinished(wct);
}
@Override
@@ -456,7 +456,7 @@ public class PipTransition extends PipTransitionController {
// for example, when app crashes while in PiP and exit transition has not started
mCurrentPipTaskToken = null;
if (mFinishCallback == null) return;
- mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
+ mFinishCallback.onTransitionFinished(null /* wct */);
mFinishCallback = null;
mFinishTransaction = null;
}
@@ -586,7 +586,7 @@ public class PipTransition extends PipTransitionController {
final boolean useLocalLeash = activitySc != null;
final boolean toFullscreen = pipChange.getEndAbsBounds().equals(
mPipBoundsState.getDisplayBounds());
- mFinishCallback = (wct, wctCB) -> {
+ mFinishCallback = (wct) -> {
mPipOrganizer.onExitPipFinished(taskInfo);
// TODO(b/286346098): remove the OPEN app flicker completely
@@ -610,7 +610,7 @@ public class PipTransition extends PipTransitionController {
mPipAnimationController.resetAnimatorState();
finishTransaction.remove(pipLeash);
}
- finishCallback.onTransitionFinished(wct, wctCB);
+ finishCallback.onTransitionFinished(wct);
};
mFinishTransaction = finishTransaction;
@@ -750,7 +750,7 @@ public class PipTransition extends PipTransitionController {
finishTransaction.setWindowCrop(info.getChanges().get(0).getLeash(),
mPipDisplayLayoutState.getDisplayBounds());
mPipOrganizer.onExitPipFinished(taskInfo);
- finishCallback.onTransitionFinished(null, null);
+ finishCallback.onTransitionFinished(null);
}
/** Whether we should handle the given {@link TransitionInfo} animation as entering PIP. */
@@ -1045,7 +1045,7 @@ public class PipTransition extends PipTransitionController {
startTransaction.apply();
mPipOrganizer.onExitPipFinished(taskInfo);
- finishCallback.onTransitionFinished(null, null);
+ finishCallback.onTransitionFinished(null);
}
private void resetPrevPip(@NonNull TransitionInfo.Change prevPipTaskChange,
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 7d82dc17ae72..f396f3fedf64 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
@@ -142,7 +142,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb
private PipBoundsAlgorithm mPipBoundsAlgorithm;
private PipKeepClearAlgorithmInterface mPipKeepClearAlgorithm;
private PipBoundsState mPipBoundsState;
- private PipSizeSpecHandler mPipSizeSpecHandler;
private PipDisplayLayoutState mPipDisplayLayoutState;
private PipMotionHelper mPipMotionHelper;
private PipTouchHandler mTouchHandler;
@@ -406,7 +405,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb
PipBoundsAlgorithm pipBoundsAlgorithm,
PipKeepClearAlgorithmInterface pipKeepClearAlgorithm,
PipBoundsState pipBoundsState,
- PipSizeSpecHandler pipSizeSpecHandler,
PipDisplayLayoutState pipDisplayLayoutState,
PipMotionHelper pipMotionHelper,
PipMediaController pipMediaController,
@@ -430,7 +428,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
return new PipController(context, shellInit, shellCommandHandler, shellController,
displayController, pipAnimationController, pipAppOpsListener,
- pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState, pipSizeSpecHandler,
+ pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState,
pipDisplayLayoutState, pipMotionHelper, pipMediaController, phonePipMenuController,
pipTaskOrganizer, pipTransitionState, pipTouchHandler, pipTransitionController,
windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
@@ -448,7 +446,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb
PipBoundsAlgorithm pipBoundsAlgorithm,
PipKeepClearAlgorithmInterface pipKeepClearAlgorithm,
@NonNull PipBoundsState pipBoundsState,
- PipSizeSpecHandler pipSizeSpecHandler,
@NonNull PipDisplayLayoutState pipDisplayLayoutState,
PipMotionHelper pipMotionHelper,
PipMediaController pipMediaController,
@@ -474,7 +471,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb
mPipBoundsAlgorithm = pipBoundsAlgorithm;
mPipKeepClearAlgorithm = pipKeepClearAlgorithm;
mPipBoundsState = pipBoundsState;
- mPipSizeSpecHandler = pipSizeSpecHandler;
mPipDisplayLayoutState = pipDisplayLayoutState;
mPipMotionHelper = pipMotionHelper;
mPipTaskOrganizer = pipTaskOrganizer;
@@ -711,7 +707,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
// Try to move the PiP window if we have entered PiP mode.
if (mPipTransitionState.hasEnteredPip()) {
final Rect pipBounds = mPipBoundsState.getBounds();
- final Point edgeInsets = mPipSizeSpecHandler.getScreenEdgeInsets();
+ final Point edgeInsets = mPipDisplayLayoutState.getScreenEdgeInsets();
if ((pipBounds.height() + 2 * edgeInsets.y) > (displayBounds.height() / 2)) {
// PiP bounds is too big to fit either half, bail early.
return;
@@ -770,7 +766,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb
mPipBoundsAlgorithm.onConfigurationChanged(mContext);
mTouchHandler.onConfigurationChanged();
mPipBoundsState.onConfigurationChanged();
- mPipSizeSpecHandler.onConfigurationChanged();
+ mPipDisplayLayoutState.onConfigurationChanged();
}
@Override
@@ -799,6 +795,14 @@ public class PipController implements PipTransitionController.PipTransitionCallb
}
private void onDisplayChangedUncheck(DisplayLayout layout, boolean saveRestoreSnapFraction) {
+ if (mPipTransitionState.getInSwipePipToHomeTransition()) {
+ // If orientation is changed when performing swipe-pip animation, DisplayLayout has
+ // been updated in startSwipePipToHome. So it is unnecessary to update again when
+ // receiving onDisplayConfigurationChanged. This also avoids TouchHandler.userResizeTo
+ // update surface position in different orientation by the intermediate state. The
+ // desired resize will be done by the end of transition.
+ return;
+ }
Runnable updateDisplayLayout = () -> {
final boolean fromRotation = Transitions.ENABLE_SHELL_TRANSITIONS
&& mPipDisplayLayoutState.getDisplayLayout().rotation() != layout.rotation();
@@ -1216,7 +1220,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb
mPipTaskOrganizer.dump(pw, innerPrefix);
mPipBoundsState.dump(pw, innerPrefix);
mPipInputConsumer.dump(pw, innerPrefix);
- mPipSizeSpecHandler.dump(pw, innerPrefix);
mPipDisplayLayoutState.dump(pw, innerPrefix);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java
deleted file mode 100644
index c6e5cf25f844..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.pip.phone;
-
-import static com.android.wm.shell.pip.PipUtils.dpToPx;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.os.SystemProperties;
-import android.util.Size;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.wm.shell.R;
-import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.pip.PipDisplayLayoutState;
-
-import java.io.PrintWriter;
-
-/**
- * Acts as a source of truth for appropriate size spec for PIP.
- */
-public class PipSizeSpecHandler {
- private static final String TAG = PipSizeSpecHandler.class.getSimpleName();
-
- @NonNull private final PipDisplayLayoutState mPipDisplayLayoutState;
-
- private final SizeSpecSource mSizeSpecSourceImpl;
-
- /** The preferred minimum (and default minimum) size specified by apps. */
- @Nullable private Size mOverrideMinSize;
- private int mOverridableMinSize;
-
- /** Used to store values obtained from resource files. */
- private Point mScreenEdgeInsets;
- private float mMinAspectRatioForMinSize;
- private float mMaxAspectRatioForMinSize;
- private int mDefaultMinSize;
-
- @NonNull private final Context mContext;
-
- private interface SizeSpecSource {
- /** Returns max size allowed for the PIP window */
- Size getMaxSize(float aspectRatio);
-
- /** Returns default size for the PIP window */
- Size getDefaultSize(float aspectRatio);
-
- /** Returns min size allowed for the PIP window */
- Size getMinSize(float aspectRatio);
-
- /** Returns the adjusted size based on current size and target aspect ratio */
- Size getSizeForAspectRatio(Size size, float aspectRatio);
-
- /** Updates internal resources on configuration changes */
- default void reloadResources() {}
- }
-
- /**
- * Determines PIP window size optimized for large screens and aspect ratios close to 1:1
- */
- private class SizeSpecLargeScreenOptimizedImpl implements SizeSpecSource {
- private static final float DEFAULT_OPTIMIZED_ASPECT_RATIO = 9f / 16;
-
- /** Default and minimum percentages for the PIP size logic. */
- private final float mDefaultSizePercent;
- private final float mMinimumSizePercent;
-
- /** Aspect ratio that the PIP size spec logic optimizes for. */
- private float mOptimizedAspectRatio;
-
- private SizeSpecLargeScreenOptimizedImpl() {
- mDefaultSizePercent = Float.parseFloat(SystemProperties
- .get("com.android.wm.shell.pip.phone.def_percentage", "0.6"));
- mMinimumSizePercent = Float.parseFloat(SystemProperties
- .get("com.android.wm.shell.pip.phone.min_percentage", "0.5"));
- }
-
- @Override
- public void reloadResources() {
- final Resources res = mContext.getResources();
-
- mOptimizedAspectRatio = res.getFloat(R.dimen.config_pipLargeScreenOptimizedAspectRatio);
- // make sure the optimized aspect ratio is valid with a default value to fall back to
- if (mOptimizedAspectRatio > 1) {
- mOptimizedAspectRatio = DEFAULT_OPTIMIZED_ASPECT_RATIO;
- }
- }
-
- /**
- * Calculates the max size of PIP.
- *
- * Optimizes for 16:9 aspect ratios, making them take full length of shortest display edge.
- * As aspect ratio approaches values close to 1:1, the logic does not let PIP occupy the
- * whole screen. A linear function is used to calculate these sizes.
- *
- * @param aspectRatio aspect ratio of the PIP window
- * @return dimensions of the max size of the PIP
- */
- @Override
- public Size getMaxSize(float aspectRatio) {
- final int totalHorizontalPadding = getInsetBounds().left
- + (getDisplayBounds().width() - getInsetBounds().right);
- final int totalVerticalPadding = getInsetBounds().top
- + (getDisplayBounds().height() - getInsetBounds().bottom);
-
- final int shorterLength = Math.min(getDisplayBounds().width() - totalHorizontalPadding,
- getDisplayBounds().height() - totalVerticalPadding);
-
- int maxWidth, maxHeight;
-
- // use the optimized max sizing logic only within a certain aspect ratio range
- if (aspectRatio >= mOptimizedAspectRatio && aspectRatio <= 1 / mOptimizedAspectRatio) {
- // this formula and its derivation is explained in b/198643358#comment16
- maxWidth = Math.round(mOptimizedAspectRatio * shorterLength
- + shorterLength * (aspectRatio - mOptimizedAspectRatio) / (1
- + aspectRatio));
- // make sure the max width doesn't go beyond shorter screen length after rounding
- maxWidth = Math.min(maxWidth, shorterLength);
- maxHeight = Math.round(maxWidth / aspectRatio);
- } else {
- if (aspectRatio > 1f) {
- maxWidth = shorterLength;
- maxHeight = Math.round(maxWidth / aspectRatio);
- } else {
- maxHeight = shorterLength;
- maxWidth = Math.round(maxHeight * aspectRatio);
- }
- }
-
- return new Size(maxWidth, maxHeight);
- }
-
- /**
- * Decreases the dimensions by a percentage relative to max size to get default size.
- *
- * @param aspectRatio aspect ratio of the PIP window
- * @return dimensions of the default size of the PIP
- */
- @Override
- public Size getDefaultSize(float aspectRatio) {
- Size minSize = this.getMinSize(aspectRatio);
-
- if (mOverrideMinSize != null) {
- return minSize;
- }
-
- Size maxSize = this.getMaxSize(aspectRatio);
-
- int defaultWidth = Math.max(Math.round(maxSize.getWidth() * mDefaultSizePercent),
- minSize.getWidth());
- int defaultHeight = Math.round(defaultWidth / aspectRatio);
-
- return new Size(defaultWidth, defaultHeight);
- }
-
- /**
- * Decreases the dimensions by a certain percentage relative to max size to get min size.
- *
- * @param aspectRatio aspect ratio of the PIP window
- * @return dimensions of the min size of the PIP
- */
- @Override
- public Size getMinSize(float aspectRatio) {
- // if there is an overridden min size provided, return that
- if (mOverrideMinSize != null) {
- return adjustOverrideMinSizeToAspectRatio(aspectRatio);
- }
-
- Size maxSize = this.getMaxSize(aspectRatio);
-
- int minWidth = Math.round(maxSize.getWidth() * mMinimumSizePercent);
- int minHeight = Math.round(maxSize.getHeight() * mMinimumSizePercent);
-
- // make sure the calculated min size is not smaller than the allowed default min size
- if (aspectRatio > 1f) {
- minHeight = Math.max(minHeight, mDefaultMinSize);
- minWidth = Math.round(minHeight * aspectRatio);
- } else {
- minWidth = Math.max(minWidth, mDefaultMinSize);
- minHeight = Math.round(minWidth / aspectRatio);
- }
- return new Size(minWidth, minHeight);
- }
-
- /**
- * Returns the size for target aspect ratio making sure new size conforms with the rules.
- *
- * <p>Recalculates the dimensions such that the target aspect ratio is achieved, while
- * maintaining the same maximum size to current size ratio.
- *
- * @param size current size
- * @param aspectRatio target aspect ratio
- */
- @Override
- public Size getSizeForAspectRatio(Size size, float aspectRatio) {
- float currAspectRatio = (float) size.getWidth() / size.getHeight();
-
- // getting the percentage of the max size that current size takes
- Size currentMaxSize = getMaxSize(currAspectRatio);
- float currentPercent = (float) size.getWidth() / currentMaxSize.getWidth();
-
- // getting the max size for the target aspect ratio
- Size updatedMaxSize = getMaxSize(aspectRatio);
-
- int width = Math.round(updatedMaxSize.getWidth() * currentPercent);
- int height = Math.round(updatedMaxSize.getHeight() * currentPercent);
-
- // adjust the dimensions if below allowed min edge size
- if (width < getMinEdgeSize() && aspectRatio <= 1) {
- width = getMinEdgeSize();
- height = Math.round(width / aspectRatio);
- } else if (height < getMinEdgeSize() && aspectRatio > 1) {
- height = getMinEdgeSize();
- width = Math.round(height * aspectRatio);
- }
-
- // reduce the dimensions of the updated size to the calculated percentage
- return new Size(width, height);
- }
- }
-
- private class SizeSpecDefaultImpl implements SizeSpecSource {
- private float mDefaultSizePercent;
- private float mMinimumSizePercent;
-
- @Override
- public void reloadResources() {
- final Resources res = mContext.getResources();
-
- mMaxAspectRatioForMinSize = res.getFloat(
- R.dimen.config_pictureInPictureAspectRatioLimitForMinSize);
- mMinAspectRatioForMinSize = 1f / mMaxAspectRatioForMinSize;
-
- mDefaultSizePercent = res.getFloat(R.dimen.config_pictureInPictureDefaultSizePercent);
- mMinimumSizePercent = res.getFraction(R.fraction.config_pipShortestEdgePercent, 1, 1);
- }
-
- @Override
- public Size getMaxSize(float aspectRatio) {
- final int shorterLength = Math.min(getDisplayBounds().width(),
- getDisplayBounds().height());
-
- final int totalHorizontalPadding = getInsetBounds().left
- + (getDisplayBounds().width() - getInsetBounds().right);
- final int totalVerticalPadding = getInsetBounds().top
- + (getDisplayBounds().height() - getInsetBounds().bottom);
-
- final int maxWidth, maxHeight;
-
- if (aspectRatio > 1f) {
- maxWidth = (int) Math.max(getDefaultSize(aspectRatio).getWidth(),
- shorterLength - totalHorizontalPadding);
- maxHeight = (int) (maxWidth / aspectRatio);
- } else {
- maxHeight = (int) Math.max(getDefaultSize(aspectRatio).getHeight(),
- shorterLength - totalVerticalPadding);
- maxWidth = (int) (maxHeight * aspectRatio);
- }
-
- return new Size(maxWidth, maxHeight);
- }
-
- @Override
- public Size getDefaultSize(float aspectRatio) {
- if (mOverrideMinSize != null) {
- return this.getMinSize(aspectRatio);
- }
-
- final int smallestDisplaySize = Math.min(getDisplayBounds().width(),
- getDisplayBounds().height());
- final int minSize = (int) Math.max(getMinEdgeSize(),
- smallestDisplaySize * mDefaultSizePercent);
-
- final int width;
- final int height;
-
- if (aspectRatio <= mMinAspectRatioForMinSize
- || aspectRatio > mMaxAspectRatioForMinSize) {
- // Beyond these points, we can just use the min size as the shorter edge
- if (aspectRatio <= 1) {
- // Portrait, width is the minimum size
- width = minSize;
- height = Math.round(width / aspectRatio);
- } else {
- // Landscape, height is the minimum size
- height = minSize;
- width = Math.round(height * aspectRatio);
- }
- } else {
- // Within these points, ensure that the bounds fit within the radius of the limits
- // at the points
- final float widthAtMaxAspectRatioForMinSize = mMaxAspectRatioForMinSize * minSize;
- final float radius = PointF.length(widthAtMaxAspectRatioForMinSize, minSize);
- height = (int) Math.round(Math.sqrt((radius * radius)
- / (aspectRatio * aspectRatio + 1)));
- width = Math.round(height * aspectRatio);
- }
-
- return new Size(width, height);
- }
-
- @Override
- public Size getMinSize(float aspectRatio) {
- if (mOverrideMinSize != null) {
- return adjustOverrideMinSizeToAspectRatio(aspectRatio);
- }
-
- final int shorterLength = Math.min(getDisplayBounds().width(),
- getDisplayBounds().height());
- final int minWidth, minHeight;
-
- if (aspectRatio > 1f) {
- minWidth = (int) Math.min(getDefaultSize(aspectRatio).getWidth(),
- shorterLength * mMinimumSizePercent);
- minHeight = (int) (minWidth / aspectRatio);
- } else {
- minHeight = (int) Math.min(getDefaultSize(aspectRatio).getHeight(),
- shorterLength * mMinimumSizePercent);
- minWidth = (int) (minHeight * aspectRatio);
- }
-
- return new Size(minWidth, minHeight);
- }
-
- @Override
- public Size getSizeForAspectRatio(Size size, float aspectRatio) {
- final int smallestSize = Math.min(size.getWidth(), size.getHeight());
- final int minSize = Math.max(getMinEdgeSize(), smallestSize);
-
- final int width;
- final int height;
- if (aspectRatio <= 1) {
- // Portrait, width is the minimum size.
- width = minSize;
- height = Math.round(width / aspectRatio);
- } else {
- // Landscape, height is the minimum size
- height = minSize;
- width = Math.round(height * aspectRatio);
- }
-
- return new Size(width, height);
- }
- }
-
- public PipSizeSpecHandler(Context context, PipDisplayLayoutState pipDisplayLayoutState) {
- mContext = context;
- mPipDisplayLayoutState = pipDisplayLayoutState;
-
- // choose between two implementations of size spec logic
- if (supportsPipSizeLargeScreen()) {
- mSizeSpecSourceImpl = new SizeSpecLargeScreenOptimizedImpl();
- } else {
- mSizeSpecSourceImpl = new SizeSpecDefaultImpl();
- }
-
- reloadResources();
- }
-
- /** Reloads the resources */
- public void onConfigurationChanged() {
- reloadResources();
- }
-
- private void reloadResources() {
- final Resources res = mContext.getResources();
-
- mDefaultMinSize = res.getDimensionPixelSize(
- R.dimen.default_minimal_size_pip_resizable_task);
- mOverridableMinSize = res.getDimensionPixelSize(
- R.dimen.overridable_minimal_size_pip_resizable_task);
-
- final String screenEdgeInsetsDpString = res.getString(
- R.string.config_defaultPictureInPictureScreenEdgeInsets);
- final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
- ? Size.parseSize(screenEdgeInsetsDpString)
- : null;
- mScreenEdgeInsets = screenEdgeInsetsDp == null ? new Point()
- : new Point(dpToPx(screenEdgeInsetsDp.getWidth(), res.getDisplayMetrics()),
- dpToPx(screenEdgeInsetsDp.getHeight(), res.getDisplayMetrics()));
-
- // update the internal resources of the size spec source's stub
- mSizeSpecSourceImpl.reloadResources();
- }
-
- @NonNull
- private Rect getDisplayBounds() {
- return mPipDisplayLayoutState.getDisplayBounds();
- }
-
- public Point getScreenEdgeInsets() {
- return mScreenEdgeInsets;
- }
-
- /**
- * Returns the inset bounds the PIP window can be visible in.
- */
- public Rect getInsetBounds() {
- Rect insetBounds = new Rect();
- DisplayLayout displayLayout = mPipDisplayLayoutState.getDisplayLayout();
- Rect insets = displayLayout.stableInsets();
- insetBounds.set(insets.left + mScreenEdgeInsets.x,
- insets.top + mScreenEdgeInsets.y,
- displayLayout.width() - insets.right - mScreenEdgeInsets.x,
- displayLayout.height() - insets.bottom - mScreenEdgeInsets.y);
- return insetBounds;
- }
-
- /** Sets the preferred size of PIP as specified by the activity in PIP mode. */
- public void setOverrideMinSize(@Nullable Size overrideMinSize) {
- mOverrideMinSize = overrideMinSize;
- }
-
- /** Returns the preferred minimal size specified by the activity in PIP. */
- @Nullable
- public Size getOverrideMinSize() {
- if (mOverrideMinSize != null
- && (mOverrideMinSize.getWidth() < mOverridableMinSize
- || mOverrideMinSize.getHeight() < mOverridableMinSize)) {
- return new Size(mOverridableMinSize, mOverridableMinSize);
- }
-
- return mOverrideMinSize;
- }
-
- /** Returns the minimum edge size of the override minimum size, or 0 if not set. */
- public int getOverrideMinEdgeSize() {
- if (mOverrideMinSize == null) return 0;
- return Math.min(getOverrideMinSize().getWidth(), getOverrideMinSize().getHeight());
- }
-
- public int getMinEdgeSize() {
- return mOverrideMinSize == null ? mDefaultMinSize : getOverrideMinEdgeSize();
- }
-
- /**
- * Returns the size for the max size spec.
- */
- public Size getMaxSize(float aspectRatio) {
- return mSizeSpecSourceImpl.getMaxSize(aspectRatio);
- }
-
- /**
- * Returns the size for the default size spec.
- */
- public Size getDefaultSize(float aspectRatio) {
- return mSizeSpecSourceImpl.getDefaultSize(aspectRatio);
- }
-
- /**
- * Returns the size for the min size spec.
- */
- public Size getMinSize(float aspectRatio) {
- return mSizeSpecSourceImpl.getMinSize(aspectRatio);
- }
-
- /**
- * Returns the adjusted size so that it conforms to the given aspectRatio.
- *
- * @param size current size
- * @param aspectRatio target aspect ratio
- */
- public Size getSizeForAspectRatio(@NonNull Size size, float aspectRatio) {
- if (size.equals(mOverrideMinSize)) {
- return adjustOverrideMinSizeToAspectRatio(aspectRatio);
- }
-
- return mSizeSpecSourceImpl.getSizeForAspectRatio(size, aspectRatio);
- }
-
- /**
- * Returns the adjusted overridden min size if it is set; otherwise, returns null.
- *
- * <p>Overridden min size needs to be adjusted in its own way while making sure that the target
- * aspect ratio is maintained
- *
- * @param aspectRatio target aspect ratio
- */
- @Nullable
- @VisibleForTesting
- Size adjustOverrideMinSizeToAspectRatio(float aspectRatio) {
- if (mOverrideMinSize == null) {
- return null;
- }
- final Size size = getOverrideMinSize();
- final float sizeAspectRatio = size.getWidth() / (float) size.getHeight();
- if (sizeAspectRatio > aspectRatio) {
- // Size is wider, fix the width and increase the height
- return new Size(size.getWidth(), (int) (size.getWidth() / aspectRatio));
- } else {
- // Size is taller, fix the height and adjust the width.
- return new Size((int) (size.getHeight() * aspectRatio), size.getHeight());
- }
- }
-
- @VisibleForTesting
- boolean supportsPipSizeLargeScreen() {
- // TODO(b/271468706): switch Tv to having a dedicated SizeSpecSource once the SizeSpecSource
- // can be injected
- return SystemProperties
- .getBoolean("persist.wm.debug.enable_pip_size_large_screen", true) && !isTv();
- }
-
- private boolean isTv() {
- return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
- }
-
- /** Dumps internal state. */
- public void dump(PrintWriter pw, String prefix) {
- final String innerPrefix = prefix + " ";
- pw.println(prefix + TAG);
- pw.println(innerPrefix + "mSizeSpecSourceImpl=" + mSizeSpecSourceImpl);
- pw.println(innerPrefix + "mOverrideMinSize=" + mOverrideMinSize);
- pw.println(innerPrefix + "mScreenEdgeInsets=" + mScreenEdgeInsets);
- }
-}
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 372ade333218..3e95498a832b 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
@@ -51,6 +51,7 @@ import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
@@ -85,7 +86,7 @@ public class PipTouchHandler {
private final Context mContext;
private final PipBoundsAlgorithm mPipBoundsAlgorithm;
@NonNull private final PipBoundsState mPipBoundsState;
- @NonNull private final PipSizeSpecHandler mPipSizeSpecHandler;
+ @NonNull private final SizeSpecSource mSizeSpecSource;
private final PipUiEventLogger mPipUiEventLogger;
private final PipDismissTargetHandler mPipDismissTargetHandler;
private final PipTaskOrganizer mPipTaskOrganizer;
@@ -179,7 +180,7 @@ public class PipTouchHandler {
PhonePipMenuController menuController,
PipBoundsAlgorithm pipBoundsAlgorithm,
@NonNull PipBoundsState pipBoundsState,
- @NonNull PipSizeSpecHandler pipSizeSpecHandler,
+ @NonNull SizeSpecSource sizeSpecSource,
PipTaskOrganizer pipTaskOrganizer,
PipMotionHelper pipMotionHelper,
FloatingContentCoordinator floatingContentCoordinator,
@@ -190,7 +191,7 @@ public class PipTouchHandler {
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
mPipBoundsAlgorithm = pipBoundsAlgorithm;
mPipBoundsState = pipBoundsState;
- mPipSizeSpecHandler = pipSizeSpecHandler;
+ mSizeSpecSource = sizeSpecSource;
mPipTaskOrganizer = pipTaskOrganizer;
mMenuController = menuController;
mPipUiEventLogger = pipUiEventLogger;
@@ -413,7 +414,7 @@ public class PipTouchHandler {
// Calculate the expanded size
float aspectRatio = (float) normalBounds.width() / normalBounds.height();
- Size expandedSize = mPipSizeSpecHandler.getDefaultSize(aspectRatio);
+ Size expandedSize = mSizeSpecSource.getDefaultSize(aspectRatio);
mPipBoundsState.setExpandedBounds(
new Rect(0, 0, expandedSize.getWidth(), expandedSize.getHeight()));
Rect expandedMovementBounds = new Rect();
@@ -517,10 +518,10 @@ public class PipTouchHandler {
private void updatePinchResizeSizeConstraints(float aspectRatio) {
final int minWidth, minHeight, maxWidth, maxHeight;
- minWidth = mPipSizeSpecHandler.getMinSize(aspectRatio).getWidth();
- minHeight = mPipSizeSpecHandler.getMinSize(aspectRatio).getHeight();
- maxWidth = mPipSizeSpecHandler.getMaxSize(aspectRatio).getWidth();
- maxHeight = mPipSizeSpecHandler.getMaxSize(aspectRatio).getHeight();
+ minWidth = mSizeSpecSource.getMinSize(aspectRatio).getWidth();
+ minHeight = mSizeSpecSource.getMinSize(aspectRatio).getHeight();
+ maxWidth = mSizeSpecSource.getMaxSize(aspectRatio).getWidth();
+ maxHeight = mSizeSpecSource.getMaxSize(aspectRatio).getHeight();
mPipResizeGestureHandler.updateMinSize(minWidth, minHeight);
mPipResizeGestureHandler.updateMaxSize(maxWidth, maxHeight);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
index 825b96921a22..cd58ff4f5154 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
@@ -36,10 +36,11 @@ import androidx.annotation.NonNull;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
+import com.android.wm.shell.pip.PipDisplayLayoutState;
import com.android.wm.shell.pip.PipKeepClearAlgorithmInterface;
import com.android.wm.shell.pip.PipSnapAlgorithm;
-import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
import com.android.wm.shell.pip.tv.TvPipKeepClearAlgorithm.Placement;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -62,9 +63,10 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm {
public TvPipBoundsAlgorithm(Context context,
@NonNull TvPipBoundsState tvPipBoundsState,
@NonNull PipSnapAlgorithm pipSnapAlgorithm,
- @NonNull PipSizeSpecHandler pipSizeSpecHandler) {
+ @NonNull PipDisplayLayoutState pipDisplayLayoutState,
+ @NonNull SizeSpecSource sizeSpecSource) {
super(context, tvPipBoundsState, pipSnapAlgorithm,
- new PipKeepClearAlgorithmInterface() {}, pipSizeSpecHandler);
+ new PipKeepClearAlgorithmInterface() {}, pipDisplayLayoutState, sizeSpecSource);
this.mTvPipBoundsState = tvPipBoundsState;
this.mKeepClearAlgorithm = new TvPipKeepClearAlgorithm();
reloadResources(context);
@@ -291,7 +293,7 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm {
expandedSize = mTvPipBoundsState.getTvExpandedSize();
} else {
int maxHeight = displayLayout.height()
- - (2 * mPipSizeSpecHandler.getScreenEdgeInsets().y)
+ - (2 * mPipDisplayLayoutState.getScreenEdgeInsets().y)
- pipDecorations.top - pipDecorations.bottom;
float aspectRatioHeight = mFixedExpandedWidthInPx / expandedRatio;
@@ -311,7 +313,7 @@ public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm {
expandedSize = mTvPipBoundsState.getTvExpandedSize();
} else {
int maxWidth = displayLayout.width()
- - (2 * mPipSizeSpecHandler.getScreenEdgeInsets().x)
+ - (2 * mPipDisplayLayoutState.getScreenEdgeInsets().x)
- pipDecorations.left - pipDecorations.right;
float aspectRatioWidth = mFixedExpandedHeightInPx * expandedRatio;
if (maxWidth > aspectRatioWidth) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
index 3f3951a2d4f0..d11f4d59a41d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
@@ -29,10 +29,10 @@ import android.util.Size;
import android.view.Gravity;
import android.view.View;
+import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipDisplayLayoutState;
-import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -76,9 +76,9 @@ public class TvPipBoundsState extends PipBoundsState {
private Insets mPipMenuTemporaryDecorInsets = Insets.NONE;
public TvPipBoundsState(@NonNull Context context,
- @NonNull PipSizeSpecHandler pipSizeSpecHandler,
+ @NonNull SizeSpecSource sizeSpecSource,
@NonNull PipDisplayLayoutState pipDisplayLayoutState) {
- super(context, pipSizeSpecHandler, pipDisplayLayoutState);
+ super(context, sizeSpecSource, pipDisplayLayoutState);
mContext = context;
updateDefaultGravity();
mTvPipGravity = mDefaultGravity;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index 88a81fc291b2..a11d9528a170 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -771,7 +771,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
Slog.e(TAG, "Error sending appeared tasks to recents animation", e);
}
}
- finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ finishCallback.onTransitionFinished(null /* wct */);
}
/** For now, just set-up a jump-cut to the new activity. */
@@ -937,7 +937,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
}
}
cleanUp();
- finishCB.onTransitionFinished(wct.isEmpty() ? null : wct, null /* wctCB */);
+ finishCB.onTransitionFinished(wct.isEmpty() ? null : wct);
}
@Override
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 7699b4bfd13a..5fa26542ee07 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
@@ -423,8 +423,9 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
* transition.
*/
public void prepareExitSplitScreen(WindowContainerTransaction wct,
- @StageType int stageToTop) {
+ @StageType int stageToTop, @ExitReason int reason) {
mStageCoordinator.prepareExitSplitScreen(stageToTop, wct);
+ mStageCoordinator.clearSplitPairedInRecents(reason);
}
public void enterSplitScreen(int taskId, boolean leftOrTop) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index d21f8a48e62a..99be5b8ee861 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -43,7 +43,6 @@ import android.window.RemoteTransition;
import android.window.TransitionInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import android.window.WindowContainerTransactionCallback;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.TransactionPool;
@@ -109,7 +108,7 @@ class SplitScreenTransitions {
if (pendingTransition.mCanceled) {
// The pending transition was canceled, so skip playing animation.
startTransaction.apply();
- onFinish(null /* wct */, null /* wctCB */);
+ onFinish(null /* wct */);
return;
}
@@ -211,7 +210,7 @@ class SplitScreenTransitions {
}
}
t.apply();
- onFinish(null /* wct */, null /* wctCB */);
+ onFinish(null /* wct */);
}
/** Play animation for drag divider dismiss transition. */
@@ -238,7 +237,7 @@ class SplitScreenTransitions {
mAnimations.remove(va);
if (animated) {
mTransitions.getMainExecutor().execute(() -> {
- onFinish(null /* wct */, null /* wctCB */);
+ onFinish(null /* wct */);
});
}
});
@@ -250,7 +249,7 @@ class SplitScreenTransitions {
}
}
startTransaction.apply();
- onFinish(null /* wct */, null /* wctCB */);
+ onFinish(null /* wct */);
}
/** Play animation for resize transition. */
@@ -283,7 +282,7 @@ class SplitScreenTransitions {
mAnimations.remove(va);
if (animated) {
mTransitions.getMainExecutor().execute(() -> {
- onFinish(null /* wct */, null /* wctCB */);
+ onFinish(null /* wct */);
});
}
});
@@ -291,7 +290,7 @@ class SplitScreenTransitions {
}
startTransaction.apply();
- onFinish(null /* wct */, null /* wctCB */);
+ onFinish(null /* wct */);
}
boolean isPendingTransition(IBinder transition) {
@@ -391,7 +390,7 @@ class SplitScreenTransitions {
if (mPendingResize != null) {
mPendingResize.cancel(null);
mAnimations.clear();
- onFinish(null /* wct */, null /* wctCB */);
+ onFinish(null /* wct */);
}
IBinder transition = mTransitions.startTransition(TRANSIT_CHANGE, wct, handler);
@@ -450,7 +449,7 @@ class SplitScreenTransitions {
}
}
- void onFinish(WindowContainerTransaction wct, WindowContainerTransactionCallback wctCB) {
+ void onFinish(WindowContainerTransaction wct) {
if (!mAnimations.isEmpty()) return;
if (wct == null) wct = new WindowContainerTransaction();
@@ -470,7 +469,7 @@ class SplitScreenTransitions {
mOnFinish.run();
if (mFinishCallback != null) {
- mFinishCallback.onTransitionFinished(wct /* wct */, wctCB /* wctCB */);
+ mFinishCallback.onTransitionFinished(wct /* wct */);
mFinishCallback = null;
}
}
@@ -495,7 +494,7 @@ class SplitScreenTransitions {
mTransactionPool.release(transaction);
mTransitions.getMainExecutor().execute(() -> {
mAnimations.remove(va);
- onFinish(null /* wct */, null /* wctCB */);
+ onFinish(null /* wct */);
});
}
});
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 7d62f58014f0..3758b6890f48 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
@@ -83,7 +83,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
-import android.content.res.Configuration;
import android.graphics.Rect;
import android.hardware.devicestate.DeviceStateManager;
import android.os.Bundle;
@@ -1494,7 +1493,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
}
- private void clearSplitPairedInRecents(@ExitReason int exitReason) {
+ void clearSplitPairedInRecents(@ExitReason int exitReason) {
if (!shouldBreakPairedTaskInRecents(exitReason) || !mShouldUpdateRecents) return;
mRecentTasks.ifPresent(recentTasks -> {
@@ -1779,8 +1778,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mRootTaskInfo = taskInfo;
if (mSplitLayout != null
&& mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)
- && mMainStage.isActive()
- && !ENABLE_SHELL_TRANSITIONS) {
+ && mMainStage.isActive()) {
// Clear the divider remote animating flag as the divider will be re-rendered to apply
// the new rotation config.
mIsDividerRemoteAnimating = false;
@@ -2218,20 +2216,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mDisplayController.addDisplayChangingController(this::onDisplayChange);
}
- @Override
- public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
- if (displayId != DEFAULT_DISPLAY) {
- return;
- }
- if (mSplitLayout != null && mSplitLayout.isDensityChanged(newConfig.densityDpi)
- && mMainStage.isActive()
- && mSplitLayout.updateConfiguration(newConfig)
- && ENABLE_SHELL_TRANSITIONS) {
- mSplitLayout.update(null /* t */);
- onLayoutSizeChanged(mSplitLayout);
- }
- }
-
/**
* Update surfaces of the split screen layout based on the current state
* @param transaction to write the updates to
@@ -2736,7 +2720,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
== TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE) {
// Open to side should only be used when split already active and foregorund.
if (mainChild == null && sideChild == null) {
- Log.w(TAG, "Launched a task in split, but didn't receive any task in transition.");
+ Log.w(TAG, splitFailureMessage("startPendingEnterAnimation",
+ "Launched a task in split, but didn't receive any task in transition."));
// This should happen when the target app is already on front, so just cancel.
mSplitTransitions.mPendingEnter.cancel(null);
return true;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
index a743e99d6954..adae21b20b3c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java
@@ -94,9 +94,11 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
mShellExecutor = organizer.getExecutor();
mSyncQueue = syncQueue;
mTaskViewTransitions = taskViewTransitions;
- if (mTaskViewTransitions != null) {
- mTaskViewTransitions.addTaskView(this);
- }
+ mShellExecutor.execute(() -> {
+ if (mTaskViewTransitions != null) {
+ mTaskViewTransitions.addTaskView(this);
+ }
+ });
mGuard.open("release");
}
@@ -225,10 +227,10 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
}
private void performRelease() {
- if (mTaskViewTransitions != null) {
- mTaskViewTransitions.removeTaskView(this);
- }
mShellExecutor.execute(() -> {
+ if (mTaskViewTransitions != null) {
+ mTaskViewTransitions.removeTaskView(this);
+ }
mTaskOrganizer.removeListener(this);
resetTaskInfo();
});
@@ -410,9 +412,12 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
if (mTaskToken == null) {
return;
}
- // Sync Transactions can't operate simultaneously with shell transition collection.
+
if (isUsingShellTransitions()) {
- mTaskViewTransitions.setTaskBounds(this, boundsOnScreen);
+ mShellExecutor.execute(() -> {
+ // Sync Transactions can't operate simultaneously with shell transition collection.
+ mTaskViewTransitions.setTaskBounds(this, boundsOnScreen);
+ });
return;
}
@@ -430,9 +435,11 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener {
Slog.w(TAG, "Trying to remove a task that was never added? (no taskToken)");
return;
}
- WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.removeTask(mTaskToken);
- mTaskViewTransitions.closeTaskView(wct, this);
+ mShellExecutor.execute(() -> {
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.removeTask(mTaskToken);
+ mTaskViewTransitions.closeTaskView(wct, this);
+ });
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
index daf8be60651a..e03f82526bdb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
@@ -390,7 +390,7 @@ public class TaskViewTransitions implements Transitions.TransitionHandler {
}
// No animation, just show it immediately.
startTransaction.apply();
- finishCallback.onTransitionFinished(wct, null /* wctCB */);
+ finishCallback.onTransitionFinished(wct);
startNextTransition();
return true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 052af3af98cc..986560bd6053 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -40,7 +40,6 @@ import android.view.WindowManager;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
-import android.window.WindowContainerTransactionCallback;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.split.SplitScreenUtils;
@@ -124,14 +123,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
mTransition = transition;
}
- void joinFinishArgs(WindowContainerTransaction wct,
- WindowContainerTransactionCallback wctCB) {
- if (wctCB != null) {
- // Technically can probably support 1, but don't want to encourage CB usage since
- // it creates instabliity, so just throw.
- throw new IllegalArgumentException("Can't mix transitions that require finish"
- + " sync callback");
- }
+ void joinFinishArgs(WindowContainerTransaction wct) {
if (wct != null) {
if (mFinishWCT == null) {
mFinishWCT = wct;
@@ -389,12 +381,12 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
info.getChanges().remove(i);
}
}
- Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
+ Transitions.TransitionFinishCallback finishCB = (wct) -> {
--mixed.mInFlightSubAnimations;
- mixed.joinFinishArgs(wct, wctCB);
+ mixed.joinFinishArgs(wct);
if (mixed.mInFlightSubAnimations > 0) return;
mActiveTransitions.remove(mixed);
- finishCallback.onTransitionFinished(mixed.mFinishWCT, wctCB);
+ finishCallback.onTransitionFinished(mixed.mFinishWCT);
};
if (pipChange == null) {
if (mixed.mLeftoversHandler != null) {
@@ -461,15 +453,15 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
return false;
}
final boolean isGoingHome = homeIsOpening;
- Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
+ Transitions.TransitionFinishCallback finishCB = (wct) -> {
--mixed.mInFlightSubAnimations;
- mixed.joinFinishArgs(wct, wctCB);
+ mixed.joinFinishArgs(wct);
if (mixed.mInFlightSubAnimations > 0) return;
mActiveTransitions.remove(mixed);
if (isGoingHome) {
mSplitHandler.onTransitionAnimationComplete();
}
- finishCallback.onTransitionFinished(mixed.mFinishWCT, wctCB);
+ finishCallback.onTransitionFinished(mixed.mFinishWCT);
};
if (isGoingHome || mSplitHandler.getSplitItemPosition(pipChange.getLastParent())
!= SPLIT_POSITION_UNDEFINED) {
@@ -586,12 +578,12 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
// We need to split the transition into 2 parts: the split part and the display part.
mixed.mInFlightSubAnimations = 2;
- Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
+ Transitions.TransitionFinishCallback finishCB = (wct) -> {
--mixed.mInFlightSubAnimations;
- mixed.joinFinishArgs(wct, wctCB);
+ mixed.joinFinishArgs(wct);
if (mixed.mInFlightSubAnimations > 0) return;
mActiveTransitions.remove(mixed);
- finishCallback.onTransitionFinished(mixed.mFinishWCT, null /* wctCB */);
+ finishCallback.onTransitionFinished(mixed.mFinishWCT);
};
// Dispatch the display change. This will most-likely be taken by the default handler.
@@ -614,7 +606,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
// Split-screen is only interested in the recents transition finishing (and merging), so
// just wrap finish and start recents animation directly.
- Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
+ Transitions.TransitionFinishCallback finishCB = (wct) -> {
mixed.mInFlightSubAnimations = 0;
mActiveTransitions.remove(mixed);
// If pair-to-pair switching, the post-recents clean-up isn't needed.
@@ -626,7 +618,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
mSplitHandler.onRecentsPairToPairAnimationFinish(wct);
}
mSplitHandler.onTransitionAnimationComplete();
- finishCallback.onTransitionFinished(wct, wctCB);
+ finishCallback.onTransitionFinished(wct);
};
mixed.mInFlightSubAnimations = 1;
mSplitHandler.onRecentsInSplitAnimationStart(info);
@@ -644,11 +636,11 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
- final Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
+ final Transitions.TransitionFinishCallback finishCB = (wct) -> {
mixed.mInFlightSubAnimations--;
if (mixed.mInFlightSubAnimations == 0) {
mActiveTransitions.remove(mixed);
- finishCallback.onTransitionFinished(wct, wctCB);
+ finishCallback.onTransitionFinished(wct);
}
};
mixed.mInFlightSubAnimations++;
@@ -693,11 +685,11 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
- final Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> {
+ final Transitions.TransitionFinishCallback finishCB = (wct) -> {
mixed.mInFlightSubAnimations--;
if (mixed.mInFlightSubAnimations > 0) return;
mActiveTransitions.remove(mixed);
- finishCallback.onTransitionFinished(wct, wctCB);
+ finishCallback.onTransitionFinished(wct);
};
mixed.mInFlightSubAnimations = 1;
// Sync pip state.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index dc78c9b139f9..7df658e6c9db 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -300,7 +300,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
// immediately finishes since there is no animation for screen-wake.
if (info.getType() == WindowManager.TRANSIT_WAKE && !info.isKeyguardGoingAway()) {
startTransaction.apply();
- finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ finishCallback.onTransitionFinished(null /* wct */);
return true;
}
@@ -309,7 +309,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
|| (info.getFlags() & WindowManager.TRANSIT_FLAG_INVISIBLE) != 0) {
startTransaction.apply();
finishTransaction.apply();
- finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ finishCallback.onTransitionFinished(null /* wct */);
return true;
}
@@ -323,7 +323,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
final Runnable onAnimFinish = () -> {
if (!animations.isEmpty()) return;
mAnimations.remove(transition);
- finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ finishCallback.onTransitionFinished(null /* wct */);
};
final List<Consumer<SurfaceControl.Transaction>> postStartTransactionCallbacks =
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
index 4e3d220f1ea2..fab2dd2bf3e1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
@@ -68,7 +68,7 @@ public class OneShotRemoteHandler implements Transitions.TransitionHandler {
final IBinder.DeathRecipient remoteDied = () -> {
Log.e(Transitions.TAG, "Remote transition died, finishing");
mMainExecutor.execute(
- () -> finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */));
+ () -> finishCallback.onTransitionFinished(null /* wct */));
};
IRemoteTransitionFinishedCallback cb = new IRemoteTransitionFinishedCallback.Stub() {
@Override
@@ -81,7 +81,7 @@ public class OneShotRemoteHandler implements Transitions.TransitionHandler {
finishTransaction.merge(sct);
}
mMainExecutor.execute(() -> {
- finishCallback.onTransitionFinished(wct, null /* wctCB */);
+ finishCallback.onTransitionFinished(wct);
});
}
};
@@ -104,7 +104,7 @@ public class OneShotRemoteHandler implements Transitions.TransitionHandler {
if (mRemote.asBinder() != null) {
mRemote.asBinder().unlinkToDeath(remoteDied, 0 /* flags */);
}
- finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ finishCallback.onTransitionFinished(null /* wct */);
}
return true;
}
@@ -122,8 +122,7 @@ public class OneShotRemoteHandler implements Transitions.TransitionHandler {
// remote applied the transaction, but applying twice will break surfaceflinger
// so just assume the worst-case and clear the local transaction.
t.clear();
- mMainExecutor.execute(
- () -> finishCallback.onTransitionFinished(wct, null /* wctCB */));
+ mMainExecutor.execute(() -> finishCallback.onTransitionFinished(wct));
}
};
try {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
index c22cc6fbea8f..bbf67a6155d7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
@@ -133,7 +133,7 @@ public class RemoteTransitionHandler implements Transitions.TransitionHandler {
}
mMainExecutor.execute(() -> {
mRequestedRemotes.remove(transition);
- finishCallback.onTransitionFinished(wct, null /* wctCB */);
+ finishCallback.onTransitionFinished(wct);
});
}
};
@@ -153,8 +153,7 @@ public class RemoteTransitionHandler implements Transitions.TransitionHandler {
Log.e(Transitions.TAG, "Error running remote transition.", e);
unhandleDeath(remote.asBinder(), finishCallback);
mRequestedRemotes.remove(transition);
- mMainExecutor.execute(
- () -> finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */));
+ mMainExecutor.execute(() -> finishCallback.onTransitionFinished(null /* wct */));
}
return true;
}
@@ -210,7 +209,7 @@ public class RemoteTransitionHandler implements Transitions.TransitionHandler {
+ "that the mergeTarget's RemoteTransition impl erroneously "
+ "accepted/ran the merge request after finishing the mergeTarget");
}
- finishCallback.onTransitionFinished(wct, null /* wctCB */);
+ finishCallback.onTransitionFinished(wct);
});
}
};
@@ -316,8 +315,7 @@ public class RemoteTransitionHandler implements Transitions.TransitionHandler {
}
}
for (int i = mPendingFinishCallbacks.size() - 1; i >= 0; --i) {
- mPendingFinishCallbacks.get(i).onTransitionFinished(
- null /* wct */, null /* wctCB */);
+ mPendingFinishCallbacks.get(i).onTransitionFinished(null /* wct */);
}
mPendingFinishCallbacks.clear();
});
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SleepHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SleepHandler.java
index d2795959494a..87c438a5b37d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SleepHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SleepHandler.java
@@ -43,7 +43,7 @@ class SleepHandler implements Transitions.TransitionHandler {
@NonNull Transitions.TransitionFinishCallback finishCallback) {
mSleepTransitions.remove(transition);
startTransaction.apply();
- finishCallback.onTransitionFinished(null, null);
+ finishCallback.onTransitionFinished(null);
return true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index e2dce88d5958..b4d0a31dc8c1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -62,7 +62,6 @@ import android.window.TransitionInfo;
import android.window.TransitionMetrics;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
-import android.window.WindowContainerTransactionCallback;
import android.window.WindowOrganizer;
import androidx.annotation.BinderThread;
@@ -829,7 +828,7 @@ public class Transitions implements RemoteCallable<Transitions>,
ready.mStartT.apply();
}
// finish now since there's nothing to animate. Calls back into processReadyQueue
- onFinish(ready, null, null);
+ onFinish(ready, null);
return;
}
playTransition(ready);
@@ -849,7 +848,7 @@ public class Transitions implements RemoteCallable<Transitions>,
+ " in case they can be merged", ready, playing);
mTracer.logMergeRequested(ready.mInfo.getDebugId(), playing.mInfo.getDebugId());
playing.mHandler.mergeAnimation(ready.mToken, ready.mInfo, ready.mStartT,
- playing.mToken, (wct, cb) -> onMerged(playing, ready));
+ playing.mToken, (wct) -> onMerged(playing, ready));
}
private void onMerged(@NonNull ActiveTransition playing, @NonNull ActiveTransition merged) {
@@ -899,7 +898,7 @@ public class Transitions implements RemoteCallable<Transitions>,
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " try firstHandler %s",
active.mHandler);
boolean consumed = active.mHandler.startAnimation(active.mToken, active.mInfo,
- active.mStartT, active.mFinishT, (wct, cb) -> onFinish(active, wct, cb));
+ active.mStartT, active.mFinishT, (wct) -> onFinish(active, wct));
if (consumed) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " animated by firstHandler");
mTracer.logDispatched(active.mInfo.getDebugId(), active.mHandler);
@@ -908,7 +907,7 @@ public class Transitions implements RemoteCallable<Transitions>,
}
// Otherwise give every other handler a chance
active.mHandler = dispatchTransition(active.mToken, active.mInfo, active.mStartT,
- active.mFinishT, (wct, cb) -> onFinish(active, wct, cb), active.mHandler);
+ active.mFinishT, (wct) -> onFinish(active, wct), active.mHandler);
}
/**
@@ -985,8 +984,7 @@ public class Transitions implements RemoteCallable<Transitions>,
}
private void onFinish(ActiveTransition active,
- @Nullable WindowContainerTransaction wct,
- @Nullable WindowContainerTransactionCallback wctCB) {
+ @Nullable WindowContainerTransaction wct) {
final Track track = mTracks.get(active.getTrack());
if (track.mActiveTransition != active) {
Log.e(TAG, "Trying to finish a non-running transition. Either remote crashed or "
@@ -1035,11 +1033,11 @@ public class Transitions implements RemoteCallable<Transitions>,
// Now perform all the finish callbacks (starting with the playing one and then all the
// transitions merged into it).
releaseSurfaces(active.mInfo);
- mOrganizer.finishTransition(active.mToken, wct, wctCB);
+ mOrganizer.finishTransition(active.mToken, wct);
if (active.mMerged != null) {
for (int iM = 0; iM < active.mMerged.size(); ++iM) {
ActiveTransition merged = active.mMerged.get(iM);
- mOrganizer.finishTransition(merged.mToken, null /* wct */, null /* wctCB */);
+ mOrganizer.finishTransition(merged.mToken, null /* wct */);
releaseSurfaces(merged.mInfo);
}
active.mMerged.clear();
@@ -1178,7 +1176,7 @@ public class Transitions implements RemoteCallable<Transitions>,
forceFinish.mHandler.onTransitionConsumed(
forceFinish.mToken, true /* aborted */, null /* finishTransaction */);
}
- onFinish(forceFinish, null, null);
+ onFinish(forceFinish, null);
}
}
if (track.isIdle() || mReadyDuringSync.isEmpty()) {
@@ -1198,7 +1196,7 @@ public class Transitions implements RemoteCallable<Transitions>,
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Attempt to merge sync %s"
+ " into %s via a SLEEP proxy", nextSync, playing);
playing.mHandler.mergeAnimation(nextSync.mToken, dummyInfo, dummyT,
- playing.mToken, (wct, cb) -> {});
+ playing.mToken, (wct) -> {});
// it's possible to complete immediately. If that happens, just repeat the signal
// loop until we either finish everything or start playing an animation that isn't
// finishing immediately.
@@ -1226,11 +1224,8 @@ public class Transitions implements RemoteCallable<Transitions>,
* The transition must not touch the surfaces after this has been called.
*
* @param wct A WindowContainerTransaction to run along with the transition clean-up.
- * @param wctCB A sync callback that will be run when the transition clean-up is done and
- * wct has been applied.
*/
- void onTransitionFinished(@Nullable WindowContainerTransaction wct,
- @Nullable WindowContainerTransactionCallback wctCB);
+ void onTransitionFinished(@Nullable WindowContainerTransaction wct);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
index f148412205bf..2eb6e71456db 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
@@ -169,7 +169,7 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene
animator.stop();
}
- mFinishCallback.onTransitionFinished(null, null);
+ mFinishCallback.onTransitionFinished(null);
mFinishCallback = null;
mTransition = null;
}
@@ -193,7 +193,7 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene
}
// Apply changes happening during the unfold animation immediately
t.apply();
- finishCallback.onTransitionFinished(null, null);
+ finishCallback.onTransitionFinished(null);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
index fb05c696af82..c9c58de6e82a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
@@ -168,7 +168,7 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback,
startTransaction.apply();
mDesktopWindowDecoration.hideResizeVeil();
mCtrlType = CTRL_TYPE_UNDEFINED;
- finishCallback.onTransitionFinished(null, null);
+ finishCallback.onTransitionFinished(null);
return true;
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
index de64f78a31eb..cb5a60d9746b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
@@ -17,6 +17,7 @@
package com.android.wm.shell.flicker.pip
import android.graphics.Rect
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
@@ -34,6 +35,7 @@ import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
/** Test the snapping of a PIP window via dragging, releasing, and checking its final location. */
+@FlakyTest(bugId = 294993100)
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
index 4fca8b46a069..2d9304705738 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java
@@ -92,7 +92,7 @@ public class ActivityEmbeddingAnimationRunnerTests extends ActivityEmbeddingAnim
.build();
final Animator animator = mAnimRunner.createAnimator(
info, mStartTransaction, mFinishTransaction,
- () -> mFinishCallback.onTransitionFinished(null /* wct */, null /* wctCB */),
+ () -> mFinishCallback.onTransitionFinished(null /* wct */),
new ArrayList());
// The animation should be empty when it is behind starting window.
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java
index ab1ccd4599a2..0b2265d4ce9c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationTestBase.java
@@ -75,7 +75,7 @@ abstract class ActivityEmbeddingAnimationTestBase extends ShellTestCase {
assertNotNull(mAnimRunner);
mAnimSpec = mAnimRunner.mAnimationSpec;
assertNotNull(mAnimSpec);
- mFinishCallback = (wct, wctCB) -> {};
+ mFinishCallback = (wct) -> {};
spyOn(mController);
spyOn(mAnimRunner);
spyOn(mAnimSpec);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java
index ba34f1f74cd3..270dbc49835f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java
@@ -217,12 +217,10 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation
doReturn(animator).when(mAnimRunner).createAnimator(any(), any(), any(), any(), any());
mController.startAnimation(mTransition, info, mStartTransaction,
mFinishTransaction, mFinishCallback);
- verify(mFinishCallback, never()).onTransitionFinished(any(), any());
+ verify(mFinishCallback, never()).onTransitionFinished(any());
mController.mergeAnimation(mTransition, info, new SurfaceControl.Transaction(),
- mTransition,
- (wct, cb) -> {
- });
- verify(mFinishCallback).onTransitionFinished(any(), any());
+ mTransition, (wct) -> {});
+ verify(mFinishCallback).onTransitionFinished(any());
}
@Test
@@ -238,9 +236,9 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation
mController.startAnimation(mTransition, info, mStartTransaction,
mFinishTransaction, mFinishCallback);
- verify(mFinishCallback, never()).onTransitionFinished(any(), any());
+ verify(mFinishCallback, never()).onTransitionFinished(any());
mController.onAnimationFinished(mTransition);
- verify(mFinishCallback).onTransitionFinished(any(), any());
+ verify(mFinishCallback).onTransitionFinished(any());
// Should not call finish when the finish has already been called.
assertThrows(IllegalStateException.class,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java
new file mode 100644
index 000000000000..139724f709c7
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.bubbles;
+
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.view.View.LAYOUT_DIRECTION_LTR;
+import static android.view.View.LAYOUT_DIRECTION_RTL;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.res.Configuration;
+import android.graphics.Insets;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableResources;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.view.WindowMetrics;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests operations and the resulting state managed by {@link BubblePositioner}.
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class BubblePositionerTest extends ShellTestCase {
+
+ private static final int MIN_WIDTH_FOR_TABLET = 600;
+
+ private BubblePositioner mPositioner;
+ private Configuration mConfiguration;
+
+ @Mock
+ private WindowManager mWindowManager;
+ @Mock
+ private WindowMetrics mWindowMetrics;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mConfiguration = spy(new Configuration());
+ TestableResources testableResources = mContext.getOrCreateTestableResources();
+ testableResources.overrideConfiguration(mConfiguration);
+
+ mPositioner = new BubblePositioner(mContext, mWindowManager);
+ }
+
+ @Test
+ public void testUpdate() {
+ Insets insets = Insets.of(10, 20, 5, 15);
+ Rect screenBounds = new Rect(0, 0, 1000, 1200);
+ Rect availableRect = new Rect(screenBounds);
+ availableRect.inset(insets);
+
+ new WindowManagerConfig()
+ .setInsets(insets)
+ .setScreenBounds(screenBounds)
+ .setUpConfig();
+ mPositioner.update();
+
+ assertThat(mPositioner.getAvailableRect()).isEqualTo(availableRect);
+ assertThat(mPositioner.isLandscape()).isFalse();
+ assertThat(mPositioner.isLargeScreen()).isFalse();
+ assertThat(mPositioner.getInsets()).isEqualTo(insets);
+ }
+
+ @Test
+ public void testShowBubblesVertically_phonePortrait() {
+ new WindowManagerConfig().setOrientation(ORIENTATION_PORTRAIT).setUpConfig();
+ mPositioner.update();
+
+ assertThat(mPositioner.showBubblesVertically()).isFalse();
+ }
+
+ @Test
+ public void testShowBubblesVertically_phoneLandscape() {
+ new WindowManagerConfig().setOrientation(ORIENTATION_LANDSCAPE).setUpConfig();
+ mPositioner.update();
+
+ assertThat(mPositioner.isLandscape()).isTrue();
+ assertThat(mPositioner.showBubblesVertically()).isTrue();
+ }
+
+ @Test
+ public void testShowBubblesVertically_tablet() {
+ new WindowManagerConfig().setLargeScreen().setUpConfig();
+ mPositioner.update();
+
+ assertThat(mPositioner.showBubblesVertically()).isTrue();
+ }
+
+ /** If a resting position hasn't been set, calling it will return the default position. */
+ @Test
+ public void testGetRestingPosition_returnsDefaultPosition() {
+ new WindowManagerConfig().setUpConfig();
+ mPositioner.update();
+
+ PointF restingPosition = mPositioner.getRestingPosition();
+ PointF defaultPosition = mPositioner.getDefaultStartPosition();
+
+ assertThat(restingPosition).isEqualTo(defaultPosition);
+ }
+
+ /** If a resting position has been set, it'll return that instead of the default position. */
+ @Test
+ public void testGetRestingPosition_returnsRestingPosition() {
+ new WindowManagerConfig().setUpConfig();
+ mPositioner.update();
+
+ PointF restingPosition = new PointF(100, 100);
+ mPositioner.setRestingPosition(restingPosition);
+
+ assertThat(mPositioner.getRestingPosition()).isEqualTo(restingPosition);
+ }
+
+ /** Test that the default resting position on phone is in upper left. */
+ @Test
+ public void testGetRestingPosition_bubble_onPhone() {
+ new WindowManagerConfig().setUpConfig();
+ mPositioner.update();
+
+ RectF allowableStackRegion =
+ mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
+ PointF restingPosition = mPositioner.getRestingPosition();
+
+ assertThat(restingPosition.x).isEqualTo(allowableStackRegion.left);
+ assertThat(restingPosition.y).isEqualTo(getDefaultYPosition());
+ }
+
+ @Test
+ public void testGetRestingPosition_bubble_onPhone_RTL() {
+ new WindowManagerConfig().setLayoutDirection(LAYOUT_DIRECTION_RTL).setUpConfig();
+ mPositioner.update();
+
+ RectF allowableStackRegion =
+ mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
+ PointF restingPosition = mPositioner.getRestingPosition();
+
+ assertThat(restingPosition.x).isEqualTo(allowableStackRegion.right);
+ assertThat(restingPosition.y).isEqualTo(getDefaultYPosition());
+ }
+
+ /** Test that the default resting position on tablet is middle left. */
+ @Test
+ public void testGetRestingPosition_chatBubble_onTablet() {
+ new WindowManagerConfig().setLargeScreen().setUpConfig();
+ mPositioner.update();
+
+ RectF allowableStackRegion =
+ mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
+ PointF restingPosition = mPositioner.getRestingPosition();
+
+ assertThat(restingPosition.x).isEqualTo(allowableStackRegion.left);
+ assertThat(restingPosition.y).isEqualTo(getDefaultYPosition());
+ }
+
+ @Test
+ public void testGetRestingPosition_chatBubble_onTablet_RTL() {
+ new WindowManagerConfig().setLargeScreen().setLayoutDirection(
+ LAYOUT_DIRECTION_RTL).setUpConfig();
+ mPositioner.update();
+
+ RectF allowableStackRegion =
+ mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
+ PointF restingPosition = mPositioner.getRestingPosition();
+
+ assertThat(restingPosition.x).isEqualTo(allowableStackRegion.right);
+ assertThat(restingPosition.y).isEqualTo(getDefaultYPosition());
+ }
+
+ /**
+ * Calculates the Y position bubbles should be placed based on the config. Based on
+ * the calculations in {@link BubblePositioner#getDefaultStartPosition()} and
+ * {@link BubbleStackView.RelativeStackPosition}.
+ */
+ private float getDefaultYPosition() {
+ final boolean isTablet = mPositioner.isLargeScreen();
+
+ // On tablet the position is centered, on phone it is an offset from the top.
+ final float desiredY = isTablet
+ ? mPositioner.getScreenRect().height() / 2f - (mPositioner.getBubbleSize() / 2f)
+ : mContext.getResources().getDimensionPixelOffset(
+ R.dimen.bubble_stack_starting_offset_y);
+ // Since we're visually centering the bubbles on tablet, use total screen height rather
+ // than the available height.
+ final float height = isTablet
+ ? mPositioner.getScreenRect().height()
+ : mPositioner.getAvailableRect().height();
+ float offsetPercent = desiredY / height;
+ offsetPercent = Math.max(0f, Math.min(1f, offsetPercent));
+ final RectF allowableStackRegion =
+ mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
+ return allowableStackRegion.top + allowableStackRegion.height() * offsetPercent;
+ }
+
+ /**
+ * Sets up window manager to return config values based on what you need for the test.
+ * By default it sets up a portrait phone without any insets.
+ */
+ private class WindowManagerConfig {
+ private Rect mScreenBounds = new Rect(0, 0, 1000, 2000);
+ private boolean mIsLargeScreen = false;
+ private int mOrientation = ORIENTATION_PORTRAIT;
+ private int mLayoutDirection = LAYOUT_DIRECTION_LTR;
+ private Insets mInsets = Insets.of(0, 0, 0, 0);
+
+ public WindowManagerConfig setScreenBounds(Rect screenBounds) {
+ mScreenBounds = screenBounds;
+ return this;
+ }
+
+ public WindowManagerConfig setLargeScreen() {
+ mIsLargeScreen = true;
+ return this;
+ }
+
+ public WindowManagerConfig setOrientation(int orientation) {
+ mOrientation = orientation;
+ return this;
+ }
+
+ public WindowManagerConfig setLayoutDirection(int layoutDirection) {
+ mLayoutDirection = layoutDirection;
+ return this;
+ }
+
+ public WindowManagerConfig setInsets(Insets insets) {
+ mInsets = insets;
+ return this;
+ }
+
+ public void setUpConfig() {
+ mConfiguration.smallestScreenWidthDp = mIsLargeScreen
+ ? MIN_WIDTH_FOR_TABLET
+ : MIN_WIDTH_FOR_TABLET - 1;
+ mConfiguration.orientation = mOrientation;
+
+ when(mConfiguration.getLayoutDirection()).thenReturn(mLayoutDirection);
+ WindowInsets windowInsets = mock(WindowInsets.class);
+ when(windowInsets.getInsetsIgnoringVisibility(anyInt())).thenReturn(mInsets);
+ when(mWindowMetrics.getWindowInsets()).thenReturn(windowInsets);
+ when(mWindowMetrics.getBounds()).thenReturn(mScreenBounds);
+ when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics);
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
index addc2338144f..bf1b7f9f86ed 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
@@ -32,7 +32,8 @@ import androidx.test.filters.SmallTest;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
+import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
+import com.android.wm.shell.common.pip.SizeSpecSource;
import org.junit.Before;
import org.junit.Test;
@@ -60,7 +61,8 @@ public class PipBoundsAlgorithmTest extends ShellTestCase {
private PipBoundsAlgorithm mPipBoundsAlgorithm;
private DisplayInfo mDefaultDisplayInfo;
- private PipBoundsState mPipBoundsState; private PipSizeSpecHandler mPipSizeSpecHandler;
+ private PipBoundsState mPipBoundsState;
+ private SizeSpecSource mSizeSpecSource;
private PipDisplayLayoutState mPipDisplayLayoutState;
@@ -68,11 +70,12 @@ public class PipBoundsAlgorithmTest extends ShellTestCase {
public void setUp() throws Exception {
initializeMockResources();
mPipDisplayLayoutState = new PipDisplayLayoutState(mContext);
- mPipSizeSpecHandler = new PipSizeSpecHandler(mContext, mPipDisplayLayoutState);
- mPipBoundsState = new PipBoundsState(mContext, mPipSizeSpecHandler, mPipDisplayLayoutState);
+
+ mSizeSpecSource = new PhoneSizeSpecSource(mContext, mPipDisplayLayoutState);
+ mPipBoundsState = new PipBoundsState(mContext, mSizeSpecSource, mPipDisplayLayoutState);
mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState,
new PipSnapAlgorithm(), new PipKeepClearAlgorithmInterface() {},
- mPipSizeSpecHandler);
+ mPipDisplayLayoutState, mSizeSpecSource);
DisplayLayout layout =
new DisplayLayout(mDefaultDisplayInfo, mContext.getResources(), true, true);
@@ -132,7 +135,7 @@ public class PipBoundsAlgorithmTest extends ShellTestCase {
@Test
public void getDefaultBounds_noOverrideMinSize_matchesDefaultSizeAndAspectRatio() {
- final Size defaultSize = mPipSizeSpecHandler.getDefaultSize(DEFAULT_ASPECT_RATIO);
+ final Size defaultSize = mSizeSpecSource.getDefaultSize(DEFAULT_ASPECT_RATIO);
mPipBoundsState.setOverrideMinSize(null);
final Rect defaultBounds = mPipBoundsAlgorithm.getDefaultBounds();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
index f32000445ca9..4341c4c8c8aa 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
@@ -35,7 +35,8 @@ import androidx.test.filters.SmallTest;
import com.android.internal.util.function.TriConsumer;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
+import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
+import com.android.wm.shell.common.pip.SizeSpecSource;
import org.junit.Before;
import org.junit.Test;
@@ -58,6 +59,7 @@ public class PipBoundsStateTest extends ShellTestCase {
private static final int OVERRIDABLE_MIN_SIZE = 40;
private PipBoundsState mPipBoundsState;
+ private SizeSpecSource mSizeSpecSource;
private ComponentName mTestComponentName1;
private ComponentName mTestComponentName2;
@@ -69,8 +71,8 @@ public class PipBoundsStateTest extends ShellTestCase {
OVERRIDABLE_MIN_SIZE);
PipDisplayLayoutState pipDisplayLayoutState = new PipDisplayLayoutState(mContext);
- mPipBoundsState = new PipBoundsState(mContext,
- new PipSizeSpecHandler(mContext, pipDisplayLayoutState), pipDisplayLayoutState);
+ mSizeSpecSource = new PhoneSizeSpecSource(mContext, pipDisplayLayoutState);
+ mPipBoundsState = new PipBoundsState(mContext, mSizeSpecSource, pipDisplayLayoutState);
mTestComponentName1 = new ComponentName(mContext, "component1");
mTestComponentName2 = new ComponentName(mContext, "component2");
}
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 842c699fa42d..1e3fe421140a 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
@@ -52,8 +52,9 @@ import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
+import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.pip.phone.PhonePipMenuController;
-import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
import com.android.wm.shell.splitscreen.SplitScreenController;
import org.junit.Before;
@@ -87,7 +88,7 @@ public class PipTaskOrganizerTest extends ShellTestCase {
private PipBoundsState mPipBoundsState;
private PipTransitionState mPipTransitionState;
private PipBoundsAlgorithm mPipBoundsAlgorithm;
- private PipSizeSpecHandler mPipSizeSpecHandler;
+ private SizeSpecSource mSizeSpecSource;
private PipDisplayLayoutState mPipDisplayLayoutState;
private ComponentName mComponent1;
@@ -99,12 +100,12 @@ public class PipTaskOrganizerTest extends ShellTestCase {
mComponent1 = new ComponentName(mContext, "component1");
mComponent2 = new ComponentName(mContext, "component2");
mPipDisplayLayoutState = new PipDisplayLayoutState(mContext);
- mPipSizeSpecHandler = new PipSizeSpecHandler(mContext, mPipDisplayLayoutState);
- mPipBoundsState = new PipBoundsState(mContext, mPipSizeSpecHandler, mPipDisplayLayoutState);
+ mSizeSpecSource = new PhoneSizeSpecSource(mContext, mPipDisplayLayoutState);
+ mPipBoundsState = new PipBoundsState(mContext, mSizeSpecSource, mPipDisplayLayoutState);
mPipTransitionState = new PipTransitionState();
mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState,
new PipSnapAlgorithm(), new PipKeepClearAlgorithmInterface() {},
- mPipSizeSpecHandler);
+ mPipDisplayLayoutState, mSizeSpecSource);
mMainExecutor = new TestShellExecutor();
mPipTaskOrganizer = new PipTaskOrganizer(mContext, mMockSyncTransactionQueue,
mPipTransitionState, mPipBoundsState, mPipDisplayLayoutState,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhoneSizeSpecSourceTest.java
index 528c23cd8115..024cba319ffc 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhoneSizeSpecSourceTest.java
@@ -32,6 +32,8 @@ import android.view.DisplayInfo;
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
+import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.pip.PipDisplayLayoutState;
import org.junit.After;
@@ -47,10 +49,10 @@ import java.util.Map;
import java.util.function.Function;
/**
- * Unit test against {@link PipSizeSpecHandler} with feature flag on.
+ * Unit test against {@link PhoneSizeSpecSource}
*/
@RunWith(AndroidTestingRunner.class)
-public class PipSizeSpecHandlerTest extends ShellTestCase {
+public class PhoneSizeSpecSourceTest extends ShellTestCase {
/** A sample overridden min edge size. */
private static final int OVERRIDE_MIN_EDGE_SIZE = 40;
/** A sample default min edge size */
@@ -75,7 +77,7 @@ public class PipSizeSpecHandlerTest extends ShellTestCase {
@Mock private Resources mResources;
private PipDisplayLayoutState mPipDisplayLayoutState;
- private TestPipSizeSpecHandler mPipSizeSpecHandler;
+ private SizeSpecSource mSizeSpecSource;
/**
* Sets up static Mockito session for SystemProperties and mocks necessary static methods.
@@ -158,10 +160,10 @@ public class PipSizeSpecHandlerTest extends ShellTestCase {
mPipDisplayLayoutState.setDisplayLayout(displayLayout);
setUpStaticSystemPropertiesSession();
- mPipSizeSpecHandler = new TestPipSizeSpecHandler(mContext, mPipDisplayLayoutState);
+ mSizeSpecSource = new PhoneSizeSpecSource(mContext, mPipDisplayLayoutState);
// no overridden min edge size by default
- mPipSizeSpecHandler.setOverrideMinSize(null);
+ mSizeSpecSource.setOverrideMinSize(null);
}
@After
@@ -172,19 +174,19 @@ public class PipSizeSpecHandlerTest extends ShellTestCase {
@Test
public void testGetMaxSize() {
forEveryTestCaseCheck(sExpectedMaxSizes,
- (aspectRatio) -> mPipSizeSpecHandler.getMaxSize(aspectRatio));
+ (aspectRatio) -> mSizeSpecSource.getMaxSize(aspectRatio));
}
@Test
public void testGetDefaultSize() {
forEveryTestCaseCheck(sExpectedDefaultSizes,
- (aspectRatio) -> mPipSizeSpecHandler.getDefaultSize(aspectRatio));
+ (aspectRatio) -> mSizeSpecSource.getDefaultSize(aspectRatio));
}
@Test
public void testGetMinSize() {
forEveryTestCaseCheck(sExpectedMinSizes,
- (aspectRatio) -> mPipSizeSpecHandler.getMinSize(aspectRatio));
+ (aspectRatio) -> mSizeSpecSource.getMinSize(aspectRatio));
}
@Test
@@ -193,7 +195,7 @@ public class PipSizeSpecHandlerTest extends ShellTestCase {
Size initSize = new Size(600, 337);
Size expectedSize = new Size(338, 601);
- Size actualSize = mPipSizeSpecHandler.getSizeForAspectRatio(initSize, 9f / 16);
+ Size actualSize = mSizeSpecSource.getSizeForAspectRatio(initSize, 9f / 16);
Assert.assertEquals(expectedSize, actualSize);
}
@@ -201,26 +203,12 @@ public class PipSizeSpecHandlerTest extends ShellTestCase {
@Test
public void testGetSizeForAspectRatio_withOverrideMinSize() {
// an initial size with a 1:1 aspect ratio
- mPipSizeSpecHandler.setOverrideMinSize(new Size(OVERRIDE_MIN_EDGE_SIZE,
- OVERRIDE_MIN_EDGE_SIZE));
- // make sure initial size is same as override min size
- Size initSize = mPipSizeSpecHandler.getOverrideMinSize();
+ Size initSize = new Size(OVERRIDE_MIN_EDGE_SIZE, OVERRIDE_MIN_EDGE_SIZE);
+ mSizeSpecSource.setOverrideMinSize(initSize);
Size expectedSize = new Size(40, 71);
- Size actualSize = mPipSizeSpecHandler.getSizeForAspectRatio(initSize, 9f / 16);
+ Size actualSize = mSizeSpecSource.getSizeForAspectRatio(initSize, 9f / 16);
Assert.assertEquals(expectedSize, actualSize);
}
-
- static class TestPipSizeSpecHandler extends PipSizeSpecHandler {
-
- TestPipSizeSpecHandler(Context context, PipDisplayLayoutState displayLayoutState) {
- super(context, displayLayoutState);
- }
-
- @Override
- boolean supportsPipSizeLargeScreen() {
- return true;
- }
- }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 85167cb97501..2cc28acd0b17 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -109,7 +109,6 @@ public class PipControllerTest extends ShellTestCase {
@Mock private PipMotionHelper mMockPipMotionHelper;
@Mock private WindowManagerShellWrapper mMockWindowManagerShellWrapper;
@Mock private PipBoundsState mMockPipBoundsState;
- @Mock private PipSizeSpecHandler mMockPipSizeSpecHandler;
@Mock private PipDisplayLayoutState mMockPipDisplayLayoutState;
@Mock private TaskStackListenerImpl mMockTaskStackListener;
@Mock private ShellExecutor mMockExecutor;
@@ -134,7 +133,7 @@ public class PipControllerTest extends ShellTestCase {
mPipController = new PipController(mContext, mShellInit, mMockShellCommandHandler,
mShellController, mMockDisplayController, mMockPipAnimationController,
mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm,
- mMockPipBoundsState, mMockPipSizeSpecHandler, mMockPipDisplayLayoutState,
+ mMockPipBoundsState, mMockPipDisplayLayoutState,
mMockPipMotionHelper, mMockPipMediaController, mMockPhonePipMenuController,
mMockPipTaskOrganizer, mMockPipTransitionState, mMockPipTouchHandler,
mMockPipTransitionController, mMockWindowManagerShellWrapper,
@@ -226,7 +225,7 @@ public class PipControllerTest extends ShellTestCase {
assertNull(PipController.create(spyContext, shellInit, mMockShellCommandHandler,
mShellController, mMockDisplayController, mMockPipAnimationController,
mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm,
- mMockPipBoundsState, mMockPipSizeSpecHandler, mMockPipDisplayLayoutState,
+ mMockPipBoundsState, mMockPipDisplayLayoutState,
mMockPipMotionHelper, mMockPipMediaController, mMockPhonePipMenuController,
mMockPipTaskOrganizer, mMockPipTransitionState, mMockPipTouchHandler,
mMockPipTransitionController, mMockWindowManagerShellWrapper,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
index 1dfdbf6514ba..689b5c5a708c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
@@ -36,6 +36,8 @@ import androidx.test.filters.SmallTest;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
+import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipDisplayLayoutState;
@@ -87,7 +89,7 @@ public class PipResizeGestureHandlerTest extends ShellTestCase {
private PipBoundsState mPipBoundsState;
- private PipSizeSpecHandler mPipSizeSpecHandler;
+ private SizeSpecSource mSizeSpecSource;
private PipDisplayLayoutState mPipDisplayLayoutState;
@@ -97,13 +99,14 @@ public class PipResizeGestureHandlerTest extends ShellTestCase {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mPipDisplayLayoutState = new PipDisplayLayoutState(mContext);
- mPipSizeSpecHandler = new PipSizeSpecHandler(mContext, mPipDisplayLayoutState);
- mPipBoundsState = new PipBoundsState(mContext, mPipSizeSpecHandler, mPipDisplayLayoutState);
+ mSizeSpecSource = new PhoneSizeSpecSource(mContext, mPipDisplayLayoutState);
+ mPipBoundsState = new PipBoundsState(mContext, mSizeSpecSource, mPipDisplayLayoutState);
final PipSnapAlgorithm pipSnapAlgorithm = new PipSnapAlgorithm();
final PipKeepClearAlgorithmInterface pipKeepClearAlgorithm =
new PipKeepClearAlgorithmInterface() {};
final PipBoundsAlgorithm pipBoundsAlgorithm = new PipBoundsAlgorithm(mContext,
- mPipBoundsState, pipSnapAlgorithm, pipKeepClearAlgorithm, mPipSizeSpecHandler);
+ mPipBoundsState, pipSnapAlgorithm, pipKeepClearAlgorithm, mPipDisplayLayoutState,
+ mSizeSpecSource);
final PipMotionHelper motionHelper = new PipMotionHelper(mContext, mPipBoundsState,
mPipTaskOrganizer, mPhonePipMenuController, pipSnapAlgorithm,
mMockPipTransitionController, mFloatingContentCoordinator);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
index 10b1ddf1b868..852183cbcbac 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
@@ -33,6 +33,8 @@ import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
+import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipDisplayLayoutState;
@@ -92,7 +94,7 @@ public class PipTouchHandlerTest extends ShellTestCase {
private PipSnapAlgorithm mPipSnapAlgorithm;
private PipMotionHelper mMotionHelper;
private PipResizeGestureHandler mPipResizeGestureHandler;
- private PipSizeSpecHandler mPipSizeSpecHandler;
+ private SizeSpecSource mSizeSpecSource;
private PipDisplayLayoutState mPipDisplayLayoutState;
private DisplayLayout mDisplayLayout;
@@ -108,16 +110,16 @@ public class PipTouchHandlerTest extends ShellTestCase {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mPipDisplayLayoutState = new PipDisplayLayoutState(mContext);
- mPipSizeSpecHandler = new PipSizeSpecHandler(mContext, mPipDisplayLayoutState);
- mPipBoundsState = new PipBoundsState(mContext, mPipSizeSpecHandler, mPipDisplayLayoutState);
+ mSizeSpecSource = new PhoneSizeSpecSource(mContext, mPipDisplayLayoutState);
+ mPipBoundsState = new PipBoundsState(mContext, mSizeSpecSource, mPipDisplayLayoutState);
mPipSnapAlgorithm = new PipSnapAlgorithm();
mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState, mPipSnapAlgorithm,
- new PipKeepClearAlgorithmInterface() {}, mPipSizeSpecHandler);
+ new PipKeepClearAlgorithmInterface() {}, mPipDisplayLayoutState, mSizeSpecSource);
PipMotionHelper pipMotionHelper = new PipMotionHelper(mContext, mPipBoundsState,
mPipTaskOrganizer, mPhonePipMenuController, mPipSnapAlgorithm,
mMockPipTransitionController, mFloatingContentCoordinator);
mPipTouchHandler = new PipTouchHandler(mContext, mShellInit, mPhonePipMenuController,
- mPipBoundsAlgorithm, mPipBoundsState, mPipSizeSpecHandler, mPipTaskOrganizer,
+ mPipBoundsAlgorithm, mPipBoundsState, mSizeSpecSource, mPipTaskOrganizer,
pipMotionHelper, mFloatingContentCoordinator, mPipUiEventLogger, mMainExecutor);
// We aren't actually using ShellInit, so just call init directly
mPipTouchHandler.onInit();
@@ -162,8 +164,8 @@ public class PipTouchHandlerTest extends ShellTestCase {
// getting the expected min and max size
float aspectRatio = (float) mPipBounds.width() / mPipBounds.height();
- Size expectedMinSize = mPipSizeSpecHandler.getMinSize(aspectRatio);
- Size expectedMaxSize = mPipSizeSpecHandler.getMaxSize(aspectRatio);
+ Size expectedMinSize = mSizeSpecSource.getMinSize(aspectRatio);
+ Size expectedMaxSize = mSizeSpecSource.getMaxSize(aspectRatio);
assertEquals(expectedMovementBounds, mPipBoundsState.getNormalMovementBounds());
verify(mPipResizeGestureHandler, times(1))
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipGravityTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipGravityTest.java
index 91ff3cbf3a63..256610b857a1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipGravityTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipGravityTest.java
@@ -26,9 +26,10 @@ import static org.junit.Assert.assertEquals;
import android.view.Gravity;
import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.common.pip.LegacySizeSpecSource;
+import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.pip.PipDisplayLayoutState;
import com.android.wm.shell.pip.PipSnapAlgorithm;
-import com.android.wm.shell.pip.phone.PipSizeSpecHandler;
import org.junit.Before;
import org.junit.Test;
@@ -47,7 +48,7 @@ public class TvPipGravityTest extends ShellTestCase {
private TvPipBoundsState mTvPipBoundsState;
private TvPipBoundsAlgorithm mTvPipBoundsAlgorithm;
- private PipSizeSpecHandler mPipSizeSpecHandler;
+ private SizeSpecSource mSizeSpecSource;
private PipDisplayLayoutState mPipDisplayLayoutState;
@Before
@@ -56,11 +57,11 @@ public class TvPipGravityTest extends ShellTestCase {
MockitoAnnotations.initMocks(this);
mPipDisplayLayoutState = new PipDisplayLayoutState(mContext);
- mPipSizeSpecHandler = new PipSizeSpecHandler(mContext, mPipDisplayLayoutState);
- mTvPipBoundsState = new TvPipBoundsState(mContext, mPipSizeSpecHandler,
+ mSizeSpecSource = new LegacySizeSpecSource(mContext, mPipDisplayLayoutState);
+ mTvPipBoundsState = new TvPipBoundsState(mContext, mSizeSpecSource,
mPipDisplayLayoutState);
mTvPipBoundsAlgorithm = new TvPipBoundsAlgorithm(mContext, mTvPipBoundsState,
- mMockPipSnapAlgorithm, mPipSizeSpecHandler);
+ mMockPipSnapAlgorithm, mPipDisplayLayoutState, mSizeSpecSource);
setRTL(false);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index ff380e92322d..99a1ac663286 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -176,7 +176,7 @@ public class ShellTransitionTests extends ShellTestCase {
assertEquals(1, mDefaultHandler.activeCount());
mDefaultHandler.finishAll();
mMainExecutor.flushAll();
- verify(mOrganizer, times(1)).finishTransition(eq(transitToken), any(), any());
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken), any());
}
@Test
@@ -299,7 +299,7 @@ public class ShellTransitionTests extends ShellTestCase {
assertTrue(remoteCalled[0]);
mDefaultHandler.finishAll();
mMainExecutor.flushAll();
- verify(mOrganizer, times(1)).finishTransition(eq(transitToken), eq(remoteFinishWCT), any());
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken), eq(remoteFinishWCT));
}
@Test
@@ -449,7 +449,7 @@ public class ShellTransitionTests extends ShellTestCase {
assertTrue(remoteCalled[0]);
mDefaultHandler.finishAll();
mMainExecutor.flushAll();
- verify(mOrganizer, times(1)).finishTransition(eq(transitToken), any(), any());
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken), any());
}
@Test
@@ -524,20 +524,20 @@ public class ShellTransitionTests extends ShellTestCase {
// default handler doesn't merge by default, so it shouldn't increment active count.
assertEquals(1, mDefaultHandler.activeCount());
assertEquals(0, mDefaultHandler.mergeCount());
- verify(mOrganizer, times(0)).finishTransition(eq(transitToken1), any(), any());
- verify(mOrganizer, times(0)).finishTransition(eq(transitToken2), any(), any());
+ verify(mOrganizer, times(0)).finishTransition(eq(transitToken1), any());
+ verify(mOrganizer, times(0)).finishTransition(eq(transitToken2), any());
mDefaultHandler.finishAll();
mMainExecutor.flushAll();
// first transition finished
- verify(mOrganizer, times(1)).finishTransition(eq(transitToken1), any(), any());
- verify(mOrganizer, times(0)).finishTransition(eq(transitToken2), any(), any());
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken1), any());
+ verify(mOrganizer, times(0)).finishTransition(eq(transitToken2), any());
// But now the "queued" transition is running
assertEquals(1, mDefaultHandler.activeCount());
mDefaultHandler.finishAll();
mMainExecutor.flushAll();
- verify(mOrganizer, times(1)).finishTransition(eq(transitToken2), any(), any());
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken2), any());
}
@Test
@@ -565,15 +565,15 @@ public class ShellTransitionTests extends ShellTestCase {
// it should still only have 1 active, but then show 1 merged
assertEquals(1, mDefaultHandler.activeCount());
assertEquals(1, mDefaultHandler.mergeCount());
- verify(mOrganizer, times(0)).finishTransition(eq(transitToken1), any(), any());
+ verify(mOrganizer, times(0)).finishTransition(eq(transitToken1), any());
// We don't tell organizer it is finished yet (since we still want to maintain ordering)
- verify(mOrganizer, times(0)).finishTransition(eq(transitToken2), any(), any());
+ verify(mOrganizer, times(0)).finishTransition(eq(transitToken2), any());
mDefaultHandler.finishAll();
mMainExecutor.flushAll();
// transition + merged all finished.
- verify(mOrganizer, times(1)).finishTransition(eq(transitToken1), any(), any());
- verify(mOrganizer, times(1)).finishTransition(eq(transitToken2), any(), any());
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken1), any());
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken2), any());
// Make sure nothing was queued
assertEquals(0, mDefaultHandler.activeCount());
}
@@ -599,8 +599,7 @@ public class ShellTransitionTests extends ShellTestCase {
requestStartTransition(transitions, transitTokenNotReady);
mDefaultHandler.setSimulateMerge(true);
- mDefaultHandler.mFinishes.get(0).second.onTransitionFinished(
- null /* wct */, null /* wctCB */);
+ mDefaultHandler.mFinishes.get(0).second.onTransitionFinished(null /* wct */);
// Make sure that the non-ready transition is not merged.
assertEquals(0, mDefaultHandler.mergeCount());
@@ -823,8 +822,8 @@ public class ShellTransitionTests extends ShellTestCase {
mDefaultHandler.finishAll();
mMainExecutor.flushAll();
// first transition finished
- verify(mOrganizer, times(1)).finishTransition(eq(transitToken1), any(), any());
- verify(mOrganizer, times(0)).finishTransition(eq(transitToken2), any(), any());
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken1), any());
+ verify(mOrganizer, times(0)).finishTransition(eq(transitToken2), any());
// But now the "queued" transition is running
assertEquals(1, mDefaultHandler.activeCount());
@@ -835,7 +834,7 @@ public class ShellTransitionTests extends ShellTestCase {
mDefaultHandler.finishAll();
mMainExecutor.flushAll();
- verify(mOrganizer, times(1)).finishTransition(eq(transitToken2), any(), any());
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken2), any());
// runnable2 and runnable3 are executed after the second transition finishes because there
// are no other active transitions, runnable1 isn't executed again.
@@ -1449,13 +1448,13 @@ public class ShellTransitionTests extends ShellTestCase {
if (mFinishOnSync && info.getType() == TRANSIT_SLEEP) {
for (int i = 0; i < mFinishes.size(); ++i) {
if (mFinishes.get(i).first != mergeTarget) continue;
- mFinishes.remove(i).second.onTransitionFinished(null, null);
+ mFinishes.remove(i).second.onTransitionFinished(null);
return;
}
}
if (!(mSimulateMerge || mShouldMerge.contains(transition))) return;
mMerged.add(transition);
- finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+ finishCallback.onTransitionFinished(null /* wct */);
}
@Nullable
@@ -1478,7 +1477,7 @@ public class ShellTransitionTests extends ShellTestCase {
mFinishes;
mFinishes = new ArrayList<>();
for (int i = finishes.size() - 1; i >= 0; --i) {
- finishes.get(i).second.onTransitionFinished(null /* wct */, null /* wctCB */);
+ finishes.get(i).second.onTransitionFinished(null /* wct */);
}
mShouldMerge.clear();
}
@@ -1486,7 +1485,7 @@ public class ShellTransitionTests extends ShellTestCase {
void finishOne() {
Pair<IBinder, Transitions.TransitionFinishCallback> fin = mFinishes.remove(0);
mMerged.clear();
- fin.second.onTransitionFinished(null /* wct */, null /* wctCB */);
+ fin.second.onTransitionFinished(null /* wct */);
}
int activeCount() {
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 52666ab8d1d5..fdb355192676 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1872,6 +1872,8 @@ struct FabricatedOverlayEntryParameters {
DataValue data_value;
std::string data_string_value;
std::optional<android::base::borrowed_fd> data_binary_value;
+ off64_t binary_data_offset;
+ size_t binary_data_size;
std::string configuration;
};
diff --git a/libs/hwui/OWNERS b/libs/hwui/OWNERS
index bb93e66968be..6ca991d8b294 100644
--- a/libs/hwui/OWNERS
+++ b/libs/hwui/OWNERS
@@ -1,3 +1,5 @@
+# Bug component: 1075005
+
alecmouri@google.com
djsollen@google.com
jreck@google.com
diff --git a/libs/hwui/Tonemapper.cpp b/libs/hwui/Tonemapper.cpp
index 974a5d05aa84..ae29edf535a2 100644
--- a/libs/hwui/Tonemapper.cpp
+++ b/libs/hwui/Tonemapper.cpp
@@ -20,6 +20,7 @@
#include <log/log.h>
// libshaders only exists on Android devices
#ifdef __ANDROID__
+#include <renderthread/CanvasContext.h>
#include <shaders/shaders.h>
#endif
@@ -53,8 +54,17 @@ static sk_sp<SkColorFilter> createLinearEffectColorFilter(const shaders::LinearE
ColorFilterRuntimeEffectBuilder effectBuilder(std::move(runtimeEffect));
+ auto colorTransform = android::mat4();
+ const auto* context = renderthread::CanvasContext::getActiveContext();
+ if (context) {
+ const auto ratio = context->targetSdrHdrRatio();
+ if (ratio > 1.0f) {
+ colorTransform = android::mat4::scale(vec4(ratio, ratio, ratio, 1.f));
+ }
+ }
+
const auto uniforms =
- shaders::buildLinearEffectUniforms(linearEffect, android::mat4(), maxDisplayLuminance,
+ shaders::buildLinearEffectUniforms(linearEffect, colorTransform, maxDisplayLuminance,
currentDisplayLuminanceNits, maxLuminance);
for (const auto& uniform : uniforms) {
diff --git a/location/TEST_MAPPING b/location/TEST_MAPPING
index 214d2f3f5646..f5deb2ba3e07 100644
--- a/location/TEST_MAPPING
+++ b/location/TEST_MAPPING
@@ -1,7 +1,13 @@
{
"presubmit": [
{
- "name": "CtsLocationFineTestCases"
+ "name": "CtsLocationFineTestCases",
+ "options": [
+ {
+ // TODO: Wait for test to deflake - b/293934372
+ "exclude-filter":"android.location.cts.fine.ScanningSettingsTest"
+ }
+ ]
},
{
"name": "CtsLocationCoarseTestCases"
@@ -16,4 +22,4 @@
}]
}
]
-} \ No newline at end of file
+}
diff --git a/location/java/android/location/LocationManagerInternal.java b/location/java/android/location/LocationManagerInternal.java
index d59756d02348..a48cc19995c9 100644
--- a/location/java/android/location/LocationManagerInternal.java
+++ b/location/java/android/location/LocationManagerInternal.java
@@ -87,12 +87,6 @@ public abstract class LocationManagerInternal {
public abstract boolean isProvider(@Nullable String provider, @NonNull CallerIdentity identity);
/**
- * Should only be used by GNSS code.
- */
- // TODO: there is no reason for this to exist as part of any API. move all the logic into gnss
- public abstract void sendNiResponse(int notifId, int userResponse);
-
- /**
* Returns the GNSS provided time.
*
* @return LocationTime object that includes the current time, according to the GNSS location
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index fba4249260ef..ee2510ff9695 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -18,28 +18,14 @@ package com.android.internal.location;
import android.Manifest;
import android.annotation.RequiresPermission;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.location.INetInitiatedListener;
import android.location.LocationManager;
-import android.os.RemoteException;
import android.os.SystemClock;
-import android.os.UserHandle;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.telephony.emergency.EmergencyNumber;
import android.util.Log;
-import com.android.internal.R;
-import com.android.internal.notification.SystemNotificationChannels;
-import com.android.internal.telephony.GsmAlphabet;
-
-import java.io.UnsupportedEncodingException;
import java.util.concurrent.TimeUnit;
/**
@@ -53,95 +39,20 @@ public class GpsNetInitiatedHandler {
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- // string constants for defining data fields in NI Intent
- public static final String NI_INTENT_KEY_NOTIF_ID = "notif_id";
- public static final String NI_INTENT_KEY_TITLE = "title";
- public static final String NI_INTENT_KEY_MESSAGE = "message";
- public static final String NI_INTENT_KEY_TIMEOUT = "timeout";
- public static final String NI_INTENT_KEY_DEFAULT_RESPONSE = "default_resp";
-
- // the extra command to send NI response to GnssLocationProvider
- public static final String NI_RESPONSE_EXTRA_CMD = "send_ni_response";
-
- // the extra command parameter names in the Bundle
- public static final String NI_EXTRA_CMD_NOTIF_ID = "notif_id";
- public static final String NI_EXTRA_CMD_RESPONSE = "response";
-
- // these need to match GpsNiType constants in gps_ni.h
- public static final int GPS_NI_TYPE_VOICE = 1;
- public static final int GPS_NI_TYPE_UMTS_SUPL = 2;
- public static final int GPS_NI_TYPE_UMTS_CTRL_PLANE = 3;
- public static final int GPS_NI_TYPE_EMERGENCY_SUPL = 4;
-
- // these need to match GpsUserResponseType constants in gps_ni.h
- public static final int GPS_NI_RESPONSE_ACCEPT = 1;
- public static final int GPS_NI_RESPONSE_DENY = 2;
- public static final int GPS_NI_RESPONSE_NORESP = 3;
- public static final int GPS_NI_RESPONSE_IGNORE = 4;
-
- // these need to match GpsNiNotifyFlags constants in gps_ni.h
- public static final int GPS_NI_NEED_NOTIFY = 0x0001;
- public static final int GPS_NI_NEED_VERIFY = 0x0002;
- public static final int GPS_NI_PRIVACY_OVERRIDE = 0x0004;
-
- // these need to match GpsNiEncodingType in gps_ni.h
- public static final int GPS_ENC_NONE = 0;
- public static final int GPS_ENC_SUPL_GSM_DEFAULT = 1;
- public static final int GPS_ENC_SUPL_UTF8 = 2;
- public static final int GPS_ENC_SUPL_UCS2 = 3;
- public static final int GPS_ENC_UNKNOWN = -1;
-
private final Context mContext;
private final TelephonyManager mTelephonyManager;
// parent gps location provider
private final LocationManager mLocationManager;
- // configuration of notificaiton behavior
- private boolean mPlaySounds = false;
- private boolean mPopupImmediately = true;
-
- // read the SUPL_ES form gps.conf
- private volatile boolean mIsSuplEsEnabled;
-
// Set to true if the phone is having emergency call.
private volatile boolean mIsInEmergencyCall;
- // If Location function is enabled.
- private volatile boolean mIsLocationEnabled = false;
-
- private final INetInitiatedListener mNetInitiatedListener;
-
- // Set to true if string from HAL is encoded as Hex, e.g., "3F0039"
- @UnsupportedAppUsage
- static private boolean mIsHexInput = true;
// End time of emergency call, and extension, if set
private volatile long mCallEndElapsedRealtimeMillis = 0;
private volatile long mEmergencyExtensionMillis = 0;
- public static class GpsNiNotification
- {
- @android.compat.annotation.UnsupportedAppUsage
- public GpsNiNotification() {
- }
- public int notificationId;
- public int niType;
- public boolean needNotify;
- public boolean needVerify;
- public boolean privacyOverride;
- public int timeout;
- public int defaultResponse;
- @UnsupportedAppUsage
- public String requestorId;
- @UnsupportedAppUsage
- public String text;
- @UnsupportedAppUsage
- public int requestorIdEncoding;
- @UnsupportedAppUsage
- public int textEncoding;
- }
-
/** Callbacks for Emergency call events. */
public interface EmergencyCallCallback {
/** Callback invoked when an emergency call starts */
@@ -182,72 +93,20 @@ public class GpsNetInitiatedHandler {
// reference here.
private final EmergencyCallListener mEmergencyCallListener = new EmergencyCallListener();
- /**
- * The notification that is shown when a network-initiated notification
- * (and verification) event is received.
- * <p>
- * This is lazily created, so use {@link #setNINotification()}.
- */
- private Notification.Builder mNiNotificationBuilder;
-
private final EmergencyCallCallback mEmergencyCallCallback;
public GpsNetInitiatedHandler(Context context,
- INetInitiatedListener netInitiatedListener,
EmergencyCallCallback emergencyCallCallback,
boolean isSuplEsEnabled) {
mContext = context;
-
- if (netInitiatedListener == null) {
- throw new IllegalArgumentException("netInitiatedListener is null");
- } else {
- mNetInitiatedListener = netInitiatedListener;
- }
mEmergencyCallCallback = emergencyCallCallback;
- setSuplEsEnabled(isSuplEsEnabled);
mLocationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
- updateLocationMode();
mTelephonyManager =
(TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
mTelephonyManager.registerTelephonyCallback(mContext.getMainExecutor(),
mEmergencyCallListener);
- BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action.equals(LocationManager.MODE_CHANGED_ACTION)) {
- updateLocationMode();
- if (DEBUG) Log.d(TAG, "location enabled :" + getLocationEnabled());
- }
- }
- };
- mContext.registerReceiver(broadcastReceiver,
- new IntentFilter(LocationManager.MODE_CHANGED_ACTION));
- }
-
- public void setSuplEsEnabled(boolean isEnabled) {
- mIsSuplEsEnabled = isEnabled;
- }
-
- public boolean getSuplEsEnabled() {
- return mIsSuplEsEnabled;
- }
-
- /**
- * Updates Location enabler based on location setting.
- */
- public void updateLocationMode() {
- mIsLocationEnabled = mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
- }
-
- /**
- * Checks if user agreed to use location.
- */
- public boolean getLocationEnabled() {
- return mIsLocationEnabled;
}
/**
@@ -289,346 +148,4 @@ public class GpsNetInitiatedHandler {
public void setEmergencyExtensionSeconds(int emergencyExtensionSeconds) {
mEmergencyExtensionMillis = TimeUnit.SECONDS.toMillis(emergencyExtensionSeconds);
}
-
- // Handles NI events from HAL
- @UnsupportedAppUsage
- public void handleNiNotification(GpsNiNotification notif) {
- if (DEBUG) Log.d(TAG, "in handleNiNotification () :"
- + " notificationId: " + notif.notificationId
- + " requestorId: " + notif.requestorId
- + " text: " + notif.text
- + " mIsSuplEsEnabled" + getSuplEsEnabled()
- + " mIsLocationEnabled" + getLocationEnabled());
-
- if (getSuplEsEnabled()) {
- handleNiInEs(notif);
- } else {
- handleNi(notif);
- }
-
- //////////////////////////////////////////////////////////////////////////
- // A note about timeout
- // According to the protocol, in the need_notify and need_verify case,
- // a default response should be sent when time out.
- //
- // In some GPS hardware, the GPS driver (under HAL) can handle the timeout case
- // and this class GpsNetInitiatedHandler does not need to do anything.
- //
- // However, the UI should at least close the dialog when timeout. Further,
- // for more general handling, timeout response should be added to the Handler here.
- //
- }
-
- // handle NI form HAL when SUPL_ES is disabled.
- private void handleNi(GpsNiNotification notif) {
- if (DEBUG) Log.d(TAG, "in handleNi () :"
- + " needNotify: " + notif.needNotify
- + " needVerify: " + notif.needVerify
- + " privacyOverride: " + notif.privacyOverride
- + " mPopupImmediately: " + mPopupImmediately
- + " mInEmergency: " + getInEmergency());
-
- if (!getLocationEnabled() && !getInEmergency()) {
- // Location is currently disabled, ignore all NI requests.
- try {
- mNetInitiatedListener.sendNiResponse(notif.notificationId,
- GPS_NI_RESPONSE_IGNORE);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in sendNiResponse");
- }
- }
- if (notif.needNotify) {
- // If NI does not need verify or the dialog is not requested
- // to pop up immediately, the dialog box will not pop up.
- if (notif.needVerify && mPopupImmediately) {
- // Popup the dialog box now
- openNiDialog(notif);
- } else {
- // Show the notification
- setNiNotification(notif);
- }
- }
- // ACCEPT cases: 1. Notify, no verify; 2. no notify, no verify;
- // 3. privacy override.
- if (!notif.needVerify || notif.privacyOverride) {
- try {
- mNetInitiatedListener.sendNiResponse(notif.notificationId,
- GPS_NI_RESPONSE_ACCEPT);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in sendNiResponse");
- }
- }
- }
-
- // handle NI from HAL when the SUPL_ES is enabled
- private void handleNiInEs(GpsNiNotification notif) {
-
- if (DEBUG) Log.d(TAG, "in handleNiInEs () :"
- + " niType: " + notif.niType
- + " notificationId: " + notif.notificationId);
-
- // UE is in emergency mode when in emergency call mode or in emergency call back mode
- /*
- 1. When SUPL ES bit is off and UE is not in emergency mode:
- Call handleNi() to do legacy behaviour.
- 2. When SUPL ES bit is on and UE is in emergency mode:
- Call handleNi() to do acceptance behaviour.
- 3. When SUPL ES bit is off but UE is in emergency mode:
- Ignore the emergency SUPL INIT.
- 4. When SUPL ES bit is on but UE is not in emergency mode:
- Ignore the emergency SUPL INIT.
- */
- boolean isNiTypeES = (notif.niType == GPS_NI_TYPE_EMERGENCY_SUPL);
- if (isNiTypeES != getInEmergency()) {
- try {
- mNetInitiatedListener.sendNiResponse(notif.notificationId,
- GPS_NI_RESPONSE_IGNORE);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in sendNiResponse");
- }
- } else {
- handleNi(notif);
- }
- }
-
- /**
- * Posts a notification in the status bar using the contents in {@code notif} object.
- */
- private synchronized void setNiNotification(GpsNiNotification notif) {
- NotificationManager notificationManager = (NotificationManager) mContext
- .getSystemService(Context.NOTIFICATION_SERVICE);
- if (notificationManager == null) {
- return;
- }
-
- String title = getNotifTitle(notif, mContext);
- String message = getNotifMessage(notif, mContext);
-
- if (DEBUG) Log.d(TAG, "setNiNotification, notifyId: " + notif.notificationId +
- ", title: " + title +
- ", message: " + message);
-
- // Construct Notification
- if (mNiNotificationBuilder == null) {
- mNiNotificationBuilder = new Notification.Builder(mContext,
- SystemNotificationChannels.NETWORK_ALERTS)
- .setSmallIcon(com.android.internal.R.drawable.stat_sys_gps_on)
- .setWhen(0)
- .setOngoing(true)
- .setAutoCancel(true)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color));
- }
-
- if (mPlaySounds) {
- mNiNotificationBuilder.setDefaults(Notification.DEFAULT_SOUND);
- } else {
- mNiNotificationBuilder.setDefaults(0);
- }
-
- mNiNotificationBuilder.setTicker(getNotifTicker(notif, mContext))
- .setContentTitle(title)
- .setContentText(message);
-
- notificationManager.notifyAsUser(null, notif.notificationId, mNiNotificationBuilder.build(),
- UserHandle.ALL);
- }
-
- // Opens the notification dialog and waits for user input
- private void openNiDialog(GpsNiNotification notif)
- {
- Intent intent = getDlgIntent(notif);
-
- if (DEBUG) Log.d(TAG, "openNiDialog, notifyId: " + notif.notificationId +
- ", requestorId: " + notif.requestorId +
- ", text: " + notif.text);
-
- mContext.startActivity(intent);
- }
-
- // Construct the intent for bringing up the dialog activity, which shows the
- // notification and takes user input
- private Intent getDlgIntent(GpsNiNotification notif)
- {
- Intent intent = new Intent();
- String title = getDialogTitle(notif, mContext);
- String message = getDialogMessage(notif, mContext);
-
- // directly bring up the NI activity
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- intent.setClass(mContext, com.android.internal.app.NetInitiatedActivity.class);
-
- // put data in the intent
- intent.putExtra(NI_INTENT_KEY_NOTIF_ID, notif.notificationId);
- intent.putExtra(NI_INTENT_KEY_TITLE, title);
- intent.putExtra(NI_INTENT_KEY_MESSAGE, message);
- intent.putExtra(NI_INTENT_KEY_TIMEOUT, notif.timeout);
- intent.putExtra(NI_INTENT_KEY_DEFAULT_RESPONSE, notif.defaultResponse);
-
- if (DEBUG) Log.d(TAG, "generateIntent, title: " + title + ", message: " + message +
- ", timeout: " + notif.timeout);
-
- return intent;
- }
-
- // Converts a string (or Hex string) to a char array
- static byte[] stringToByteArray(String original, boolean isHex)
- {
- int length = isHex ? original.length() / 2 : original.length();
- byte[] output = new byte[length];
- int i;
-
- if (isHex)
- {
- for (i = 0; i < length; i++)
- {
- output[i] = (byte) Integer.parseInt(original.substring(i*2, i*2+2), 16);
- }
- }
- else {
- for (i = 0; i < length; i++)
- {
- output[i] = (byte) original.charAt(i);
- }
- }
-
- return output;
- }
-
- /**
- * Unpacks an byte array containing 7-bit packed characters into a String.
- *
- * @param input a 7-bit packed char array
- * @return the unpacked String
- */
- static String decodeGSMPackedString(byte[] input)
- {
- final char PADDING_CHAR = 0x00;
- int lengthBytes = input.length;
- int lengthSeptets = (lengthBytes * 8) / 7;
- String decoded;
-
- /* Special case where the last 7 bits in the last byte could hold a valid
- * 7-bit character or a padding character. Drop the last 7-bit character
- * if it is a padding character.
- */
- if (lengthBytes % 7 == 0) {
- if (lengthBytes > 0) {
- if ((input[lengthBytes - 1] >> 1) == PADDING_CHAR) {
- lengthSeptets = lengthSeptets - 1;
- }
- }
- }
-
- decoded = GsmAlphabet.gsm7BitPackedToString(input, 0, lengthSeptets);
-
- // Return "" if decoding of GSM packed string fails
- if (null == decoded) {
- Log.e(TAG, "Decoding of GSM packed string failed");
- decoded = "";
- }
-
- return decoded;
- }
-
- static String decodeUTF8String(byte[] input)
- {
- String decoded = "";
- try {
- decoded = new String(input, "UTF-8");
- }
- catch (UnsupportedEncodingException e)
- {
- throw new AssertionError();
- }
- return decoded;
- }
-
- static String decodeUCS2String(byte[] input)
- {
- String decoded = "";
- try {
- decoded = new String(input, "UTF-16");
- }
- catch (UnsupportedEncodingException e)
- {
- throw new AssertionError();
- }
- return decoded;
- }
-
- /** Decode NI string
- *
- * @param original The text string to be decoded
- * @param isHex Specifies whether the content of the string has been encoded as a Hex string. Encoding
- * a string as Hex can allow zeros inside the coded text.
- * @param coding Specifies the coding scheme of the string, such as GSM, UTF8, UCS2, etc. This coding scheme
- * needs to match those used passed to HAL from the native GPS driver. Decoding is done according
- * to the <code> coding </code>, after a Hex string is decoded. Generally, if the
- * notification strings don't need further decoding, <code> coding </code> encoding can be
- * set to -1, and <code> isHex </code> can be false.
- * @return the decoded string
- */
- @UnsupportedAppUsage
- static private String decodeString(String original, boolean isHex, int coding)
- {
- if (coding == GPS_ENC_NONE || coding == GPS_ENC_UNKNOWN) {
- return original;
- }
-
- byte[] input = stringToByteArray(original, isHex);
-
- switch (coding) {
- case GPS_ENC_SUPL_GSM_DEFAULT:
- return decodeGSMPackedString(input);
-
- case GPS_ENC_SUPL_UTF8:
- return decodeUTF8String(input);
-
- case GPS_ENC_SUPL_UCS2:
- return decodeUCS2String(input);
-
- default:
- Log.e(TAG, "Unknown encoding " + coding + " for NI text " + original);
- return original;
- }
- }
-
- // change this to configure notification display
- static private String getNotifTicker(GpsNiNotification notif, Context context)
- {
- String ticker = String.format(context.getString(R.string.gpsNotifTicker),
- decodeString(notif.requestorId, mIsHexInput, notif.requestorIdEncoding),
- decodeString(notif.text, mIsHexInput, notif.textEncoding));
- return ticker;
- }
-
- // change this to configure notification display
- static private String getNotifTitle(GpsNiNotification notif, Context context)
- {
- String title = String.format(context.getString(R.string.gpsNotifTitle));
- return title;
- }
-
- // change this to configure notification display
- static private String getNotifMessage(GpsNiNotification notif, Context context)
- {
- String message = String.format(context.getString(R.string.gpsNotifMessage),
- decodeString(notif.requestorId, mIsHexInput, notif.requestorIdEncoding),
- decodeString(notif.text, mIsHexInput, notif.textEncoding));
- return message;
- }
-
- // change this to configure dialog display (for verification)
- static public String getDialogTitle(GpsNiNotification notif, Context context)
- {
- return getNotifTitle(notif, context);
- }
-
- // change this to configure dialog display (for verification)
- static private String getDialogMessage(GpsNiNotification notif, Context context)
- {
- return getNotifMessage(notif, context);
- }
-
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 4759689335e9..e8c9d0dbd884 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -6929,6 +6929,114 @@ public class AudioManager {
/**
* @hide
+ * Describes an audio device that has not been categorized with a specific
+ * audio type.
+ */
+ public static final int AUDIO_DEVICE_CATEGORY_UNKNOWN = 0;
+
+ /**
+ * @hide
+ * Describes an audio device which is categorized as something different.
+ */
+ public static final int AUDIO_DEVICE_CATEGORY_OTHER = 1;
+
+ /**
+ * @hide
+ * Describes an audio device which was categorized as speakers.
+ */
+ public static final int AUDIO_DEVICE_CATEGORY_SPEAKER = 2;
+
+ /**
+ * @hide
+ * Describes an audio device which was categorized as headphones.
+ */
+ public static final int AUDIO_DEVICE_CATEGORY_HEADPHONES = 3;
+
+ /**
+ * @hide
+ * Describes an audio device which was categorized as car-kit.
+ */
+ public static final int AUDIO_DEVICE_CATEGORY_CARKIT = 4;
+
+ /**
+ * @hide
+ * Describes an audio device which was categorized as watch.
+ */
+ public static final int AUDIO_DEVICE_CATEGORY_WATCH = 5;
+
+ /**
+ * @hide
+ * Describes an audio device which was categorized as hearing aid.
+ */
+ public static final int AUDIO_DEVICE_CATEGORY_HEARING_AID = 6;
+
+ /**
+ * @hide
+ * Describes an audio device which was categorized as receiver.
+ */
+ public static final int AUDIO_DEVICE_CATEGORY_RECEIVER = 7;
+
+ /** @hide */
+ @IntDef(flag = false, prefix = "AUDIO_DEVICE_CATEGORY", value = {
+ AUDIO_DEVICE_CATEGORY_UNKNOWN,
+ AUDIO_DEVICE_CATEGORY_OTHER,
+ AUDIO_DEVICE_CATEGORY_SPEAKER,
+ AUDIO_DEVICE_CATEGORY_HEADPHONES,
+ AUDIO_DEVICE_CATEGORY_CARKIT,
+ AUDIO_DEVICE_CATEGORY_WATCH,
+ AUDIO_DEVICE_CATEGORY_HEARING_AID,
+ AUDIO_DEVICE_CATEGORY_RECEIVER }
+ )
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AudioDeviceCategory {}
+
+ /** @hide */
+ public static String audioDeviceCategoryToString(int audioDeviceCategory) {
+ switch (audioDeviceCategory) {
+ case AUDIO_DEVICE_CATEGORY_UNKNOWN: return "AUDIO_DEVICE_CATEGORY_UNKNOWN";
+ case AUDIO_DEVICE_CATEGORY_OTHER: return "AUDIO_DEVICE_CATEGORY_OTHER";
+ case AUDIO_DEVICE_CATEGORY_SPEAKER: return "AUDIO_DEVICE_CATEGORY_SPEAKER";
+ case AUDIO_DEVICE_CATEGORY_HEADPHONES: return "AUDIO_DEVICE_CATEGORY_HEADPHONES";
+ case AUDIO_DEVICE_CATEGORY_CARKIT: return "AUDIO_DEVICE_CATEGORY_CARKIT";
+ case AUDIO_DEVICE_CATEGORY_WATCH: return "AUDIO_DEVICE_CATEGORY_WATCH";
+ case AUDIO_DEVICE_CATEGORY_HEARING_AID: return "AUDIO_DEVICE_CATEGORY_HEARING_AID";
+ case AUDIO_DEVICE_CATEGORY_RECEIVER: return "AUDIO_DEVICE_CATEGORY_RECEIVER";
+ default:
+ return new StringBuilder("unknown AudioDeviceCategory ").append(
+ audioDeviceCategory).toString();
+ }
+ }
+
+ /**
+ * @hide
+ * Sets the audio device type of a Bluetooth device given its MAC address
+ */
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
+ public void setBluetoothAudioDeviceCategory(@NonNull String address, boolean isBle,
+ @AudioDeviceCategory int btAudioDeviceType) {
+ try {
+ getService().setBluetoothAudioDeviceCategory(address, isBle, btAudioDeviceType);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ * Gets the audio device type of a Bluetooth device given its MAC address
+ */
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
+ @AudioDeviceCategory
+ public int getBluetoothAudioDeviceCategory(@NonNull String address, boolean isBle) {
+ try {
+ return getService().getBluetoothAudioDeviceCategory(address, isBle);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
* Sound dose warning at every 100% of dose during integration window
*/
public static final int CSD_WARNING_DOSE_REACHED_1X = 1;
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 02f765a3dab9..b2466e990b8f 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -324,6 +324,12 @@ interface IAudioService {
@EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
boolean isCsdEnabled();
+ @EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
+ oneway void setBluetoothAudioDeviceCategory(in String address, boolean isBle, int deviceType);
+
+ @EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
+ int getBluetoothAudioDeviceCategory(in String address, boolean isBle);
+
int setHdmiSystemAudioSupported(boolean on);
boolean isHdmiSystemAudioSupported();
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index f664fdc949de..1d6e38d2a510 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -450,6 +450,7 @@ public final class MediaSession {
* but it must be released if your activity or service is being destroyed.
*/
public void release() {
+ setCallback(null);
try {
mBinder.destroySession();
} catch (RemoteException e) {
diff --git a/media/tests/mediatestutils/Android.bp b/media/tests/mediatestutils/Android.bp
new file mode 100644
index 000000000000..15bc1774d4d4
--- /dev/null
+++ b/media/tests/mediatestutils/Android.bp
@@ -0,0 +1,53 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+// TODO audio build defaults
+java_library {
+ name: "mediatestutils_host",
+ host_supported: true,
+ srcs: [
+ "java/com/android/media/mediatestutils/CancelAllFuturesRule.java",
+ ],
+ static_libs: [
+ "junit",
+ ],
+ visibility: [
+ ":__subpackages__",
+ ],
+}
+
+java_library {
+ name: "mediatestutils",
+ srcs: [
+ "java/com/android/media/mediatestutils/TestUtils.java",
+ ],
+ static_libs: [
+ "androidx.concurrent_concurrent-futures",
+ "guava",
+ "mediatestutils_host",
+ ],
+ visibility: [
+ "//cts/tests/tests/media:__subpackages__",
+ ":__subpackages__",
+ ],
+}
+
+java_test_host {
+ name: "mediatestutilshosttests",
+ srcs: ["javatests/**/*.java"],
+ static_libs: [
+ "mediatestutils_host",
+ "junit",
+ "truth",
+ ],
+ test_suites: ["general-tests"],
+ test_options: {
+ unit_test: true,
+ },
+}
diff --git a/media/tests/mediatestutils/OWNERS b/media/tests/mediatestutils/OWNERS
new file mode 100644
index 000000000000..b9eb1f82663f
--- /dev/null
+++ b/media/tests/mediatestutils/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 48436
+atneya@google.com
+jmtrivi@google.com
+elaurent@google.com
diff --git a/media/tests/mediatestutils/TEST_MAPPING b/media/tests/mediatestutils/TEST_MAPPING
new file mode 100644
index 000000000000..6dd09ae9c501
--- /dev/null
+++ b/media/tests/mediatestutils/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "mediatestutilstests"
+ }
+ ]
+}
diff --git a/media/tests/mediatestutils/java/com/android/media/mediatestutils/CancelAllFuturesRule.java b/media/tests/mediatestutils/java/com/android/media/mediatestutils/CancelAllFuturesRule.java
new file mode 100644
index 000000000000..14e261c40d9f
--- /dev/null
+++ b/media/tests/mediatestutils/java/com/android/media/mediatestutils/CancelAllFuturesRule.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.media.mediatestutils;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Future;
+
+/**
+ *
+ */
+public class CancelAllFuturesRule implements TestRule {
+ private List<Future> mRegisteredFutures = new ArrayList<>();
+
+ public <T extends Future<?>> T registerFuture(T future) {
+ mRegisteredFutures.add(future);
+ return future;
+ }
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ try {
+ base.evaluate();
+ } finally {
+ mRegisteredFutures.forEach(f -> f.cancel(false /* shouldInterrupt */));
+ }
+ }
+ };
+ }
+}
diff --git a/media/tests/mediatestutils/java/com/android/media/mediatestutils/TestUtils.java b/media/tests/mediatestutils/java/com/android/media/mediatestutils/TestUtils.java
new file mode 100644
index 000000000000..69d836d24664
--- /dev/null
+++ b/media/tests/mediatestutils/java/com/android/media/mediatestutils/TestUtils.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.media.mediatestutils;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import androidx.concurrent.futures.CallbackToFutureAdapter;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+
+import java.lang.ref.WeakReference;
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+/** Utils for audio tests. */
+public class TestUtils {
+ /**
+ * Return a future for an intent delivered by a broadcast receiver which matches an
+ * action and predicate.
+ * @param context - Context to register the receiver with
+ * @param action - String representing action to register receiver for
+ * @param pred - Predicate which sets the future if evaluates to true, otherwise, leaves
+ * the future unset. If the predicate throws, the future is set exceptionally
+ * @return - The future representing intent delivery matching predicate.
+ */
+ public static ListenableFuture<Intent> getFutureForIntent(
+ Context context, String action, Predicate<Intent> pred) {
+ // These are evaluated async
+ Objects.requireNonNull(action);
+ Objects.requireNonNull(pred);
+ return getFutureForListener(
+ (recv) ->
+ context.registerReceiver(
+ recv, new IntentFilter(action), Context.RECEIVER_NOT_EXPORTED),
+ (recv) -> {
+ try {
+ context.unregisterReceiver(recv);
+ } catch (IllegalArgumentException e) {
+ // Thrown when receiver is already unregistered, nothing to do
+ }
+ },
+ (completer) ->
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ try {
+ if (action.equals(intent.getAction()) && pred.test(intent)) {
+ completer.set(intent);
+ }
+ } catch (Exception e) {
+ completer.setException(e);
+ }
+ }
+ },
+ "Intent receiver future for action: " + action);
+ }
+
+ /**
+ * Return a future for a callback registered to a listener interface.
+ * @param registerFunc - Function which consumes the callback object for registration
+ * @param unregisterFunc - Function which consumes the callback object for unregistration
+ * This function is called when the future is completed or cancelled
+ * @param instantiateCallback - Factory function for the callback object, provided a completer
+ * object (see {@code CallbackToFutureAdapter.Completer<T>}), which is a logical reference
+ * to the future returned by this function
+ * @param debug - Debug string contained in future {@code toString} representation.
+ */
+ public static <T, V> ListenableFuture<T> getFutureForListener(
+ Consumer<V> registerFunc,
+ Consumer<V> unregisterFunc,
+ Function<CallbackToFutureAdapter.Completer<T>, V> instantiateCallback,
+ String debug) {
+ // Doesn't need to be thread safe since the resolver is called inline
+ final WeakReference<V> wrapper[] = new WeakReference[1];
+ ListenableFuture<T> future =
+ CallbackToFutureAdapter.getFuture(
+ completer -> {
+ final var cb = instantiateCallback.apply(completer);
+ wrapper[0] = new WeakReference(cb);
+ registerFunc.accept(cb);
+ return debug;
+ });
+ if (wrapper[0] == null) {
+ throw new AssertionError("Resolver should be called inline");
+ }
+ final var weakref = wrapper[0];
+ future.addListener(
+ () -> {
+ var cb = weakref.get();
+ // If there is no reference left, the receiver has already been unregistered
+ if (cb != null) {
+ unregisterFunc.accept(cb);
+ return;
+ }
+ },
+ MoreExecutors.directExecutor()); // Direct executor is fine since lightweight
+ return future;
+ }
+}
diff --git a/media/tests/mediatestutils/javatests/com/android/media/mediatestutils/CancelAllFuturesRuleTest.java b/media/tests/mediatestutils/javatests/com/android/media/mediatestutils/CancelAllFuturesRuleTest.java
new file mode 100644
index 000000000000..94fa3d7847eb
--- /dev/null
+++ b/media/tests/mediatestutils/javatests/com/android/media/mediatestutils/CancelAllFuturesRuleTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.media.mediatestutils;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Future;
+
+
+@RunWith(JUnit4.class)
+public class CancelAllFuturesRuleTest {
+
+ public static class TestException extends Throwable { }
+
+ public static class CheckFutureStatusRule implements TestRule {
+ private final List<CompletableFuture> mFutures = Arrays.asList(new CompletableFuture<>(),
+ new CompletableFuture<>());
+
+ private boolean mCompleted;
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ try {
+ base.evaluate();
+ } finally {
+ // Intentionally suppresses original exception
+ if (mCompleted) {
+ assertThat(mFutures.get(0).isDone())
+ .isTrue();
+ assertThat(mFutures.get(0).isCancelled())
+ .isFalse();
+ } else {
+ assertThat(mFutures.get(0).isCancelled())
+ .isTrue();
+ }
+ assertThat(mFutures.get(1).isCancelled())
+ .isTrue();
+ }
+ }
+ };
+ }
+
+ Future getFuture(int idx) {
+ return mFutures.get(idx);
+ }
+
+ void completeFirstFuture(boolean exceptionally) {
+ assertThat(mFutures.get(0).complete(null))
+ .isTrue();
+ mCompleted = true;
+ }
+ }
+
+ @Rule(order = 0)
+ public ExpectedException mExpectedThrownRule = ExpectedException.none();
+
+ @Rule(order = 1)
+ public CheckFutureStatusRule mRuleVerifyerRule = new CheckFutureStatusRule();
+
+ @Rule(order = 2)
+ public CancelAllFuturesRule mCancelRule = new CancelAllFuturesRule();
+
+ @Test
+ public void testRuleCancelsFutures_whenFinishesNormally() {
+ mCancelRule.registerFuture(mRuleVerifyerRule.getFuture(0));
+ mCancelRule.registerFuture(mRuleVerifyerRule.getFuture(1));
+ // return normally
+ }
+
+ @Test
+ public void testRuleCancelsFutures_whenFinishesExceptionally() throws TestException {
+ mExpectedThrownRule.expect(TestException.class);
+ mCancelRule.registerFuture(mRuleVerifyerRule.getFuture(0));
+ mCancelRule.registerFuture(mRuleVerifyerRule.getFuture(1));
+ throw new TestException();
+ }
+
+ @Test
+ public void testRuleDoesNotThrow_whenCompletesNormally() {
+ mCancelRule.registerFuture(mRuleVerifyerRule.getFuture(0));
+ mCancelRule.registerFuture(mRuleVerifyerRule.getFuture(1));
+ mRuleVerifyerRule.completeFirstFuture(false);
+ }
+
+ @Test
+ public void testRuleDoesNotThrow_whenCompletesExceptionally() {
+ mCancelRule.registerFuture(mRuleVerifyerRule.getFuture(0));
+ mCancelRule.registerFuture(mRuleVerifyerRule.getFuture(1));
+ mRuleVerifyerRule.completeFirstFuture(false);
+ }
+}
diff --git a/media/tests/mediatestutils/tests/Android.bp b/media/tests/mediatestutils/tests/Android.bp
new file mode 100644
index 000000000000..24a8360d1187
--- /dev/null
+++ b/media/tests/mediatestutils/tests/Android.bp
@@ -0,0 +1,22 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "mediatestutilstests",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "mockito-target-minus-junit4",
+ "androidx.test.runner",
+ "androidx.test.core",
+ "mediatestutils",
+ "junit",
+ "truth",
+ ],
+ test_suites: ["general-tests"],
+}
diff --git a/media/tests/mediatestutils/tests/AndroidManifest.xml b/media/tests/mediatestutils/tests/AndroidManifest.xml
new file mode 100644
index 000000000000..662bc45abc5d
--- /dev/null
+++ b/media/tests/mediatestutils/tests/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.media.mediatestutils">
+
+ <application android:testOnly="false"
+ android:debuggable="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.media.mediatestutils"
+ android:label="mediatestutils tests" />
+
+</manifest>
diff --git a/media/tests/mediatestutils/tests/src/java/com/android/media/mediatestutils/GetFutureForIntentTest.java b/media/tests/mediatestutils/tests/src/java/com/android/media/mediatestutils/GetFutureForIntentTest.java
new file mode 100644
index 000000000000..a4266a33f522
--- /dev/null
+++ b/media/tests/mediatestutils/tests/src/java/com/android/media/mediatestutils/GetFutureForIntentTest.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.media.mediatestutils;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static com.android.media.mediatestutils.TestUtils.getFutureForIntent;
+import static com.android.media.mediatestutils.TestUtils.getFutureForListener;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.SystemClock;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.ExecutionException;
+import java.util.function.Predicate;
+
+@RunWith(AndroidJUnit4.class)
+public class GetFutureForIntentTest {
+ public static final String INTENT_ACTION = "com.android.media.mediatestutils.TEST_ACTION";
+ public static final String INTENT_EXTRA = "com.android.media.mediatestutils.TEST_EXTRA";
+ public static final int MAGIC_VALUE = 7;
+
+ public final Context mContext = getApplicationContext();
+ public final Predicate<Intent> mPred =
+ i -> (i != null) && (i.getIntExtra(INTENT_EXTRA, -1) == MAGIC_VALUE);
+
+ @Test
+ public void futureCompletes_afterBroadcastFiresPredicatePasses() throws Exception {
+ final var future = getFutureForIntent(mContext, INTENT_ACTION, mPred);
+ sendIntent(true);
+ var intent = future.get();
+ assertThat(intent.getAction()).isEqualTo(INTENT_ACTION);
+ assertThat(intent.getIntExtra(INTENT_EXTRA, -1)).isEqualTo(MAGIC_VALUE);
+ }
+
+ @Test
+ public void futureDoesNotComplete_afterBroadcastFiresPredicateFails() throws Exception {
+ final var future = getFutureForIntent(mContext, INTENT_ACTION, mPred);
+ sendIntent(false);
+
+ // Wait a bit, and ensure the future hasn't completed
+ SystemClock.sleep(100);
+ assertThat(future.isDone()).isFalse();
+
+ // Future should still respond to subsequent passing intent
+ sendIntent(true);
+ var intent = future.get();
+ assertThat(intent.getAction()).isEqualTo(INTENT_ACTION);
+ assertThat(intent.getIntExtra(INTENT_EXTRA, -1)).isEqualTo(MAGIC_VALUE);
+ }
+
+ @Test
+ public void futureCompletesExceptionally_afterBroadcastFiresPredicateThrows() throws Exception {
+ final var future =
+ getFutureForIntent(
+ mContext,
+ INTENT_ACTION,
+ i -> {
+ throw new IllegalStateException();
+ });
+
+ sendIntent(true);
+ try {
+ var intent = future.get();
+ fail("Exception expected if predicate throws");
+ } catch (ExecutionException e) {
+ assertThat(e.getCause().getClass()).isEqualTo(IllegalStateException.class);
+ }
+ }
+
+ @Test
+ public void doesNotThrow_whenDoubleSet() throws Exception {
+ final var future = getFutureForIntent(mContext, INTENT_ACTION, mPred);
+ sendIntent(true);
+ sendIntent(true);
+ var intent = future.get();
+ assertThat(intent.getAction()).isEqualTo(INTENT_ACTION);
+ assertThat(intent.getIntExtra(INTENT_EXTRA, -1)).isEqualTo(MAGIC_VALUE);
+ }
+
+ @Test
+ public void unregisterListener_whenComplete() throws Exception {
+ final var service = new FakeService();
+ final ListenableFuture<Void> future =
+ getFutureForListener(
+ service::registerListener,
+ service::unregisterListener,
+ completer ->
+ () -> {
+ completer.set(null);
+ },
+ "FakeService listener future");
+ service.mRunnable.run();
+ assertThat(service.mRunnable).isNull();
+ }
+
+ @Test
+ public void unregisterListener_whenCancel() throws Exception {
+ final var service = new FakeService();
+ final ListenableFuture<Void> future =
+ getFutureForListener(
+ service::registerListener,
+ service::unregisterListener,
+ completer ->
+ () -> {
+ completer.set(null);
+ },
+ "FakeService listener future");
+ future.cancel(false);
+ assertThat(service.mRunnable).isNull();
+ }
+
+ private static class FakeService {
+ Runnable mRunnable;
+
+ void registerListener(Runnable r) {
+ mRunnable = r;
+ }
+
+ void unregisterListener(Runnable r) {
+ assertThat(r).isEqualTo(mRunnable);
+ mRunnable = null;
+ }
+ }
+
+ private void sendIntent(boolean correctValue) {
+ final Intent intent = new Intent(INTENT_ACTION).setPackage(mContext.getPackageName());
+ intent.putExtra(INTENT_EXTRA, correctValue ? MAGIC_VALUE : MAGIC_VALUE + 1);
+ mContext.sendBroadcast(intent);
+ }
+}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index b66679af3fe3..df91d98b8360 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -16,9 +16,7 @@
*/
package com.android.packageinstaller;
-import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.content.Intent.FLAG_ACTIVITY_NO_HISTORY;
-import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import android.Manifest;
@@ -808,8 +806,12 @@ public class PackageInstallerActivity extends AlertActivity {
}
new Handler(Looper.getMainLooper()).postDelayed(() -> {
if (!isDestroyed()) {
- startActivity(getIntent().addFlags(
- FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP));
+ startActivity(getIntent());
+ // The start flag (FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP) doesn't
+ // work for the multiple user case, i.e. the caller task user and started
+ // Activity user are not the same. To avoid having multiple PIAs in the task,
+ // finish the current PackageInstallerActivity
+ finish();
}
}, 500);
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt
index e2ff7b0bc2f8..a370ebfe21d5 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt
@@ -22,7 +22,6 @@ import android.os.UserHandle
import android.os.UserManager
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
-import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.settingslib.RestrictedLockUtils
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
@@ -90,7 +89,6 @@ internal class RestrictionsProviderImpl(
emit(getRestrictedMode())
}.flowOn(Dispatchers.IO)
- @OptIn(ExperimentalLifecycleComposeApi::class)
@Composable
override fun restrictedModeState() =
restrictedMode.collectAsStateWithLifecycle(initialValue = null)
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppInfoTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppInfoTest.kt
index 6831e56596cc..ab34f6820014 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppInfoTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppInfoTest.kt
@@ -23,10 +23,12 @@ import android.content.pm.PackageManager
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.testutils.waitUntilExists
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -51,7 +53,7 @@ class AppInfoTest {
}
}
- composeTestRule.onNodeWithText(LABEL).assertIsDisplayed()
+ composeTestRule.waitUntilExists(hasText(LABEL))
}
@Test
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
index 241a134b6a76..124ced6f88db 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
@@ -21,14 +21,16 @@ import android.content.pm.ApplicationInfo
import android.icu.text.CollationKey
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.unit.dp
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.android.settingslib.spa.framework.compose.toState
+import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.widget.ui.SpinnerOption
import com.android.settingslib.spaprivileged.R
import com.android.settingslib.spaprivileged.model.app.AppEntry
@@ -42,6 +44,7 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+@OptIn(ExperimentalTestApi::class)
@RunWith(AndroidJUnit4::class)
class AppListTest {
@get:Rule
@@ -53,7 +56,10 @@ class AppListTest {
fun whenHasOptions_firstOptionDisplayed() {
setContent(options = listOf(OPTION_0, OPTION_1))
- composeTestRule.onNodeWithText(OPTION_0).assertIsDisplayed()
+ composeTestRule.waitUntilExactlyOneExists(
+ matcher = hasText(OPTION_0),
+ timeoutMillis = 5_000,
+ )
composeTestRule.onNodeWithText(OPTION_1).assertDoesNotExist()
}
@@ -61,6 +67,10 @@ class AppListTest {
fun whenHasOptions_couldSwitchOption() {
setContent(options = listOf(OPTION_0, OPTION_1))
+ composeTestRule.waitUntilExactlyOneExists(
+ matcher = hasText(OPTION_0),
+ timeoutMillis = 5_000,
+ )
composeTestRule.onNodeWithText(OPTION_0).performClick()
composeTestRule.onNodeWithText(OPTION_1).performClick()
@@ -72,22 +82,30 @@ class AppListTest {
fun whenNoApps() {
setContent(appEntries = emptyList())
- composeTestRule.onNodeWithText(context.getString(R.string.no_applications))
- .assertIsDisplayed()
+ composeTestRule.waitUntilExactlyOneExists(
+ matcher = hasText(context.getString(R.string.no_applications)),
+ timeoutMillis = 5_000,
+ )
}
@Test
fun couldShowAppItem() {
setContent(appEntries = listOf(APP_ENTRY_A))
- composeTestRule.onNodeWithText(APP_ENTRY_A.label).assertIsDisplayed()
+ composeTestRule.waitUntilExactlyOneExists(
+ matcher = hasText(APP_ENTRY_A.label),
+ timeoutMillis = 5_000,
+ )
}
@Test
fun couldShowHeader() {
setContent(appEntries = listOf(APP_ENTRY_A), header = { Text(HEADER) })
- composeTestRule.onNodeWithText(HEADER).assertIsDisplayed()
+ composeTestRule.waitUntilExactlyOneExists(
+ matcher = hasText(HEADER),
+ timeoutMillis = 5_000,
+ )
}
@Test
@@ -102,7 +120,10 @@ class AppListTest {
fun whenGrouped_groupTitleDisplayed() {
setContent(appEntries = listOf(APP_ENTRY_A, APP_ENTRY_B), enableGrouping = true)
- composeTestRule.onNodeWithText(GROUP_A).assertIsDisplayed()
+ composeTestRule.waitUntilExactlyOneExists(
+ matcher = hasText(GROUP_A),
+ timeoutMillis = 5_000,
+ )
composeTestRule.onNodeWithText(GROUP_B).assertIsDisplayed()
}
@@ -112,29 +133,26 @@ class AppListTest {
header: @Composable () -> Unit = {},
enableGrouping: Boolean = false,
) {
+ val appListInput = AppListInput(
+ config = AppListConfig(
+ userIds = listOf(USER_ID),
+ showInstantApps = false,
+ matchAnyUserForAdmin = false,
+ ),
+ listModel = TestAppListModel(enableGrouping = enableGrouping),
+ state = AppListState(showSystem = stateOf(false), searchQuery = stateOf("")),
+ header = header,
+ bottomPadding = 0.dp,
+ )
+ val listViewModel = object : IAppListViewModel<TestAppRecord> {
+ override val optionFlow = MutableStateFlow<Int?>(null)
+ override val spinnerOptionsFlow = flowOf(options.mapIndexed { index, option ->
+ SpinnerOption(id = index, text = option)
+ })
+ override val appListDataFlow = flowOf(AppListData(appEntries, option = 0))
+ }
composeTestRule.setContent {
- AppListInput(
- config = AppListConfig(
- userIds = listOf(USER_ID),
- showInstantApps = false,
- matchAnyUserForAdmin = false,
- ),
- listModel = TestAppListModel(enableGrouping = enableGrouping),
- state = AppListState(
- showSystem = false.toState(),
- searchQuery = "".toState(),
- ),
- header = header,
- bottomPadding = 0.dp,
- ).AppListImpl {
- object : IAppListViewModel<TestAppRecord> {
- override val optionFlow: MutableStateFlow<Int?> = MutableStateFlow(null)
- override val spinnerOptionsFlow = flowOf(options.mapIndexed { index, option ->
- SpinnerOption(id = index, text = option)
- })
- override val appListDataFlow = flowOf(AppListData(appEntries, option = 0))
- }
- }
+ appListInput.AppListImpl { listViewModel }
}
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 46e73d096c0b..58106c05affa 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -442,5 +442,6 @@ public class GlobalSettingsValidators {
}));
VALIDATORS.put(Global.Wearable.PHONE_SWITCHING_SUPPORTED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.Wearable.WEAR_LAUNCHER_UI_MODE, NON_NEGATIVE_INTEGER_VALIDATOR);
+ VALIDATORS.put(Global.Wearable.WEAR_POWER_ANOMALY_SERVICE_ENABLED, BOOLEAN_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 9c9dd8a6c39e..61afb5b84247 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -689,7 +689,8 @@ public class SettingsBackupTest {
Settings.Global.Wearable.TETHER_CONFIG_STATE,
Settings.Global.Wearable.PHONE_SWITCHING_SUPPORTED,
Settings.Global.Wearable.WEAR_MEDIA_CONTROLS_PACKAGE,
- Settings.Global.Wearable.WEAR_MEDIA_SESSIONS_PACKAGE);
+ Settings.Global.Wearable.WEAR_MEDIA_SESSIONS_PACKAGE,
+ Settings.Global.Wearable.WEAR_POWER_ANOMALY_SERVICE_ENABLED);
private static final Set<String> BACKUP_DENY_LIST_SECURE_SETTINGS =
newHashSet(
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 0474849778d9..29999c240d4c 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -132,6 +132,17 @@ android_library {
manifest: "AndroidManifest-res.xml",
}
+aconfig_declarations {
+ name: "systemui_aconfig_flags",
+ package: "com.android.systemui.aconfig",
+ srcs: ["src/com/android/systemui/aconfig/systemui.aconfig"],
+}
+
+java_aconfig_library {
+ name: "systemui_aconfig_flags_lib",
+ aconfig_declarations: "systemui_aconfig_flags",
+}
+
android_library {
name: "SystemUI-core",
defaults: [
@@ -166,6 +177,7 @@ android_library {
"SystemUISharedLib",
"SystemUI-statsd",
"SettingsLib",
+ "systemui_aconfig_flags_lib",
"androidx.core_core-ktx",
"androidx.viewpager2_viewpager2",
"androidx.legacy_legacy-support-v4",
@@ -201,7 +213,6 @@ android_library {
"lottie",
"LowLightDreamLib",
"motion_tool_lib",
- "IntentResolver-core",
],
manifest: "AndroidManifest.xml",
@@ -344,6 +355,7 @@ android_library {
"SystemUICustomizationLib",
"SystemUI-statsd",
"SettingsLib",
+ "systemui_aconfig_flags_lib",
"androidx.viewpager2_viewpager2",
"androidx.legacy_legacy-support-v4",
"androidx.recyclerview_recyclerview",
@@ -385,7 +397,6 @@ android_library {
"motion_tool_lib",
"androidx.core_core-animation-testing-nodeps",
"androidx.compose.ui_ui",
- "IntentResolver-core",
],
}
@@ -408,6 +419,7 @@ android_library {
static_libs: [
"SystemUI-tests-base",
"androidx.test.uiautomator_uiautomator",
+ "androidx.core_core-animation-testing",
"mockito-target-extended-minus-junit4",
"androidx.test.ext.junit",
"androidx.test.ext.truth",
@@ -477,6 +489,7 @@ android_robolectric_test {
],
static_libs: [
"androidx.test.uiautomator_uiautomator",
+ "androidx.core_core-animation-testing",
"androidx.test.ext.junit",
"inline-mockito-robolectric-prebuilt",
],
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 58c9f777de33..6778d5a08506 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -562,7 +562,7 @@
android:exported="true"
android:launchMode="singleTop"
android:permission="android.permission.MANAGE_SENSOR_PRIVACY"
- android:theme="@style/Theme.SystemUI.Dialog.Alert"
+ android:theme="@style/Theme.SystemUI.Dialog.Alert.SensorPrivacy"
android:finishOnCloseSystemDialogs="true"
android:showForAllUsers="true">
</activity>
diff --git a/packages/SystemUI/compose/core/OWNERS b/packages/SystemUI/compose/core/OWNERS
new file mode 100644
index 000000000000..7e37f4fba538
--- /dev/null
+++ b/packages/SystemUI/compose/core/OWNERS
@@ -0,0 +1,12 @@
+set noparent
+
+# Bug component: 1184816
+
+jdemeulenaere@google.com
+nijamkin@google.com
+
+# Don't send reviews here.
+dsandler@android.com
+cinek@google.com
+juliacr@google.com
+pixel@google.com
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/activity/EdgeToEdgeActivitContent.kt b/packages/SystemUI/compose/core/src/com/android/compose/activity/EdgeToEdgeActivitContent.kt
new file mode 100644
index 000000000000..97c8076e910b
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/compose/activity/EdgeToEdgeActivitContent.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.activity
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.LocalContentColor
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.contentColorFor
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import com.android.compose.rememberSystemUiController
+import com.android.compose.theme.PlatformTheme
+
+/** Scaffolding for an edge-to-edge activity content. */
+@Composable
+fun EdgeToEdgeActivityContent(
+ modifier: Modifier = Modifier,
+ content: @Composable () -> Unit,
+) {
+ // Make the status and navigation bars transparent, ensuring that the status bar icons are dark
+ // when the theme is light and vice-versa.
+ val systemUiController = rememberSystemUiController()
+ val isDarkTheme = isSystemInDarkTheme()
+ val useDarkIcons = !isDarkTheme
+ DisposableEffect(systemUiController, useDarkIcons) {
+ systemUiController.setSystemBarsColor(
+ color = Color.Transparent,
+ darkIcons = useDarkIcons,
+ )
+ onDispose {}
+ }
+
+ PlatformTheme(isDarkTheme) {
+ val backgroundColor = MaterialTheme.colorScheme.background
+ Box(modifier.fillMaxSize().background(backgroundColor)) {
+ CompositionLocalProvider(LocalContentColor provides contentColorFor(backgroundColor)) {
+ content()
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/ExampleFeature.kt b/packages/SystemUI/compose/features/src/com/android/systemui/ExampleFeature.kt
deleted file mode 100644
index c58c16259abe..000000000000
--- a/packages/SystemUI/compose/features/src/com/android/systemui/ExampleFeature.kt
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui
-
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.BoxWithConstraints
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Surface
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.dp
-import kotlin.math.roundToInt
-
-/**
- * This is an example Compose feature, which shows a text and a count that is incremented when
- * clicked. We also show the max width available to this component, which is displayed either next
- * to or below the text depending on that max width.
- */
-@Composable
-fun ExampleFeature(text: String, modifier: Modifier = Modifier) {
- BoxWithConstraints(modifier) {
- val maxWidth = maxWidth
- if (maxWidth < 600.dp) {
- Column {
- CounterTile(text)
- Spacer(Modifier.size(16.dp))
- MaxWidthTile(maxWidth)
- }
- } else {
- Row {
- CounterTile(text)
- Spacer(Modifier.size(16.dp))
- MaxWidthTile(maxWidth)
- }
- }
- }
-}
-
-@Composable
-private fun CounterTile(text: String, modifier: Modifier = Modifier) {
- Surface(
- modifier,
- color = MaterialTheme.colorScheme.primaryContainer,
- shape = RoundedCornerShape(28.dp),
- ) {
- var count by remember { mutableStateOf(0) }
- Column(
- Modifier.clickable { count++ }.padding(16.dp),
- ) {
- Text(text)
- Text("I was clicked $count times.")
- }
- }
-}
-
-@Composable
-private fun MaxWidthTile(maxWidth: Dp, modifier: Modifier = Modifier) {
- Surface(
- modifier,
- color = MaterialTheme.colorScheme.tertiaryContainer,
- shape = RoundedCornerShape(28.dp),
- ) {
- Text(
- "The max available width to me is: ${maxWidth.value.roundToInt()}dp",
- Modifier.padding(16.dp)
- )
- }
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
index ca7352ef2501..da48762e1960 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
@@ -63,7 +63,7 @@ constructor(
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
- initialValue = destinationScenes(up = viewModel.upDestinationSceneKey.value)
+ initialValue = destinationScenes(up = null)
)
@Composable
@@ -77,12 +77,12 @@ constructor(
}
private fun destinationScenes(
- up: SceneKey,
+ up: SceneKey?,
): Map<UserAction, SceneModel> {
- return mapOf(
- UserAction.Swipe(Direction.UP) to SceneModel(up),
- UserAction.Swipe(Direction.DOWN) to SceneModel(SceneKey.Shade)
- )
+ return buildMap {
+ up?.let { this[UserAction.Swipe(Direction.UP)] = SceneModel(up) }
+ this[UserAction.Swipe(Direction.DOWN)] = SceneModel(SceneKey.Shade)
+ }
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
index d84e67620177..68f010e1c50d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt
@@ -42,13 +42,10 @@ import androidx.compose.runtime.key
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap
-import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.repeatOnLifecycle
import com.android.compose.theme.LocalAndroidColorScheme
import com.android.systemui.R
import com.android.systemui.compose.modifiers.sysuiResTag
@@ -70,15 +67,6 @@ fun PeopleScreen(
val priorityTiles by viewModel.priorityTiles.collectAsState()
val recentTiles by viewModel.recentTiles.collectAsState()
- // Make sure to refresh the tiles/conversations when the lifecycle is resumed, so that it
- // updates them when going back to the Activity after leaving it.
- val lifecycleOwner = LocalLifecycleOwner.current
- LaunchedEffect(lifecycleOwner, viewModel) {
- lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
- viewModel.onTileRefreshRequested()
- }
- }
-
// Call [onResult] this activity when the ViewModel tells us so.
LaunchedEffect(viewModel.result) {
viewModel.result.collect { result ->
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index 3dfdbbaaee77..f91baf298347 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -77,7 +77,7 @@ fun SceneContainer(
SceneTransitionLayout(
currentScene = currentSceneKey.toTransitionSceneKey(),
- onChangeScene = { sceneKey -> viewModel.setCurrentScene(sceneKey.toModel()) },
+ onChangeScene = viewModel::onSceneChanged,
transitions = transitions {},
state = state,
modifier = modifier.fillMaxSize(),
@@ -154,3 +154,7 @@ private fun UserAction.toTransitionUserAction(): SceneTransitionUserAction {
is UserAction.Back -> Back
}
}
+
+private fun SceneContainerViewModel.onSceneChanged(sceneKey: SceneTransitionSceneKey) {
+ onSceneChanged(sceneKey.toModel())
+}
diff --git a/packages/SystemUI/compose/features/tests/src/com/android/systemui/ExampleFeatureTest.kt b/packages/SystemUI/compose/features/tests/src/com/android/systemui/ExampleFeatureTest.kt
deleted file mode 100644
index 1c2e8fab0337..000000000000
--- a/packages/SystemUI/compose/features/tests/src/com/android/systemui/ExampleFeatureTest.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui
-
-import androidx.compose.ui.test.assertIsDisplayed
-import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.test.onNodeWithText
-import androidx.compose.ui.test.performClick
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-class ExampleFeatureTest {
- @get:Rule val composeRule = createComposeRule()
-
- @Test
- fun testProvidedTextIsDisplayed() {
- composeRule.setContent { ExampleFeature("foo") }
-
- composeRule.onNodeWithText("foo").assertIsDisplayed()
- }
-
- @Test
- fun testCountIsIncreasedWhenClicking() {
- composeRule.setContent { ExampleFeature("foo") }
-
- composeRule.onNodeWithText("I was clicked 0 times.").assertIsDisplayed().performClick()
- composeRule.onNodeWithText("I was clicked 1 times.").assertIsDisplayed()
- }
-}
diff --git a/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml b/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml
index 8f1323db299d..a1e2dc36278b 100644
--- a/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml
+++ b/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml
@@ -54,7 +54,7 @@
</FrameLayout>
<ImageView
android:id="@+id/mobile_type"
- android:layout_height="@dimen/status_bar_mobile_signal_size"
+ android:layout_height="@dimen/status_bar_mobile_type_size"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical"
android:adjustViewBounds="true"
@@ -74,13 +74,15 @@
<com.android.systemui.statusbar.AnimatedImageView
android:id="@+id/mobile_signal"
android:layout_height="@dimen/status_bar_mobile_signal_size"
- android:layout_width="@dimen/status_bar_mobile_signal_size"
+ android:layout_width="wrap_content"
+ android:adjustViewBounds="true"
systemui:hasOverlappingRendering="false"
/>
<ImageView
android:id="@+id/mobile_roaming"
- android:layout_width="@dimen/status_bar_mobile_signal_size"
- android:layout_height="@dimen/status_bar_mobile_signal_size"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/status_bar_mobile_roam_size"
+ android:adjustViewBounds="true"
android:layout_gravity="top|start"
android:src="@drawable/stat_sys_roaming"
android:contentDescription="@string/data_connection_roaming"
diff --git a/packages/SystemUI/res/layout/combined_qs_header.xml b/packages/SystemUI/res/layout/combined_qs_header.xml
index f3a6bbeaaf0e..12f13e9a2138 100644
--- a/packages/SystemUI/res/layout/combined_qs_header.xml
+++ b/packages/SystemUI/res/layout/combined_qs_header.xml
@@ -133,7 +133,8 @@ frame when animating QS <-> QQS transition
<com.android.systemui.statusbar.phone.StatusIconContainer
android:id="@+id/statusIcons"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
+ android:layout_weight="1"
android:layout_height="wrap_content"
android:paddingEnd="@dimen/signal_cluster_battery_padding" />
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 66c57fc2a9ac..36f7b96a267c 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -22,42 +22,6 @@
android:layout_width="match_parent"
android:outlineProvider="none" >
- <LinearLayout
- android:id="@id/keyguard_indication_area"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/keyguard_indication_margin_bottom"
- android:layout_gravity="bottom|center_horizontal"
- android:orientation="vertical">
-
- <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
- android:id="@id/keyguard_indication_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:paddingStart="@dimen/keyguard_indication_text_padding"
- android:paddingEnd="@dimen/keyguard_indication_text_padding"
- android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
- android:accessibilityLiveRegion="polite"/>
-
- <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
- android:id="@id/keyguard_indication_text_bottom"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:minHeight="@dimen/keyguard_indication_text_min_height"
- android:layout_gravity="center_horizontal"
- android:paddingStart="@dimen/keyguard_indication_text_padding"
- android:paddingEnd="@dimen/keyguard_indication_text_padding"
- android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
- android:maxLines="2"
- android:ellipsize="end"
- android:alpha=".8"
- android:accessibilityLiveRegion="polite"
- android:visibility="gone"/>
-
- </LinearLayout>
-
<com.android.systemui.animation.view.LaunchableImageView
android:id="@+id/start_button"
android:layout_height="@dimen/keyguard_affordance_fixed_height"
diff --git a/packages/SystemUI/res/layout/log_access_user_consent_dialog_permission.xml b/packages/SystemUI/res/layout/log_access_user_consent_dialog_permission.xml
index 89e36ac93387..d647c9b9f2ee 100644
--- a/packages/SystemUI/res/layout/log_access_user_consent_dialog_permission.xml
+++ b/packages/SystemUI/res/layout/log_access_user_consent_dialog_permission.xml
@@ -16,22 +16,29 @@
** limitations under the License.
*/
-->
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="380dp"
- android:layout_height="match_parent"
- android:clipToPadding="false">
- <LinearLayout
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="380dp"
+ android:layout_height="match_parent"
+ android:clipToPadding="false"
+ android:orientation="vertical">
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:orientation="vertical"
- android:gravity="center"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:paddingTop="24dp"
- android:paddingBottom="24dp">
+ android:paddingBottom="24dp"
+ android:gravity="center">
- <ImageView
+ <ImageView
android:id="@+id/log_access_image_view"
android:layout_width="32dp"
android:layout_height="32dp"
@@ -41,7 +48,7 @@
tools:layout_editor_absoluteY="35dp"
android:gravity="center" />
- <TextView
+ <TextView
android:id="@+id/log_access_dialog_title"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -51,7 +58,7 @@
android:textColor="?android:attr/textColorPrimary"
android:gravity="center" />
- <TextView
+ <TextView
android:id="@+id/log_access_dialog_body"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -60,42 +67,37 @@
android:textAppearance="@style/PrimaryAllowLogAccess"
android:textColor="?android:attr/textColorPrimary"
android:gravity="center" />
+ </LinearLayout>
+ </ScrollView>
- <Space
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1" />
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="24dp"
+ android:paddingRight="24dp"
+ android:paddingTop="24dp"
+ android:paddingBottom="24dp">
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <Button
- android:id="@+id/log_access_dialog_allow_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/log_access_confirmation_allow"
- style="?permissionGrantButtonTopStyle"
- android:textAppearance="@style/PermissionGrantButtonTextAppearance"
- android:layout_marginBottom="5dp"
- android:layout_centerHorizontal="true"
- android:layout_alignParentTop="true"
- android:layout_alignParentBottom="true"
- android:clipToOutline="true"
- android:gravity="center" />
+ <Button
+ android:id="@+id/log_access_dialog_allow_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/log_access_confirmation_allow"
+ style="?permissionGrantButtonTopStyle"
+ android:textAppearance="@style/PermissionGrantButtonTextAppearance"
+ android:layout_marginBottom="5dp"
+ android:clipToOutline="true"
+ android:gravity="center" />
- <Button
- android:id="@+id/log_access_dialog_deny_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/log_access_confirmation_deny"
- style="?permissionGrantButtonBottomStyle"
- android:textAppearance="@style/PermissionGrantButtonTextAppearance"
- android:layout_centerHorizontal="true"
- android:layout_alignParentTop="true"
- android:layout_alignParentBottom="true"
- android:clipToOutline="true"
- android:gravity="center" />
- </LinearLayout>
+ <Button
+ android:id="@+id/log_access_dialog_deny_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/log_access_confirmation_deny"
+ style="?permissionGrantButtonBottomStyle"
+ android:textAppearance="@style/PermissionGrantButtonTextAppearance"
+ android:clipToOutline="true"
+ android:gravity="center" />
</LinearLayout>
-</ScrollView>
+</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_projection_app_selector.xml b/packages/SystemUI/res/layout/media_projection_app_selector.xml
index 5404cfad25c5..e4749381243a 100644
--- a/packages/SystemUI/res/layout/media_projection_app_selector.xml
+++ b/packages/SystemUI/res/layout/media_projection_app_selector.xml
@@ -14,7 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.intentresolver.widget.ResolverDrawerLayout
+<com.android.internal.widget.ResolverDrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:layout_width="match_parent"
@@ -84,7 +84,7 @@
android:id="@*android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
- <com.android.intentresolver.ResolverViewPager
+ <com.android.internal.app.ResolverViewPager
android:id="@*android:id/profile_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
@@ -92,4 +92,4 @@
</LinearLayout>
</TabHost>
-</com.android.intentresolver.widget.ResolverDrawerLayout>
+</com.android.internal.widget.ResolverDrawerLayout>
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 909f19ffa519..59fcf0ea366c 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -67,6 +67,7 @@
android:id="@+id/status_bar_start_side_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|start"
android:clipChildren="false">
<include layout="@layout/heads_up_status_bar_layout" />
@@ -88,7 +89,8 @@
<com.android.systemui.statusbar.policy.Clock
android:id="@+id/clock"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_height="@dimen/status_bar_system_icons_height"
+ android:layout_gravity="center_vertical"
android:textAppearance="@style/TextAppearance.StatusBar.Clock"
android:singleLine="true"
android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
@@ -146,7 +148,10 @@
android:layout_marginEnd="@dimen/status_bar_user_chip_end_margin"
layout="@layout/status_bar_user_chip_container" />
- <include layout="@layout/system_icons" />
+ <include layout="@layout/system_icons"
+ android:layout_gravity="center_vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/status_bar_system_icons_height" />
</com.android.keyguard.AlphaOptimizedLinearLayout>
</FrameLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 34f8f2d89be2..572a7fe7b8fe 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -121,6 +121,9 @@
<dimen name="navigation_edge_cancelled_arrow_height">0dp</dimen>
<dimen name="navigation_edge_cancelled_edge_corners">6dp</dimen>
+ <!-- Height of the system icons container view in the status bar -->
+ <dimen name="status_bar_system_icons_height">@dimen/status_bar_icon_size_sp</dimen>
+
<!-- New sp height of notification icons in the status bar -->
<dimen name="status_bar_icon_size_sp">@*android:dimen/status_bar_icon_size_sp</dimen>
<!-- Original dp height of notification icons in the status bar -->
@@ -162,13 +165,21 @@
<!-- Size of the view displaying the wifi inout icon in the status bar. -->
<dimen name="status_bar_wifi_inout_container_size">17sp</dimen>
- <!-- Size of the view displaying the wifi signal icon in the status bar. -->
- <dimen name="status_bar_wifi_signal_size">13sp</dimen>
+ <!-- Size of the view displaying the wifi signal icon in the status bar. This value should
+ match the core/status_bar_system_icon_size and change to sp unit -->
+ <dimen name="status_bar_wifi_signal_size">15sp</dimen>
<!-- Size of the view displaying the mobile inout icon in the status bar. -->
<dimen name="status_bar_mobile_inout_container_size">17sp</dimen>
- <!-- Size of the view displaying the mobile signal icon in the status bar. -->
- <dimen name="status_bar_mobile_signal_size">13sp</dimen>
+ <!-- Size of the view displaying the mobile signal icon in the status bar. This value should
+ match the core/status_bar_system_icon_size and change to sp unit -->
+ <dimen name="status_bar_mobile_signal_size">15sp</dimen>
+ <!-- Size of the view displaying the mobile signal icon in the status bar. This value should
+ match the viewport height of mobile signal drawables such as ic_lte_mobiledata -->
+ <dimen name="status_bar_mobile_type_size">16sp</dimen>
+ <!-- Size of the view displaying the mobile roam icon in the status bar. This value should
+ match the viewport size of drawable stat_sys_roaming -->
+ <dimen name="status_bar_mobile_roam_size">8sp</dimen>
<!-- Spacing before the airplane mode icon if there are any icons preceding it. -->
<dimen name="status_bar_airplane_spacer_width">4sp</dimen>
@@ -343,8 +354,8 @@
<dimen name="status_bar_icons_padding_start">11dp</dimen>
<dimen name="status_bar_icons_padding_end">0dp</dimen>
- <dimen name="status_bar_icons_padding_bottom">8dp</dimen>
- <dimen name="status_bar_icons_padding_top">8dp</dimen>
+ <dimen name="status_bar_icons_padding_bottom">0dp</dimen>
+ <dimen name="status_bar_icons_padding_top">0dp</dimen>
<!-- gap on either side of status bar notification icons -->
<dimen name="status_bar_icon_horizontal_margin">0sp</dimen>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index 763930db1d55..c2dba6c41d12 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -38,4 +38,6 @@
protected. -->
<bool name="flag_battery_shield_icon">false</bool>
+ <!-- Whether face auth will immediately stop when the display state is OFF -->
+ <bool name="flag_stop_face_auth_on_display_off">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 15ca9d48c62a..d2cb475ad2b0 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -212,6 +212,7 @@
<item type="id" name="keyguard_indication_text" />
<item type="id" name="keyguard_indication_text_bottom" />
<item type="id" name="nssl_guideline" />
+ <item type="id" name="split_shade_guideline" />
<item type="id" name="lock_icon" />
<item type="id" name="lock_icon_bg" />
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ee9b132facbe..0befb3b82196 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3053,13 +3053,6 @@
<string name="wallet_quick_affordance_unavailable_configure_the_app">To add the Wallet app as a shortcut, make sure at least one card has been added</string>
<!--
- Requirement for the QR code scanner functionality to be available for the user to use. This is
- shown as part of a bulleted list of requirements. When all requirements are met, the piece of
- functionality can be accessed through a shortcut button on the lock screen. [CHAR LIMIT=NONE].
- -->
- <string name="qr_scanner_quick_affordance_unavailable_explanation">To add the QR code scanner as a shortcut, make sure a camera app is installed</string>
-
- <!--
Explains that the lock screen shortcut for the "home" app is not available because the app isn't
installed. This is shown as part of a dialog that explains to the user why they cannot select
this shortcut for their lock screen right now. [CHAR LIMIT=NONE].
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index d520670ec012..10340c6847f7 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -451,6 +451,11 @@
<style name="Theme.SystemUI.Dialog.Alert" parent="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
+ <style name="Theme.SystemUI.Dialog.Alert.SensorPrivacy" parent="Theme.SystemUI.Dialog.Alert">
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ </style>
+
<style name="Theme.SystemUI.Dialog.GlobalActions" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar.Fullscreen">
<item name="android:colorError">@*android:color/error_color_material_dark</item>
<item name="android:windowIsFloating">true</item>
diff --git a/packages/SystemUI/res/xml/qs_header.xml b/packages/SystemUI/res/xml/qs_header.xml
index 7b4282f049b8..427fd87c640a 100644
--- a/packages/SystemUI/res/xml/qs_header.xml
+++ b/packages/SystemUI/res/xml/qs_header.xml
@@ -83,6 +83,7 @@
android:layout_width="0dp"
android:layout_height="@dimen/new_qs_header_non_clickable_element_height"
app:layout_constraintWidth_default="wrap"
+ app:layout_constraintStart_toEndOf="@id/date"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/date"
app:layout_constraintBottom_toBottomOf="@id/date"
diff --git a/packages/SystemUI/shared/res/values-my/bools.xml b/packages/SystemUI/shared/res/values-my/bools.xml
new file mode 100644
index 000000000000..27cbe80ae54c
--- /dev/null
+++ b/packages/SystemUI/shared/res/values-my/bools.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Formatting note: terminate all comments with a period, to avoid breaking
+ the documentation output. To suppress comment lines from the documentation
+ output, insert an eat-comment element after the comment lines.
+-->
+
+<resources>
+ <!-- Whether to add padding at the bottom of the complication clock -->
+ <bool name="dream_overlay_complication_clock_bottom_padding">true</bool>
+</resources> \ No newline at end of file
diff --git a/packages/SystemUI/shared/res/values/bools.xml b/packages/SystemUI/shared/res/values/bools.xml
new file mode 100644
index 000000000000..f22dac4b9fb4
--- /dev/null
+++ b/packages/SystemUI/shared/res/values/bools.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Formatting note: terminate all comments with a period, to avoid breaking
+ the documentation output. To suppress comment lines from the documentation
+ output, insert an eat-comment element after the comment lines.
+-->
+
+<resources>
+ <!-- Whether to add padding at the bottom of the complication clock -->
+ <bool name="dream_overlay_complication_clock_bottom_padding">false</bool>
+</resources> \ No newline at end of file
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 b6aae69ebad6..f1a40077f3f9 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
@@ -24,14 +24,12 @@ import android.os.Parcelable
/**
* Base interface for flags that can change value on a running device.
- * @property id unique id to help identify this flag. Must be unique. This will be removed soon.
* @property teamfood Set to true to include this flag as part of the teamfood flag. This will
* be removed soon.
* @property name Used for server-side flagging where appropriate. Also used for display. No spaces.
* @property namespace The server-side namespace that this flag lives under.
*/
interface Flag<T> {
- val id: Int
val teamfood: Boolean
val name: String
val namespace: String
@@ -58,7 +56,6 @@ interface SysPropFlag<T> : Flag<T> {
*/
// Consider using the "parcelize" kotlin library.
abstract class BooleanFlag constructor(
- override val id: Int,
override val name: String,
override val namespace: String,
override val default: Boolean = false,
@@ -74,8 +71,17 @@ abstract class BooleanFlag constructor(
}
}
+ private constructor(
+ id: Int,
+ name: String,
+ namespace: String,
+ default: Boolean,
+ teamfood: Boolean,
+ overridden: Boolean,
+ ) : this(name, namespace, default, teamfood, overridden)
+
private constructor(parcel: Parcel) : this(
- id = parcel.readInt(),
+ parcel.readInt(),
name = parcel.readString() ?: "",
namespace = parcel.readString() ?: "",
default = parcel.readBoolean(),
@@ -84,7 +90,7 @@ abstract class BooleanFlag constructor(
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
- parcel.writeInt(id)
+ parcel.writeInt(0)
parcel.writeString(name)
parcel.writeString(namespace)
parcel.writeBoolean(default)
@@ -99,12 +105,11 @@ abstract class BooleanFlag constructor(
* It can be changed or overridden in debug builds but not in release builds.
*/
data class UnreleasedFlag constructor(
- override val id: Int,
override val name: String,
override val namespace: String,
override val teamfood: Boolean = false,
override val overridden: Boolean = false
-) : BooleanFlag(id, name, namespace, false, teamfood, overridden)
+) : BooleanFlag(name, namespace, false, teamfood, overridden)
/**
* A Flag that is true by default.
@@ -112,12 +117,11 @@ data class UnreleasedFlag constructor(
* It can be changed or overridden in any build, meaning it can be turned off if needed.
*/
data class ReleasedFlag constructor(
- override val id: Int,
override val name: String,
override val namespace: String,
override val teamfood: Boolean = false,
override val overridden: Boolean = false
-) : BooleanFlag(id, name, namespace, true, teamfood, overridden)
+) : BooleanFlag(name, namespace, true, teamfood, overridden)
/**
* A Flag that reads its default values from a resource overlay instead of code.
@@ -125,7 +129,6 @@ data class ReleasedFlag constructor(
* Prefer [UnreleasedFlag] and [ReleasedFlag].
*/
data class ResourceBooleanFlag constructor(
- override val id: Int,
override val name: String,
override val namespace: String,
@BoolRes override val resourceId: Int,
@@ -140,7 +143,6 @@ data class ResourceBooleanFlag constructor(
* Prefer [UnreleasedFlag] and [ReleasedFlag].
*/
data class SysPropBooleanFlag constructor(
- override val id: Int,
override val name: String,
override val namespace: String,
override val default: Boolean = false,
@@ -150,7 +152,6 @@ data class SysPropBooleanFlag constructor(
}
data class StringFlag constructor(
- override val id: Int,
override val name: String,
override val namespace: String,
override val default: String = "",
@@ -165,15 +166,21 @@ data class StringFlag constructor(
}
}
+ private constructor(id: Int, name: String, namespace: String, default: String) : this(
+ name,
+ namespace,
+ default
+ )
+
private constructor(parcel: Parcel) : this(
- id = parcel.readInt(),
+ parcel.readInt(),
name = parcel.readString() ?: "",
namespace = parcel.readString() ?: "",
default = parcel.readString() ?: ""
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
- parcel.writeInt(id)
+ parcel.writeInt(0)
parcel.writeString(name)
parcel.writeString(namespace)
parcel.writeString(default)
@@ -181,7 +188,6 @@ data class StringFlag constructor(
}
data class ResourceStringFlag constructor(
- override val id: Int,
override val name: String,
override val namespace: String,
@StringRes override val resourceId: Int,
@@ -189,7 +195,6 @@ data class ResourceStringFlag constructor(
) : ResourceFlag<String>
data class IntFlag constructor(
- override val id: Int,
override val name: String,
override val namespace: String,
override val default: Int = 0,
@@ -205,15 +210,21 @@ data class IntFlag constructor(
}
}
+ private constructor(id: Int, name: String, namespace: String, default: Int) : this(
+ name,
+ namespace,
+ default
+ )
+
private constructor(parcel: Parcel) : this(
- id = parcel.readInt(),
+ parcel.readInt(),
name = parcel.readString() ?: "",
namespace = parcel.readString() ?: "",
default = parcel.readInt()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
- parcel.writeInt(id)
+ parcel.writeInt(0)
parcel.writeString(name)
parcel.writeString(namespace)
parcel.writeInt(default)
@@ -221,7 +232,6 @@ data class IntFlag constructor(
}
data class ResourceIntFlag constructor(
- override val id: Int,
override val name: String,
override val namespace: String,
@IntegerRes override val resourceId: Int,
@@ -229,11 +239,10 @@ data class ResourceIntFlag constructor(
) : ResourceFlag<Int>
data class LongFlag constructor(
- override val id: Int,
- override val default: Long = 0,
- override val teamfood: Boolean = false,
override val name: String,
override val namespace: String,
+ override val default: Long = 0,
+ override val teamfood: Boolean = false,
override val overridden: Boolean = false
) : ParcelableFlag<Long> {
@@ -245,15 +254,21 @@ data class LongFlag constructor(
}
}
+ private constructor(id: Int, name: String, namespace: String, default: Long) : this(
+ name,
+ namespace,
+ default
+ )
+
private constructor(parcel: Parcel) : this(
- id = parcel.readInt(),
+ parcel.readInt(),
name = parcel.readString() ?: "",
namespace = parcel.readString() ?: "",
default = parcel.readLong()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
- parcel.writeInt(id)
+ parcel.writeInt(0)
parcel.writeString(name)
parcel.writeString(namespace)
parcel.writeLong(default)
@@ -261,7 +276,6 @@ data class LongFlag constructor(
}
data class FloatFlag constructor(
- override val id: Int,
override val name: String,
override val namespace: String,
override val default: Float = 0f,
@@ -277,15 +291,21 @@ data class FloatFlag constructor(
}
}
+ private constructor(id: Int, name: String, namespace: String, default: Float) : this(
+ name,
+ namespace,
+ default
+ )
+
private constructor(parcel: Parcel) : this(
- id = parcel.readInt(),
+ parcel.readInt(),
name = parcel.readString() ?: "",
namespace = parcel.readString() ?: "",
default = parcel.readFloat()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
- parcel.writeInt(id)
+ parcel.writeInt(0)
parcel.writeString(name)
parcel.writeString(namespace)
parcel.writeFloat(default)
@@ -293,7 +313,6 @@ data class FloatFlag constructor(
}
data class ResourceFloatFlag constructor(
- override val id: Int,
override val name: String,
override val namespace: String,
override val resourceId: Int,
@@ -301,7 +320,6 @@ data class ResourceFloatFlag constructor(
) : ResourceFlag<Int>
data class DoubleFlag constructor(
- override val id: Int,
override val name: String,
override val namespace: String,
override val default: Double = 0.0,
@@ -317,15 +335,21 @@ data class DoubleFlag constructor(
}
}
+ private constructor(id: Int, name: String, namespace: String, default: Double) : this(
+ name,
+ namespace,
+ default
+ )
+
private constructor(parcel: Parcel) : this(
- id = parcel.readInt(),
+ parcel.readInt(),
name = parcel.readString() ?: "",
namespace = parcel.readString() ?: "",
default = parcel.readDouble()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
- parcel.writeInt(id)
+ parcel.writeInt(0)
parcel.writeString(name)
parcel.writeString(namespace)
parcel.writeDouble(default)
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 da1641c326de..1366226a4e24 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt
@@ -116,13 +116,6 @@ class FlagManager constructor(
}
/** Returns the stored value or null if not set. */
- // TODO(b/265188950): Remove method this once ids are fully deprecated.
- fun <T> readFlagValue(id: Int, serializer: FlagSerializer<T>): T? {
- val data = settings.getStringFromSecure(idToSettingsKey(id))
- return serializer.fromSettingsData(data)
- }
-
- /** Returns the stored value or null if not set. */
fun <T> readFlagValue(name: String, serializer: FlagSerializer<T>): T? {
val data = settings.getString(nameToSettingsKey(name))
return serializer.fromSettingsData(data)
@@ -158,11 +151,6 @@ class FlagManager constructor(
return intent
}
- // TODO(b/265188950): Remove method this once ids are fully deprecated.
- fun idToSettingsKey(id: Int): String {
- return "$SETTINGS_PREFIX/$id"
- }
-
fun nameToSettingsKey(name: String): String {
return "$SETTINGS_PREFIX/$name"
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/flags/FlagSettingsHelper.kt b/packages/SystemUI/shared/src/com/android/systemui/flags/FlagSettingsHelper.kt
index 6beb8518ab67..e0a7feaf671c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/flags/FlagSettingsHelper.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/flags/FlagSettingsHelper.kt
@@ -22,7 +22,6 @@ import android.provider.Settings
class FlagSettingsHelper(private val contentResolver: ContentResolver) {
- // TODO(b/265188950): Remove method this once ids are fully deprecated.
fun getStringFromSecure(key: String): String? = Settings.Secure.getString(contentResolver, key)
fun getString(key: String): String? = Settings.Global.getString(contentResolver, key)
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
index fac2f910a789..3605ac2bfc66 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
@@ -336,6 +336,14 @@ public class Task {
@Override
public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (!(o instanceof Task)) {
+ return false;
+ }
+
// Check that the id matches
Task t = (Task) o;
return key.equals(t.key);
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextClock.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextClock.kt
index 5a6f1840bc95..4b602cb643a6 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextClock.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextClock.kt
@@ -16,6 +16,8 @@
package com.android.systemui.shared.shadow
import android.content.Context
+import android.content.res.Resources
+import android.content.res.TypedArray
import android.graphics.Canvas
import android.util.AttributeSet
import android.widget.TextClock
@@ -31,19 +33,40 @@ constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
- defStyleRes: Int = 0
+ defStyleRes: Int = 0,
) : TextClock(context, attrs, defStyleAttr, defStyleRes) {
- private val mAmbientShadowInfo: ShadowInfo
- private val mKeyShadowInfo: ShadowInfo
+ private lateinit var mAmbientShadowInfo: ShadowInfo
+ private lateinit var mKeyShadowInfo: ShadowInfo
+ private var attributesInput: TypedArray? = null
+ private var resources: Resources? = null
+ constructor(
+ resources: Resources,
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+ defStyleRes: Int = 0,
+ attributesInput: TypedArray? = null
+ ) : this(context, attrs, defStyleAttr, defStyleRes) {
+ this.attributesInput = attributesInput
+ this.resources = resources
+ this.initializeAttributes(attrs, defStyleAttr, defStyleRes)
+ }
init {
- val attributes =
- context.obtainStyledAttributes(
- attrs,
- R.styleable.DoubleShadowTextClock,
- defStyleAttr,
- defStyleRes
- )
+ initializeAttributes(attrs, defStyleAttr, defStyleRes)
+ }
+
+ private fun initializeAttributes(attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) {
+ var attributes: TypedArray =
+ this.attributesInput
+ ?: context.obtainStyledAttributes(
+ attrs,
+ R.styleable.DoubleShadowTextClock,
+ defStyleAttr,
+ defStyleRes
+ )
+
+ var resource: Resources = this.resources ?: context.resources
try {
val keyShadowBlur =
attributes.getDimensionPixelSize(R.styleable.DoubleShadowTextClock_keyShadowBlur, 0)
@@ -98,18 +121,27 @@ constructor(
0
)
if (removeTextDescent) {
- setPaddingRelative(
- 0,
- 0,
- 0,
- textDescentExtraPadding - floor(paint.fontMetrics.descent.toDouble()).toInt()
- )
+ val addBottomPaddingToClock =
+ resource.getBoolean(R.bool.dream_overlay_complication_clock_bottom_padding)
+ val metrics = paint.fontMetrics
+ val padding =
+ if (addBottomPaddingToClock) {
+ textDescentExtraPadding +
+ floor(metrics.descent.toDouble()).toInt() / paddingDividedOffset
+ } else {
+ textDescentExtraPadding - floor(metrics.descent.toDouble()).toInt()
+ }
+ setPaddingRelative(0, 0, 0, padding)
}
} finally {
attributes.recycle()
}
}
+ companion object {
+ private val paddingDividedOffset = 2
+ }
+
public override fun onDraw(canvas: Canvas) {
applyShadows(mKeyShadowInfo, mAmbientShadowInfo, this, canvas) { super.onDraw(canvas) }
}
diff --git a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsFactory.kt b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsFactory.kt
index c22d689338a8..3360c967a182 100644
--- a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsFactory.kt
+++ b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsFactory.kt
@@ -29,35 +29,31 @@ object FlagsFactory {
}
fun unreleasedFlag(
- id: Int,
name: String,
namespace: String = "systemui",
teamfood: Boolean = false
): UnreleasedFlag {
- val flag = UnreleasedFlag(id = id, name = name, namespace = namespace, teamfood = teamfood)
+ val flag = UnreleasedFlag(name = name, namespace = namespace, teamfood = teamfood)
checkForDupesAndAdd(flag)
return flag
}
fun releasedFlag(
- id: Int,
name: String,
namespace: String = "systemui",
): ReleasedFlag {
- val flag = ReleasedFlag(id = id, name = name, namespace = namespace, teamfood = false)
+ val flag = ReleasedFlag(name = name, namespace = namespace, teamfood = false)
checkForDupesAndAdd(flag)
return flag
}
fun resourceBooleanFlag(
- id: Int,
@BoolRes resourceId: Int,
name: String,
namespace: String = "systemui",
): ResourceBooleanFlag {
val flag =
ResourceBooleanFlag(
- id = id,
name = name,
namespace = namespace,
resourceId = resourceId,
@@ -68,13 +64,11 @@ object FlagsFactory {
}
fun sysPropBooleanFlag(
- id: Int,
name: String,
namespace: String = "systemui",
default: Boolean = false
): SysPropBooleanFlag {
- val flag =
- SysPropBooleanFlag(id = id, name = name, namespace = "systemui", default = default)
+ val flag = SysPropBooleanFlag(name = name, namespace = "systemui", default = default)
checkForDupesAndAdd(flag)
return flag
}
diff --git a/packages/SystemUI/src-release/com/android/systemui/flags/FlagsFactory.kt b/packages/SystemUI/src-release/com/android/systemui/flags/FlagsFactory.kt
index 5502da146bba..75465c27724d 100644
--- a/packages/SystemUI/src-release/com/android/systemui/flags/FlagsFactory.kt
+++ b/packages/SystemUI/src-release/com/android/systemui/flags/FlagsFactory.kt
@@ -29,35 +29,31 @@ object FlagsFactory {
}
fun unreleasedFlag(
- id: Int,
name: String,
namespace: String = "systemui",
teamfood: Boolean = false
): UnreleasedFlag {
// Unreleased flags are always false in this build.
- val flag = UnreleasedFlag(id = id, name = "", namespace = "", teamfood = false)
+ val flag = UnreleasedFlag(name = name, namespace = namespace, teamfood = false)
return flag
}
fun releasedFlag(
- id: Int,
name: String,
namespace: String = "systemui",
): ReleasedFlag {
- val flag = ReleasedFlag(id = id, name = name, namespace = namespace, teamfood = false)
+ val flag = ReleasedFlag(name = name, namespace = namespace, teamfood = false)
flagMap[name] = flag
return flag
}
fun resourceBooleanFlag(
- id: Int,
@BoolRes resourceId: Int,
name: String,
namespace: String = "systemui",
): ResourceBooleanFlag {
val flag =
ResourceBooleanFlag(
- id = id,
name = name,
namespace = namespace,
resourceId = resourceId,
@@ -68,13 +64,11 @@ object FlagsFactory {
}
fun sysPropBooleanFlag(
- id: Int,
name: String,
namespace: String = "systemui",
default: Boolean = false
): SysPropBooleanFlag {
- val flag =
- SysPropBooleanFlag(id = id, name = name, namespace = namespace, default = default)
+ val flag = SysPropBooleanFlag(name = name, namespace = namespace, default = default)
flagMap[name] = flag
return flag
}
diff --git a/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt b/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt
index 22cdb30376d0..2abb7a41ef08 100644
--- a/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt
+++ b/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt
@@ -33,6 +33,7 @@ import com.android.keyguard.InternalFaceAuthReasons.AUTH_REQUEST_DURING_CANCELLA
import com.android.keyguard.InternalFaceAuthReasons.BIOMETRIC_ENABLED
import com.android.keyguard.InternalFaceAuthReasons.CAMERA_LAUNCHED
import com.android.keyguard.InternalFaceAuthReasons.DEVICE_WOKEN_UP_ON_REACH_GESTURE
+import com.android.keyguard.InternalFaceAuthReasons.DISPLAY_OFF
import com.android.keyguard.InternalFaceAuthReasons.DREAM_STARTED
import com.android.keyguard.InternalFaceAuthReasons.DREAM_STOPPED
import com.android.keyguard.InternalFaceAuthReasons.ENROLLMENTS_CHANGED
@@ -131,6 +132,7 @@ private object InternalFaceAuthReasons {
const val NON_STRONG_BIOMETRIC_ALLOWED_CHANGED =
"Face auth stopped because non strong biometric allowed changed"
const val POSTURE_CHANGED = "Face auth started/stopped due to device posture changed."
+ const val DISPLAY_OFF = "Face auth stopped due to display state OFF."
}
/**
@@ -221,7 +223,8 @@ constructor(private val id: Int, val reason: String, var extraInfo: Int = 0) :
FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED(1255, STRONG_AUTH_ALLOWED_CHANGED),
@UiEvent(doc = NON_STRONG_BIOMETRIC_ALLOWED_CHANGED)
FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED(1256, NON_STRONG_BIOMETRIC_ALLOWED_CHANGED),
- @UiEvent(doc = ACCESSIBILITY_ACTION) FACE_AUTH_ACCESSIBILITY_ACTION(1454, ACCESSIBILITY_ACTION);
+ @UiEvent(doc = ACCESSIBILITY_ACTION) FACE_AUTH_ACCESSIBILITY_ACTION(1454, ACCESSIBILITY_ACTION),
+ @UiEvent(doc = DISPLAY_OFF) FACE_AUTH_DISPLAY_OFF(1461, DISPLAY_OFF);
override fun getId(): Int = this.id
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 00256c4d7707..30b8ed0f1750 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -335,7 +335,6 @@ public class KeyguardClockSwitch extends RelativeLayout {
}
});
- in.setAlpha(0);
in.setVisibility(View.VISIBLE);
mClockInAnim = new AnimatorSet();
mClockInAnim.setDuration(CLOCK_IN_MILLIS);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 2c224f62dac7..3d48f3cc5359 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -244,24 +244,8 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
return;
}
updateAodIcons();
-
mStatusArea = mView.findViewById(R.id.keyguard_status_area);
- if (mSmartspaceController.isEnabled()) {
- View ksv = mView.findViewById(R.id.keyguard_slice_view);
- int viewIndex = mStatusArea.indexOfChild(ksv);
- ksv.setVisibility(View.GONE);
-
- // TODO(b/261757708): add content observer for the Settings toggle and add/remove
- // weather according to the Settings.
- if (mSmartspaceController.isDateWeatherDecoupled()) {
- addDateWeatherView(viewIndex);
- viewIndex += 1;
- }
-
- addSmartspaceView(viewIndex);
- }
-
mSecureSettings.registerContentObserverForUser(
Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK,
false, /* notifyForDescendants */
@@ -275,13 +259,27 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mShowWeatherObserver,
UserHandle.USER_ALL
);
-
updateDoubleLineClock();
- setDateWeatherVisibility();
- setWeatherVisibility();
mKeyguardUnlockAnimationController.addKeyguardUnlockAnimationListener(
mKeyguardUnlockAnimationListener);
+
+ if (mSmartspaceController.isEnabled()) {
+ View ksv = mView.findViewById(R.id.keyguard_slice_view);
+ int viewIndex = mStatusArea.indexOfChild(ksv);
+ ksv.setVisibility(View.GONE);
+
+ mSmartspaceController.removeViewsFromParent(mStatusArea);
+ addSmartspaceView();
+ // TODO(b/261757708): add content observer for the Settings toggle and add/remove
+ // weather according to the Settings.
+ if (mSmartspaceController.isDateWeatherDecoupled()) {
+ addDateWeatherView();
+ }
+ }
+
+ setDateWeatherVisibility();
+ setWeatherVisibility();
}
int getNotificationIconAreaHeight() {
@@ -302,29 +300,22 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
void onLocaleListChanged() {
if (mSmartspaceController.isEnabled()) {
+ mSmartspaceController.removeViewsFromParent(mStatusArea);
+ addSmartspaceView();
if (mSmartspaceController.isDateWeatherDecoupled()) {
mDateWeatherView.removeView(mWeatherView);
- int index = mStatusArea.indexOfChild(mDateWeatherView);
- if (index >= 0) {
- mStatusArea.removeView(mDateWeatherView);
- addDateWeatherView(index);
- }
+ addDateWeatherView();
setDateWeatherVisibility();
setWeatherVisibility();
}
- int index = mStatusArea.indexOfChild(mSmartspaceView);
- if (index >= 0) {
- mStatusArea.removeView(mSmartspaceView);
- addSmartspaceView(index);
- }
}
}
- private void addDateWeatherView(int index) {
+ private void addDateWeatherView() {
mDateWeatherView = (ViewGroup) mSmartspaceController.buildAndConnectDateView(mView);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
MATCH_PARENT, WRAP_CONTENT);
- mStatusArea.addView(mDateWeatherView, index, lp);
+ mStatusArea.addView(mDateWeatherView, 0, lp);
int startPadding = getContext().getResources().getDimensionPixelSize(
R.dimen.below_clock_padding_start);
int endPadding = getContext().getResources().getDimensionPixelSize(
@@ -344,11 +335,11 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mWeatherView.setPaddingRelative(0, 0, 4, 0);
}
- private void addSmartspaceView(int index) {
+ private void addSmartspaceView() {
mSmartspaceView = mSmartspaceController.buildAndConnectView(mView);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
MATCH_PARENT, WRAP_CONTENT);
- mStatusArea.addView(mSmartspaceView, index, lp);
+ mStatusArea.addView(mSmartspaceView, 0, lp);
int startPadding = getContext().getResources().getDimensionPixelSize(
R.dimen.below_clock_padding_start);
int endPadding = getContext().getResources().getDimensionPixelSize(
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
index 461d390fd477..bb799fc55171 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
@@ -27,6 +27,7 @@ data class KeyguardFaceListenModel(
override var userId: Int = 0,
override var listening: Boolean = false,
// keep sorted
+ var allowedDisplayState: Boolean = false,
var alternateBouncerShowing: Boolean = false,
var authInterruptActive: Boolean = false,
var biometricSettingEnabledForUser: Boolean = false,
@@ -57,6 +58,8 @@ data class KeyguardFaceListenModel(
userId.toString(),
listening.toString(),
// keep sorted
+ allowedDisplayState.toString(),
+ alternateBouncerShowing.toString(),
authInterruptActive.toString(),
biometricSettingEnabledForUser.toString(),
bouncerFullyShown.toString(),
@@ -74,7 +77,6 @@ data class KeyguardFaceListenModel(
supportsDetect.toString(),
switchingUser.toString(),
systemUser.toString(),
- alternateBouncerShowing.toString(),
udfpsFingerDown.toString(),
userNotTrustedOrDetectionIsNeeded.toString(),
)
@@ -96,7 +98,9 @@ data class KeyguardFaceListenModel(
userId = model.userId
listening = model.listening
// keep sorted
+ allowedDisplayState = model.allowedDisplayState
alternateBouncerShowing = model.alternateBouncerShowing
+ authInterruptActive = model.authInterruptActive
biometricSettingEnabledForUser = model.biometricSettingEnabledForUser
bouncerFullyShown = model.bouncerFullyShown
faceAndFpNotAuthenticated = model.faceAndFpNotAuthenticated
@@ -105,7 +109,6 @@ data class KeyguardFaceListenModel(
faceLockedOut = model.faceLockedOut
goingToSleep = model.goingToSleep
keyguardAwake = model.keyguardAwake
- goingToSleep = model.goingToSleep
keyguardGoingAway = model.keyguardGoingAway
listeningForFaceAssistant = model.listeningForFaceAssistant
occludingAppRequestingFaceAuth = model.occludingAppRequestingFaceAuth
@@ -140,6 +143,8 @@ data class KeyguardFaceListenModel(
"userId",
"listening",
// keep sorted
+ "allowedDisplayState",
+ "alternateBouncerShowing",
"authInterruptActive",
"biometricSettingEnabledForUser",
"bouncerFullyShown",
@@ -157,7 +162,6 @@ data class KeyguardFaceListenModel(
"supportsDetect",
"switchingUser",
"systemUser",
- "udfpsBouncerShowing",
"udfpsFingerDown",
"userNotTrustedOrDetectionIsNeeded",
)
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 03d9eb3455fd..59ee0d817ef3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -32,6 +32,7 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Trace;
@@ -71,6 +72,8 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView {
private Interpolator mLinearOutSlowInInterpolator;
private Interpolator mFastOutLinearInInterpolator;
private DisappearAnimationListener mDisappearAnimationListener;
+ private static final int[] DISABLE_STATE_SET = {-android.R.attr.state_enabled};
+ private static final int[] ENABLE_STATE_SET = {android.R.attr.state_enabled};
public KeyguardPasswordView(Context context) {
this(context, null);
@@ -148,7 +151,10 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView {
@Override
protected void setPasswordEntryEnabled(boolean enabled) {
- mPasswordEntry.setEnabled(enabled);
+ int color = mPasswordEntry.getTextColors().getColorForState(
+ enabled ? ENABLE_STATE_SET : DISABLE_STATE_SET, 0);
+ mPasswordEntry.setBackgroundTintList(ColorStateList.valueOf(color));
+ mPasswordEntry.setCursorVisible(enabled);
}
@Override
@@ -189,17 +195,18 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView {
if (controller.isCancelled()) {
return;
}
+ float value = (float) animation.getAnimatedValue();
+ float fraction = anim.getAnimatedFraction();
Insets shownInsets = controller.getShownStateInsets();
int dist = (int) (-shownInsets.bottom / 4
- * anim.getAnimatedFraction());
+ * fraction);
Insets insets = Insets.add(shownInsets, Insets.of(0, 0, 0, dist));
if (mDisappearAnimationListener != null) {
mDisappearAnimationListener.setTranslationY(-dist);
}
- controller.setInsetsAndAlpha(insets,
- (float) animation.getAnimatedValue(),
- anim.getAnimatedFraction());
+ controller.setInsetsAndAlpha(insets, value, fraction);
+ setAlpha(value);
});
anim.addListener(new AnimatorListenerAdapter() {
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
index 1f6b09b91b87..5dbd01407a43 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
@@ -265,7 +265,8 @@ public class KeyguardPasswordViewController
private boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManager imm,
final boolean shouldIncludeAuxiliarySubtypes) {
final List<InputMethodInfo> enabledImis =
- imm.getEnabledInputMethodListAsUser(KeyguardUpdateMonitor.getCurrentUser());
+ imm.getEnabledInputMethodListAsUser(
+ UserHandle.of(KeyguardUpdateMonitor.getCurrentUser()));
// Number of the filtered IMEs
int filteredImisCount = 0;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 8a0c9ef6680c..61addabe7341 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -1198,8 +1198,6 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
});
mPopup.show();
});
-
- mUserSwitcherViewGroup.setAlpha(0f);
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index aff25914ec36..4e1cbc737d5f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -476,18 +476,16 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
if (mFeatureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
// When the scene framework transitions from bouncer to gone, we dismiss the keyguard.
mSceneTransitionCollectionJob = mJavaAdapter.get().alwaysCollectFlow(
- mSceneInteractor.get().getTransitions(),
- sceneTransitionModel -> {
- if (sceneTransitionModel != null
- && sceneTransitionModel.getFrom() == SceneKey.Bouncer.INSTANCE
- && sceneTransitionModel.getTo() == SceneKey.Gone.INSTANCE) {
- final int selectedUserId = mUserInteractor.getSelectedUserId();
- showNextSecurityScreenOrFinish(
- /* authenticated= */ true,
- selectedUserId,
- /* bypassSecondaryLockScreen= */ true,
- mSecurityModel.getSecurityMode(selectedUserId));
- }
+ mSceneInteractor.get().finishedSceneTransitions(
+ /* from= */ SceneKey.Bouncer.INSTANCE,
+ /* to= */ SceneKey.Gone.INSTANCE),
+ unused -> {
+ final int selectedUserId = mUserInteractor.getSelectedUserId();
+ showNextSecurityScreenOrFinish(
+ /* authenticated= */ true,
+ selectedUserId,
+ /* bypassSecondaryLockScreen= */ true,
+ mSecurityModel.getSecurityMode(selectedUserId));
});
}
}
@@ -677,6 +675,14 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mSecurityViewFlipperController.reset();
}
+ /** Prepares views in the bouncer before starting appear animation. */
+ public void prepareToShow() {
+ View bouncerUserSwitcher = mView.findViewById(R.id.keyguard_bouncer_user_switcher);
+ if (bouncerUserSwitcher != null) {
+ bouncerUserSwitcher.setAlpha(0f);
+ }
+ }
+
@Override
public void onResume(int reason) {
if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
@@ -827,7 +833,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
boolean isLockscreenDisabled = mLockPatternUtils.isLockScreenDisabled(
KeyguardUpdateMonitor.getCurrentUser());
- if (securityMode == SecurityMode.None || isLockscreenDisabled) {
+
+ if (securityMode == SecurityMode.None) {
finish = isLockscreenDisabled;
eventSubtype = BOUNCER_DISMISS_SIM;
uiEvent = BouncerUiEvent.BOUNCER_DISMISS_SIM;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 8e92941c79fa..73b4c5f47cde 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -150,7 +150,8 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
@Override
public void onInit() {
mKeyguardClockSwitchController.init();
- mDumpManager.registerDumpable(this);
+
+ mDumpManager.registerDumpable(getInstanceName(), this);
if (mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
startCoroutines(EmptyCoroutineContext.INSTANCE);
}
@@ -190,7 +191,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
* Called in notificationPanelViewController to avoid leak
*/
public void onDestroy() {
- mDumpManager.unregisterDumpable(TAG);
+ mDumpManager.unregisterDumpable(getInstanceName());
}
/**
@@ -385,7 +386,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
* Updates the alignment of the KeyguardStatusView and animates the transition if requested.
*/
public void updateAlignment(
- ConstraintLayout notifContainerParent,
+ ConstraintLayout layout,
boolean splitShadeEnabled,
boolean shouldBeCentered,
boolean animate) {
@@ -395,16 +396,23 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
}
mStatusViewCentered = shouldBeCentered;
- if (notifContainerParent == null) {
+ if (layout == null) {
return;
}
ConstraintSet constraintSet = new ConstraintSet();
- constraintSet.clone(notifContainerParent);
- int statusConstraint = shouldBeCentered ? PARENT_ID : R.id.qs_edge_guideline;
+ constraintSet.clone(layout);
+ int guideline;
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+ guideline = R.id.split_shade_guideline;
+ } else {
+ guideline = R.id.qs_edge_guideline;
+ }
+
+ int statusConstraint = shouldBeCentered ? PARENT_ID : guideline;
constraintSet.connect(R.id.keyguard_status_view, END, statusConstraint, END);
if (!animate) {
- constraintSet.applyTo(notifContainerParent);
+ constraintSet.applyTo(layout);
return;
}
@@ -447,7 +455,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
// old animation rather than setting up the custom animations.
if (clockContainerView == null || clockContainerView.getChildCount() == 0) {
transition.addListener(mKeyguardStatusAlignmentTransitionListener);
- TransitionManager.beginDelayedTransition(notifContainerParent, transition);
+ TransitionManager.beginDelayedTransition(layout, transition);
} else {
View clockView = clockContainerView.getChildAt(0);
@@ -481,14 +489,14 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
}
set.addListener(mKeyguardStatusAlignmentTransitionListener);
- TransitionManager.beginDelayedTransition(notifContainerParent, set);
+ TransitionManager.beginDelayedTransition(layout, set);
}
} else {
transition.addListener(mKeyguardStatusAlignmentTransitionListener);
- TransitionManager.beginDelayedTransition(notifContainerParent, transition);
+ TransitionManager.beginDelayedTransition(layout, transition);
}
- constraintSet.applyTo(notifContainerParent);
+ constraintSet.applyTo(layout);
}
@Override
@@ -496,6 +504,10 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
mView.dump(pw, args);
}
+ String getInstanceName() {
+ return TAG + "#" + hashCode();
+ }
+
@VisibleForTesting
static class SplitShadeTransitionAdapter extends Transition {
private static final String PROP_BOUNDS_LEFT = "splitShadeTransitionAdapter:boundsLeft";
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index c03053d0a8a2..853a62a09f83 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -41,6 +41,7 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.keyguard.FaceAuthReasonKt.apiRequestReasonToUiEvent;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_DISPLAY_OFF;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_DREAM_STARTED;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_FACE_CANCEL_NOT_RECEIVED;
@@ -135,6 +136,7 @@ import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.view.Display;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -175,6 +177,7 @@ import com.android.systemui.keyguard.shared.model.SysUiFaceAuthenticateOptions;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.WeatherData;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -335,6 +338,25 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
}
};
+ private final DisplayTracker.Callback mDisplayCallback = new DisplayTracker.Callback() {
+ @Override
+ public void onDisplayChanged(int displayId) {
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ return;
+ }
+
+ if (mDisplayTracker.getDisplay(mDisplayTracker.getDefaultDisplayId()).getState()
+ == Display.STATE_OFF) {
+ mAllowedDisplayStateForFaceAuth = false;
+ updateFaceListeningState(
+ BIOMETRIC_ACTION_STOP,
+ FACE_AUTH_DISPLAY_OFF
+ );
+ } else {
+ mAllowedDisplayStateForFaceAuth = true;
+ }
+ }
+ };
private final FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig;
HashMap<Integer, SimData> mSimDatas = new HashMap<>();
@@ -355,6 +377,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private boolean mOccludingAppRequestingFp;
private boolean mOccludingAppRequestingFace;
private boolean mSecureCameraLaunched;
+ private boolean mAllowedDisplayStateForFaceAuth = true;
@VisibleForTesting
protected boolean mTelephonyCapable;
private boolean mAllowFingerprintOnCurrentOccludingActivity;
@@ -403,6 +426,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private KeyguardFaceAuthInteractor mFaceAuthInteractor;
private final TaskStackChangeListeners mTaskStackChangeListeners;
private final IActivityTaskManager mActivityTaskManager;
+ private final DisplayTracker mDisplayTracker;
private final LockPatternUtils mLockPatternUtils;
@VisibleForTesting
@DevicePostureInt
@@ -2187,6 +2211,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
Trace.beginSection("KeyguardUpdateMonitor#handleStartedWakingUp");
Assert.isMainThread();
+ mAllowedDisplayStateForFaceAuth = true;
updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
if (mFaceWakeUpTriggersConfig.shouldTriggerFaceAuthOnWakeUpFrom(pmWakeReason)) {
FACE_AUTH_UPDATED_STARTED_WAKING_UP.setExtraInfo(pmWakeReason);
@@ -2342,7 +2367,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
Optional<FingerprintInteractiveToAuthProvider> interactiveToAuthProvider,
FeatureFlags featureFlags,
TaskStackChangeListeners taskStackChangeListeners,
- IActivityTaskManager activityTaskManagerService) {
+ IActivityTaskManager activityTaskManagerService,
+ DisplayTracker displayTracker) {
mContext = context;
mSubscriptionManager = subscriptionManager;
mUserTracker = userTracker;
@@ -2390,6 +2416,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
.collect(Collectors.toSet());
mTaskStackChangeListeners = taskStackChangeListeners;
mActivityTaskManager = activityTaskManagerService;
+ mDisplayTracker = displayTracker;
+ if (mFeatureFlags.isEnabled(Flags.STOP_FACE_AUTH_ON_DISPLAY_OFF)) {
+ mDisplayTracker.addDisplayChangeCallback(mDisplayCallback, mainExecutor);
+ }
mHandler = new Handler(mainLooper) {
@Override
@@ -3199,7 +3229,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
&& (!mSecureCameraLaunched || mAlternateBouncerShowing)
&& faceAndFpNotAuthenticated
&& !mGoingToSleep
- && isPostureAllowedForFaceAuth;
+ && isPostureAllowedForFaceAuth
+ && mAllowedDisplayStateForFaceAuth;
// Aggregate relevant fields for debug logging.
logListenerModelData(
@@ -3207,6 +3238,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
System.currentTimeMillis(),
user,
shouldListen,
+ mAllowedDisplayStateForFaceAuth,
mAlternateBouncerShowing,
mAuthInterruptActive,
biometricEnabledForUser,
@@ -4400,6 +4432,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mLockPatternUtils.unregisterStrongAuthTracker(mStrongAuthTracker);
mTrustManager.unregisterTrustListener(this);
+ mDisplayTracker.removeCallback(mDisplayCallback);
mHandler.removeCallbacksAndMessages(null);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 4845a6173be9..951a6aeef11b 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -25,6 +25,7 @@ import static com.android.keyguard.LockIconView.ICON_UNLOCK;
import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
import static com.android.systemui.flags.Flags.DOZING_MIGRATION_1;
import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
+import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
import android.content.res.Configuration;
@@ -39,6 +40,7 @@ import android.os.VibrationAttributes;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.MathUtils;
+import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
@@ -613,12 +615,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_HOVER_ENTER:
if (!mDownDetected && mAccessibilityManager.isTouchExplorationEnabled()) {
- mVibrator.vibrate(
- Process.myUid(),
- getContext().getOpPackageName(),
- UdfpsController.EFFECT_CLICK,
- "lock-icon-down",
- TOUCH_VIBRATION_ATTRIBUTES);
+ vibrateOnTouchExploration();
}
// The pointer that causes ACTION_DOWN is always at index 0.
@@ -699,13 +696,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mOnGestureDetectedRunnable.run();
}
- // play device entry haptic (same as biometric success haptic)
- mVibrator.vibrate(
- Process.myUid(),
- getContext().getOpPackageName(),
- UdfpsController.EFFECT_CLICK,
- "lock-screen-lock-icon-longpress",
- TOUCH_VIBRATION_ATTRIBUTES);
+ // play device entry haptic (consistent with UDFPS controller longpress)
+ vibrateOnLongPress();
mKeyguardViewController.showPrimaryBouncer(/* scrim */ true);
}
@@ -753,6 +745,37 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
});
}
+ @VisibleForTesting
+ void vibrateOnTouchExploration() {
+ if (mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) {
+ mVibrator.performHapticFeedback(
+ mView,
+ HapticFeedbackConstants.CONTEXT_CLICK
+ );
+ } else {
+ mVibrator.vibrate(
+ Process.myUid(),
+ getContext().getOpPackageName(),
+ UdfpsController.EFFECT_CLICK,
+ "lock-icon-down",
+ TOUCH_VIBRATION_ATTRIBUTES);
+ }
+ }
+
+ @VisibleForTesting
+ void vibrateOnLongPress() {
+ if (mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) {
+ mVibrator.performHapticFeedback(mView, UdfpsController.LONG_PRESS);
+ } else {
+ mVibrator.vibrate(
+ Process.myUid(),
+ getContext().getOpPackageName(),
+ UdfpsController.EFFECT_CLICK,
+ "lock-screen-lock-icon-longpress",
+ TOUCH_VIBRATION_ATTRIBUTES);
+ }
+ }
+
private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() {
@Override
public void onAllAuthenticatorsRegistered(@BiometricAuthenticator.Modality int modality) {
diff --git a/core/java/android/view/selectiontoolbar/ToolbarMenuItem.aidl b/packages/SystemUI/src/com/android/systemui/aconfig/AConfigModule.kt
index 711a85a7771e..251a699be38c 100644
--- a/core/java/android/view/selectiontoolbar/ToolbarMenuItem.aidl
+++ b/packages/SystemUI/src/com/android/systemui/aconfig/AConfigModule.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,9 +14,20 @@
* limitations under the License.
*/
-package android.view.selectiontoolbar;
+package com.android.systemui.aconfig
-/**
- * @hide
- */
-parcelable ToolbarMenuItem;
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Module
+import dagger.Provides
+
+@Module
+abstract class AConfigModule {
+ @Module
+ companion object {
+ @Provides
+ @SysUISingleton
+ fun providesImpl(): FeatureFlags {
+ return FeatureFlagsImpl()
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/aconfig/systemui.aconfig b/packages/SystemUI/src/com/android/systemui/aconfig/systemui.aconfig
new file mode 100644
index 000000000000..2d6e25776134
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/aconfig/systemui.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.systemui.aconfig"
+
+flag {
+ name: "example_flag"
+ namespace: "systemui"
+ description: "An Example Flag"
+ bug: "292511372"
+}
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/data/model/AuthenticationMethodModel.kt b/packages/SystemUI/src/com/android/systemui/authentication/data/model/AuthenticationMethodModel.kt
new file mode 100644
index 000000000000..6d23b11e5d66
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/authentication/data/model/AuthenticationMethodModel.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.authentication.data.model
+
+/** Enumerates all known authentication methods. */
+sealed class AuthenticationMethodModel(
+ /**
+ * Whether the authentication method is considered to be "secure".
+ *
+ * "Secure" authentication methods require authentication to unlock the device. Non-secure auth
+ * methods simply require user dismissal.
+ */
+ open val isSecure: Boolean,
+) {
+ /** There is no authentication method on the device. We shouldn't even show the lock screen. */
+ object None : AuthenticationMethodModel(isSecure = false)
+
+ object Pin : AuthenticationMethodModel(isSecure = true)
+
+ object Password : AuthenticationMethodModel(isSecure = true)
+
+ object Pattern : AuthenticationMethodModel(isSecure = true)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
index deb3d035d753..8d1fc5d9d558 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
@@ -14,15 +14,21 @@
* limitations under the License.
*/
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
package com.android.systemui.authentication.data.repository
+import android.app.admin.DevicePolicyManager
+import android.content.IntentFilter
+import android.os.UserHandle
import com.android.internal.widget.LockPatternChecker
import com.android.internal.widget.LockPatternUtils
import com.android.internal.widget.LockscreenCredential
import com.android.keyguard.KeyguardSecurityModel
-import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.authentication.data.model.AuthenticationMethodModel
import com.android.systemui.authentication.shared.model.AuthenticationResultModel
import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
+import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyguard.data.repository.KeyguardRepository
@@ -37,13 +43,17 @@ import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -54,9 +64,10 @@ interface AuthenticationRepository {
* Whether the device is unlocked.
*
* A device that is not yet unlocked requires unlocking by completing an authentication
- * challenge according to the current authentication method.
- *
- * Note that this state has no real bearing on whether the lockscreen is showing or dismissed.
+ * challenge according to the current authentication method, unless in cases when the current
+ * authentication method is not "secure" (for example, None); in such cases, the value of this
+ * flow will always be `true`, even if the lockscreen is showing and still needs to be dismissed
+ * by the user to proceed.
*/
val isUnlocked: StateFlow<Boolean>
@@ -86,8 +97,29 @@ interface AuthenticationRepository {
val throttling: StateFlow<AuthenticationThrottlingModel>
/**
+ * The currently-configured authentication method. This determines how the authentication
+ * challenge needs to be completed in order to unlock an otherwise locked device.
+ *
+ * Note: there may be other ways to unlock the device that "bypass" the need for this
+ * authentication challenge (notably, biometrics like fingerprint or face unlock).
+ *
+ * Note: by design, this is a [Flow] and not a [StateFlow]; a consumer who wishes to get a
+ * snapshot of the current authentication method without establishing a collector of the flow
+ * can do so by invoking [getAuthenticationMethod].
+ */
+ val authenticationMethod: Flow<AuthenticationMethodModel>
+
+ /**
* Returns the currently-configured authentication method. This determines how the
- * authentication challenge is completed in order to unlock an otherwise locked device.
+ * authentication challenge needs to be completed in order to unlock an otherwise locked device.
+ *
+ * Note: there may be other ways to unlock the device that "bypass" the need for this
+ * authentication challenge (notably, biometrics like fingerprint or face unlock).
+ *
+ * Note: by design, this is offered as a convenience method alongside [authenticationMethod].
+ * The flow should be used for code that wishes to stay up-to-date its logic as the
+ * authentication changes over time and this method should be used for simple code that only
+ * needs to check the current value.
*/
suspend fun getAuthenticationMethod(): AuthenticationMethodModel
@@ -141,6 +173,7 @@ constructor(
private val userRepository: UserRepository,
keyguardRepository: KeyguardRepository,
private val lockPatternUtils: LockPatternUtils,
+ broadcastDispatcher: BroadcastDispatcher,
) : AuthenticationRepository {
override val isUnlocked = keyguardRepository.isKeyguardUnlocked
@@ -148,7 +181,7 @@ constructor(
override suspend fun isLockscreenEnabled(): Boolean {
return withContext(backgroundDispatcher) {
val selectedUserId = userRepository.selectedUserId
- !lockPatternUtils.isLockPatternEnabled(selectedUserId)
+ !lockPatternUtils.isLockScreenDisabled(selectedUserId)
}
}
@@ -172,18 +205,31 @@ constructor(
private val UserRepository.selectedUserId: Int
get() = getSelectedUserInfo().id
+ override val authenticationMethod: Flow<AuthenticationMethodModel> =
+ userRepository.selectedUserInfo
+ .map { it.id }
+ .distinctUntilChanged()
+ .flatMapLatest { selectedUserId ->
+ broadcastDispatcher
+ .broadcastFlow(
+ filter =
+ IntentFilter(
+ DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
+ ),
+ user = UserHandle.of(selectedUserId),
+ )
+ .onStart { emit(Unit) }
+ .map { selectedUserId }
+ }
+ .map { selectedUserId ->
+ withContext(backgroundDispatcher) {
+ blockingAuthenticationMethodInternal(selectedUserId)
+ }
+ }
+
override suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
return withContext(backgroundDispatcher) {
- val selectedUserId = userRepository.selectedUserId
- when (getSecurityMode.apply(selectedUserId)) {
- KeyguardSecurityModel.SecurityMode.PIN,
- KeyguardSecurityModel.SecurityMode.SimPin,
- KeyguardSecurityModel.SecurityMode.SimPuk -> AuthenticationMethodModel.Pin
- KeyguardSecurityModel.SecurityMode.Password -> AuthenticationMethodModel.Password
- KeyguardSecurityModel.SecurityMode.Pattern -> AuthenticationMethodModel.Pattern
- KeyguardSecurityModel.SecurityMode.None -> AuthenticationMethodModel.None
- KeyguardSecurityModel.SecurityMode.Invalid -> error("Invalid security mode!")
- }
+ blockingAuthenticationMethodInternal(userRepository.selectedUserId)
}
}
@@ -301,6 +347,27 @@ constructor(
return flow.asStateFlow()
}
+
+ /**
+ * Returns the authentication method for the given user ID.
+ *
+ * WARNING: this is actually a blocking IPC/"binder" call that's expensive to do on the main
+ * thread. We keep it not marked as `suspend` because we want to be able to run this without a
+ * `runBlocking` which has a ton of performance/blocking problems.
+ */
+ private fun blockingAuthenticationMethodInternal(
+ userId: Int,
+ ): AuthenticationMethodModel {
+ return when (getSecurityMode.apply(userId)) {
+ KeyguardSecurityModel.SecurityMode.PIN,
+ KeyguardSecurityModel.SecurityMode.SimPin,
+ KeyguardSecurityModel.SecurityMode.SimPuk -> AuthenticationMethodModel.Pin
+ KeyguardSecurityModel.SecurityMode.Password -> AuthenticationMethodModel.Password
+ KeyguardSecurityModel.SecurityMode.Pattern -> AuthenticationMethodModel.Pattern
+ KeyguardSecurityModel.SecurityMode.None -> AuthenticationMethodModel.None
+ KeyguardSecurityModel.SecurityMode.Invalid -> error("Invalid security mode!")
+ }
+ }
}
@Module
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
index d4371bf30e0e..75192021dab6 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
@@ -18,8 +18,10 @@ package com.android.systemui.authentication.domain.interactor
import com.android.internal.widget.LockPatternView
import com.android.internal.widget.LockscreenCredential
+import com.android.systemui.authentication.data.model.AuthenticationMethodModel as DataLayerAuthenticationMethodModel
import com.android.systemui.authentication.data.repository.AuthenticationRepository
-import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.authentication.domain.model.AuthenticationMethodModel as DomainLayerAuthenticationMethodModel
+import com.android.systemui.authentication.shared.model.AuthenticationPatternCoordinate
import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -35,8 +37,10 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
@@ -56,21 +60,40 @@ constructor(
private val clock: SystemClock,
) {
/**
+ * The currently-configured authentication method. This determines how the authentication
+ * challenge needs to be completed in order to unlock an otherwise locked device.
+ *
+ * Note: there may be other ways to unlock the device that "bypass" the need for this
+ * authentication challenge (notably, biometrics like fingerprint or face unlock).
+ *
+ * Note: by design, this is a [Flow] and not a [StateFlow]; a consumer who wishes to get a
+ * snapshot of the current authentication method without establishing a collector of the flow
+ * can do so by invoking [getAuthenticationMethod].
+ *
+ * Note: this layer adds the synthetic authentication method of "swipe" which is special. When
+ * the current authentication method is "swipe", the user does not need to complete any
+ * authentication challenge to unlock the device; they just need to dismiss the lockscreen to
+ * get past it. This also means that the value of [isUnlocked] remains `false` even when the
+ * lockscreen is showing and still needs to be dismissed by the user to proceed.
+ */
+ val authenticationMethod: Flow<DomainLayerAuthenticationMethodModel> =
+ repository.authenticationMethod.map { rawModel -> rawModel.toDomainLayer() }
+
+ /**
* Whether the device is unlocked.
*
* A device that is not yet unlocked requires unlocking by completing an authentication
- * challenge according to the current authentication method.
- *
- * Note that this state has no real bearing on whether the lock screen is showing or dismissed.
+ * challenge according to the current authentication method, unless in cases when the current
+ * authentication method is not "secure" (for example, None and Swipe); in such cases, the value
+ * of this flow will always be `true`, even if the lockscreen is showing and still needs to be
+ * dismissed by the user to proceed.
*/
val isUnlocked: StateFlow<Boolean> =
- repository.isUnlocked
- .map { isUnlocked ->
- if (getAuthenticationMethod() is AuthenticationMethodModel.None) {
- true
- } else {
- isUnlocked
- }
+ combine(
+ repository.isUnlocked,
+ authenticationMethod,
+ ) { isUnlocked, authenticationMethod ->
+ authenticationMethod is DomainLayerAuthenticationMethodModel.None || isUnlocked
}
.stateIn(
scope = applicationScope,
@@ -129,18 +152,24 @@ constructor(
/**
* Returns the currently-configured authentication method. This determines how the
- * authentication challenge is completed in order to unlock an otherwise locked device.
+ * authentication challenge needs to be completed in order to unlock an otherwise locked device.
+ *
+ * Note: there may be other ways to unlock the device that "bypass" the need for this
+ * authentication challenge (notably, biometrics like fingerprint or face unlock).
+ *
+ * Note: by design, this is offered as a convenience method alongside [authenticationMethod].
+ * The flow should be used for code that wishes to stay up-to-date its logic as the
+ * authentication changes over time and this method should be used for simple code that only
+ * needs to check the current value.
+ *
+ * Note: this layer adds the synthetic authentication method of "swipe" which is special. When
+ * the current authentication method is "swipe", the user does not need to complete any
+ * authentication challenge to unlock the device; they just need to dismiss the lockscreen to
+ * get past it. This also means that the value of [isUnlocked] remains `false` even when the
+ * lockscreen is showing and still needs to be dismissed by the user to proceed.
*/
- suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
- val authMethod = repository.getAuthenticationMethod()
- return if (
- authMethod is AuthenticationMethodModel.None && repository.isLockscreenEnabled()
- ) {
- // We treat "None" as "Swipe" when the lockscreen is enabled.
- AuthenticationMethodModel.Swipe
- } else {
- authMethod
- }
+ suspend fun getAuthenticationMethod(): DomainLayerAuthenticationMethodModel {
+ return repository.getAuthenticationMethod().toDomainLayer()
}
/**
@@ -270,21 +299,38 @@ constructor(
}
}
- private fun AuthenticationMethodModel.createCredential(
+ private fun DomainLayerAuthenticationMethodModel.createCredential(
input: List<Any>
): LockscreenCredential? {
return when (this) {
- is AuthenticationMethodModel.Pin ->
+ is DomainLayerAuthenticationMethodModel.Pin ->
LockscreenCredential.createPin(input.joinToString(""))
- is AuthenticationMethodModel.Password ->
+ is DomainLayerAuthenticationMethodModel.Password ->
LockscreenCredential.createPassword(input.joinToString(""))
- is AuthenticationMethodModel.Pattern ->
+ is DomainLayerAuthenticationMethodModel.Pattern ->
LockscreenCredential.createPattern(
input
- .map { it as AuthenticationMethodModel.Pattern.PatternCoordinate }
+ .map { it as AuthenticationPatternCoordinate }
.map { LockPatternView.Cell.of(it.y, it.x) }
)
else -> null
}
}
+
+ private suspend fun DataLayerAuthenticationMethodModel.toDomainLayer():
+ DomainLayerAuthenticationMethodModel {
+ return when (this) {
+ is DataLayerAuthenticationMethodModel.None ->
+ if (repository.isLockscreenEnabled()) {
+ DomainLayerAuthenticationMethodModel.Swipe
+ } else {
+ DomainLayerAuthenticationMethodModel.None
+ }
+ is DataLayerAuthenticationMethodModel.Pin -> DomainLayerAuthenticationMethodModel.Pin
+ is DataLayerAuthenticationMethodModel.Password ->
+ DomainLayerAuthenticationMethodModel.Password
+ is DataLayerAuthenticationMethodModel.Pattern ->
+ DomainLayerAuthenticationMethodModel.Pattern
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/model/AuthenticationMethodModel.kt
index 97c6697f10a5..d7e6099a8908 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/model/AuthenticationMethodModel.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.authentication.shared.model
+package com.android.systemui.authentication.domain.model
/** Enumerates all known authentication methods. */
sealed class AuthenticationMethodModel(
@@ -36,10 +36,5 @@ sealed class AuthenticationMethodModel(
object Password : AuthenticationMethodModel(isSecure = true)
- object Pattern : AuthenticationMethodModel(isSecure = true) {
- data class PatternCoordinate(
- val x: Int,
- val y: Int,
- )
- }
+ object Pattern : AuthenticationMethodModel(isSecure = true)
}
diff --git a/core/java/android/view/selectiontoolbar/WidgetInfo.aidl b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationPatternCoordinate.kt
index 1057c516e233..8a3f780b3e54 100644
--- a/core/java/android/view/selectiontoolbar/WidgetInfo.aidl
+++ b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationPatternCoordinate.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.view.selectiontoolbar;
+package com.android.systemui.authentication.shared.model
-/**
- * @hide
- */
-parcelable WidgetInfo;
+data class AuthenticationPatternCoordinate(
+ val x: Int,
+ val y: Int,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/battery/AccessorizedBatteryDrawable.kt b/packages/SystemUI/src/com/android/systemui/battery/AccessorizedBatteryDrawable.kt
index b34f1b45d763..b81d7fced5e4 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/AccessorizedBatteryDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/battery/AccessorizedBatteryDrawable.kt
@@ -178,6 +178,11 @@ class AccessorizedBatteryDrawable(
mainBatteryDrawable.charging = charging
}
+ /** Returns whether the battery is currently charging. */
+ fun getCharging(): Boolean {
+ return mainBatteryDrawable.charging
+ }
+
/** Sets the current level (out of 100) of the battery. */
fun setBatteryLevel(level: Int) {
mainBatteryDrawable.setBatteryLevel(level)
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
index 46fcdbc909b6..87ea4111d8c8 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
@@ -77,8 +77,9 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver {
private int mShowPercentMode = MODE_DEFAULT;
private boolean mShowPercentAvailable;
private String mEstimateText = null;
- private boolean mCharging;
+ private boolean mPluggedIn;
private boolean mIsBatteryDefender;
+ private boolean mIsIncompatibleCharging;
private boolean mDisplayShieldEnabled;
// Error state where we know nothing about the current battery state
private boolean mBatteryStateUnknown;
@@ -202,10 +203,10 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver {
* @param pluggedIn whether the device is plugged in or not
*/
public void onBatteryLevelChanged(@IntRange(from = 0, to = 100) int level, boolean pluggedIn) {
- mDrawable.setCharging(pluggedIn);
- mDrawable.setBatteryLevel(level);
- mCharging = pluggedIn;
+ mPluggedIn = pluggedIn;
mLevel = level;
+ mDrawable.setCharging(isCharging());
+ mDrawable.setBatteryLevel(level);
updatePercentText();
}
@@ -224,6 +225,15 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver {
}
}
+ void onIsIncompatibleChargingChanged(boolean isIncompatibleCharging) {
+ boolean valueChanged = mIsIncompatibleCharging != isIncompatibleCharging;
+ mIsIncompatibleCharging = isIncompatibleCharging;
+ if (valueChanged) {
+ mDrawable.setCharging(isCharging());
+ updateContentDescription();
+ }
+ }
+
private TextView loadPercentView() {
return (TextView) LayoutInflater.from(getContext())
.inflate(R.layout.battery_percentage_view, null);
@@ -263,7 +273,7 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver {
}
if (mBatteryPercentView != null) {
- if (mShowPercentMode == MODE_ESTIMATE && !mCharging) {
+ if (mShowPercentMode == MODE_ESTIMATE && !isCharging()) {
mBatteryEstimateFetcher.fetchBatteryTimeRemainingEstimate(
(String estimate) -> {
if (mBatteryPercentView == null) {
@@ -316,7 +326,7 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver {
} else if (mIsBatteryDefender) {
contentDescription =
context.getString(R.string.accessibility_battery_level_charging_paused, mLevel);
- } else if (mCharging) {
+ } else if (isCharging()) {
contentDescription =
context.getString(R.string.accessibility_battery_level_charging, mLevel);
} else {
@@ -464,16 +474,24 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver {
}
}
+ private boolean isCharging() {
+ return mPluggedIn && !mIsIncompatibleCharging;
+ }
+
public void dump(PrintWriter pw, String[] args) {
String powerSave = mDrawable == null ? null : mDrawable.getPowerSaveEnabled() + "";
String displayShield = mDrawable == null ? null : mDrawable.getDisplayShield() + "";
+ String charging = mDrawable == null ? null : mDrawable.getCharging() + "";
CharSequence percent = mBatteryPercentView == null ? null : mBatteryPercentView.getText();
pw.println(" BatteryMeterView:");
pw.println(" mDrawable.getPowerSave: " + powerSave);
pw.println(" mDrawable.getDisplayShield: " + displayShield);
+ pw.println(" mDrawable.getCharging: " + charging);
pw.println(" mBatteryPercentView.getText(): " + percent);
pw.println(" mTextColor: #" + Integer.toHexString(mTextColor));
pw.println(" mBatteryStateUnknown: " + mBatteryStateUnknown);
+ pw.println(" mIsIncompatibleCharging: " + mIsIncompatibleCharging);
+ pw.println(" mPluggedIn: " + mPluggedIn);
pw.println(" mLevel: " + mLevel);
pw.println(" mMode: " + mShowPercentMode);
}
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
index 6a5749cc5571..0ca38834960c 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
@@ -32,6 +32,8 @@ import androidx.annotation.NonNull;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarLocation;
@@ -50,6 +52,7 @@ public class BatteryMeterViewController extends ViewController<BatteryMeterView>
private final TunerService mTunerService;
private final Handler mMainHandler;
private final ContentResolver mContentResolver;
+ private final FeatureFlags mFeatureFlags;
private final BatteryController mBatteryController;
private final String mSlotBattery;
@@ -99,6 +102,13 @@ public class BatteryMeterViewController extends ViewController<BatteryMeterView>
}
@Override
+ public void onIsIncompatibleChargingChanged(boolean isIncompatibleCharging) {
+ if (mFeatureFlags.isEnabled(Flags.INCOMPATIBLE_CHARGING_BATTERY_ICON)) {
+ mView.onIsIncompatibleChargingChanged(isIncompatibleCharging);
+ }
+ }
+
+ @Override
public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
pw.print(super.toString());
pw.println(" location=" + mLocation);
@@ -129,6 +139,7 @@ public class BatteryMeterViewController extends ViewController<BatteryMeterView>
TunerService tunerService,
@Main Handler mainHandler,
ContentResolver contentResolver,
+ FeatureFlags featureFlags,
BatteryController batteryController) {
super(view);
mLocation = location;
@@ -137,6 +148,7 @@ public class BatteryMeterViewController extends ViewController<BatteryMeterView>
mTunerService = tunerService;
mMainHandler = mainHandler;
mContentResolver = contentResolver;
+ mFeatureFlags = featureFlags;
mBatteryController = batteryController;
mView.setBatteryEstimateFetcher(mBatteryController::getEstimatedTimeRemainingString);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index 063f62e19686..869d0846e0ae 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -186,7 +186,7 @@ constructor(
}
private fun listenForAlternateBouncerVisibility() {
- alternateBouncerInteractor.setAlternateBouncerUIAvailable(true)
+ alternateBouncerInteractor.setAlternateBouncerUIAvailable(true, "SideFpsController")
scope.launch {
alternateBouncerInteractor.isVisible.collect { isVisible: Boolean ->
if (isVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
index 15bd73193687..db30a55ea1e1 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt
@@ -83,6 +83,7 @@ constructor(
dumpManager,
),
UdfpsKeyguardViewControllerAdapter {
+ private val uniqueIdentifier = this.toString()
private val useExpandedOverlay: Boolean =
featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)
private var showingUdfpsBouncer = false
@@ -282,7 +283,7 @@ constructor(
public override fun onViewAttached() {
super.onViewAttached()
- alternateBouncerInteractor.setAlternateBouncerUIAvailable(true)
+ alternateBouncerInteractor.setAlternateBouncerUIAvailable(true, uniqueIdentifier)
val dozeAmount = statusBarStateController.dozeAmount
lastDozeAmount = dozeAmount
stateListener.onDozeAmountChanged(dozeAmount, dozeAmount)
@@ -312,7 +313,7 @@ constructor(
override fun onViewDetached() {
super.onViewDetached()
- alternateBouncerInteractor.setAlternateBouncerUIAvailable(false)
+ alternateBouncerInteractor.setAlternateBouncerUIAvailable(false, uniqueIdentifier)
faceDetectRunning = false
keyguardStateController.removeCallback(keyguardStateControllerCallback)
statusBarStateController.removeCallback(stateListener)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/controller/UdfpsKeyguardViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/controller/UdfpsKeyguardViewController.kt
index 2a9f3eafc776..c9b1624d4d50 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/controller/UdfpsKeyguardViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/controller/UdfpsKeyguardViewController.kt
@@ -46,6 +46,7 @@ open class UdfpsKeyguardViewController(
dumpManager,
),
UdfpsKeyguardViewControllerAdapter {
+ private val uniqueIdentifier = this.toString()
override val tag: String
get() = TAG
@@ -55,12 +56,12 @@ open class UdfpsKeyguardViewController(
public override fun onViewAttached() {
super.onViewAttached()
- alternateBouncerInteractor.setAlternateBouncerUIAvailable(true)
+ alternateBouncerInteractor.setAlternateBouncerUIAvailable(true, uniqueIdentifier)
}
public override fun onViewDetached() {
super.onViewDetached()
- alternateBouncerInteractor.setAlternateBouncerUIAvailable(false)
+ alternateBouncerInteractor.setAlternateBouncerUIAvailable(false, uniqueIdentifier)
}
override fun shouldPauseAuth(): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
index e3e9b3a3754a..98ae54b1340e 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
@@ -40,6 +40,7 @@ constructor(
) {
var receivedDownTouch = false
val isVisible: Flow<Boolean> = bouncerRepository.alternateBouncerVisible
+ private val alternateBouncerUiAvailableFromSource: HashSet<String> = HashSet()
/**
* Sets the correct bouncer states to show the alternate bouncer if it can show.
@@ -69,8 +70,15 @@ constructor(
return bouncerRepository.alternateBouncerVisible.value
}
- fun setAlternateBouncerUIAvailable(isAvailable: Boolean) {
- bouncerRepository.setAlternateBouncerUIAvailable(isAvailable)
+ fun setAlternateBouncerUIAvailable(isAvailable: Boolean, token: String) {
+ if (isAvailable) {
+ alternateBouncerUiAvailableFromSource.add(token)
+ } else {
+ alternateBouncerUiAvailableFromSource.remove(token)
+ }
+ bouncerRepository.setAlternateBouncerUIAvailable(
+ alternateBouncerUiAvailableFromSource.isNotEmpty()
+ )
}
fun canShowAlternateBouncerForFingerprint(): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
index 8ed964d4af22..1bf3a9ead08e 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-@file:OptIn(ExperimentalCoroutinesApi::class)
-
package com.android.systemui.bouncer.domain.interactor
import android.content.Context
import com.android.systemui.R
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
-import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
import com.android.systemui.bouncer.data.repository.BouncerRepository
import com.android.systemui.dagger.SysUISingleton
@@ -35,7 +33,6 @@ import com.android.systemui.util.kotlin.pairwise
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
@@ -107,14 +104,6 @@ constructor(
}
/**
- * Returns the currently-configured authentication method. This determines how the
- * authentication challenge is completed in order to unlock an otherwise locked device.
- */
- suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
- return authenticationInteractor.getAuthenticationMethod()
- }
-
- /**
* Either shows the bouncer or unlocks the device, if the bouncer doesn't need to be shown.
*
* @param message An optional message to show to the user in the bouncer.
@@ -124,13 +113,15 @@ constructor(
) {
applicationScope.launch {
if (authenticationInteractor.isAuthenticationRequired()) {
- repository.setMessage(message ?: promptMessage(getAuthenticationMethod()))
- sceneInteractor.setCurrentScene(
+ repository.setMessage(
+ message ?: promptMessage(authenticationInteractor.getAuthenticationMethod())
+ )
+ sceneInteractor.changeScene(
scene = SceneModel(SceneKey.Bouncer),
loggingReason = "request to unlock device while authentication required",
)
} else {
- sceneInteractor.setCurrentScene(
+ sceneInteractor.changeScene(
scene = SceneModel(SceneKey.Gone),
loggingReason = "request to unlock device while authentication isn't required",
)
@@ -143,7 +134,9 @@ constructor(
* method.
*/
fun resetMessage() {
- applicationScope.launch { repository.setMessage(promptMessage(getAuthenticationMethod())) }
+ applicationScope.launch {
+ repository.setMessage(promptMessage(authenticationInteractor.getAuthenticationMethod()))
+ }
}
/** Removes the user-facing message. */
@@ -176,12 +169,12 @@ constructor(
authenticationInteractor.authenticate(input, tryAutoConfirm) ?: return null
if (isAuthenticated) {
- sceneInteractor.setCurrentScene(
+ sceneInteractor.changeScene(
scene = SceneModel(SceneKey.Gone),
loggingReason = "successful authentication",
)
} else {
- repository.setMessage(errorMessage(getAuthenticationMethod()))
+ repository.setMessage(errorMessage(authenticationInteractor.getAuthenticationMethod()))
}
return isAuthenticated
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
index d9ec5d0d1744..56f1cf661cda 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
@@ -121,7 +121,7 @@ object KeyguardBouncerViewBinder {
view.visibility = if (isShowing) View.VISIBLE else View.INVISIBLE
if (isShowing) {
// Reset security container because these views are not reinflated.
- securityContainerController.reset()
+ securityContainerController.prepareToShow()
securityContainerController.reinflateViewFlipper {
// Reset Security Container entirely.
securityContainerController.onBouncerVisibilityChanged(
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
index 68e1a29bc609..5b1998d1e5f6 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
@@ -14,25 +14,20 @@
* limitations under the License.
*/
-@file:OptIn(ExperimentalCoroutinesApi::class)
-
package com.android.systemui.bouncer.ui.viewmodel
import android.content.Context
import com.android.systemui.R
-import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
+import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
-import com.android.systemui.util.kotlin.pairwise
import javax.inject.Inject
import kotlin.math.ceil
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.channels.BufferOverflow
-import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -50,23 +45,24 @@ class BouncerViewModel
constructor(
@Application private val applicationContext: Context,
@Application private val applicationScope: CoroutineScope,
- private val interactor: BouncerInteractor,
+ private val bouncerInteractor: BouncerInteractor,
+ private val authenticationInteractor: AuthenticationInteractor,
featureFlags: FeatureFlags,
) {
private val isInputEnabled: StateFlow<Boolean> =
- interactor.isThrottled
+ bouncerInteractor.isThrottled
.map { !it }
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = !interactor.isThrottled.value,
+ initialValue = !bouncerInteractor.isThrottled.value,
)
private val pin: PinBouncerViewModel by lazy {
PinBouncerViewModel(
applicationContext = applicationContext,
applicationScope = applicationScope,
- interactor = interactor,
+ interactor = bouncerInteractor,
isInputEnabled = isInputEnabled,
)
}
@@ -74,7 +70,7 @@ constructor(
private val password: PasswordBouncerViewModel by lazy {
PasswordBouncerViewModel(
applicationScope = applicationScope,
- interactor = interactor,
+ interactor = bouncerInteractor,
isInputEnabled = isInputEnabled,
)
}
@@ -83,31 +79,35 @@ constructor(
PatternBouncerViewModel(
applicationContext = applicationContext,
applicationScope = applicationScope,
- interactor = interactor,
+ interactor = bouncerInteractor,
isInputEnabled = isInputEnabled,
)
}
/** View-model for the current UI, based on the current authentication method. */
- private val _authMethod =
- MutableSharedFlow<AuthMethodBouncerViewModel?>(
- replay = 1,
- onBufferOverflow = BufferOverflow.DROP_OLDEST,
- )
val authMethod: StateFlow<AuthMethodBouncerViewModel?> =
- _authMethod.stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = null,
- )
+ authenticationInteractor.authenticationMethod
+ .map { authenticationMethod ->
+ when (authenticationMethod) {
+ is AuthenticationMethodModel.Pin -> pin
+ is AuthenticationMethodModel.Password -> password
+ is AuthenticationMethodModel.Pattern -> pattern
+ else -> null
+ }
+ }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = null,
+ )
init {
if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
applicationScope.launch {
- interactor.isThrottled
+ bouncerInteractor.isThrottled
.map { isThrottled ->
if (isThrottled) {
- when (interactor.getAuthenticationMethod()) {
+ when (authenticationInteractor.getAuthenticationMethod()) {
is AuthenticationMethodModel.Pin ->
R.string.kg_too_many_failed_pin_attempts_dialog_message
is AuthenticationMethodModel.Password ->
@@ -118,8 +118,9 @@ constructor(
}?.let { stringResourceId ->
applicationContext.getString(
stringResourceId,
- interactor.throttling.value.failedAttemptCount,
- ceil(interactor.throttling.value.remainingMs / 1000f).toInt(),
+ bouncerInteractor.throttling.value.failedAttemptCount,
+ ceil(bouncerInteractor.throttling.value.remainingMs / 1000f)
+ .toInt(),
)
}
} else {
@@ -133,25 +134,14 @@ constructor(
}
}
}
-
- applicationScope.launch {
- _authMethod.subscriptionCount
- .pairwise()
- .map { (previousCount, currentCount) -> currentCount > previousCount }
- .collect { subscriberAdded ->
- if (subscriberAdded) {
- reloadAuthMethod()
- }
- }
- }
}
}
/** The user-facing message to show in the bouncer. */
val message: StateFlow<MessageViewModel> =
combine(
- interactor.message,
- interactor.isThrottled,
+ bouncerInteractor.message,
+ bouncerInteractor.isThrottled,
) { message, isThrottled ->
toMessageViewModel(message, isThrottled)
}
@@ -160,8 +150,8 @@ constructor(
started = SharingStarted.WhileSubscribed(),
initialValue =
toMessageViewModel(
- message = interactor.message.value,
- isThrottled = interactor.isThrottled.value,
+ message = bouncerInteractor.message.value,
+ isThrottled = bouncerInteractor.isThrottled.value,
),
)
@@ -197,17 +187,6 @@ constructor(
)
}
- private suspend fun reloadAuthMethod() {
- _authMethod.tryEmit(
- when (interactor.getAuthenticationMethod()) {
- is AuthenticationMethodModel.Pin -> pin
- is AuthenticationMethodModel.Password -> password
- is AuthenticationMethodModel.Pattern -> pattern
- else -> null
- }
- )
- }
-
data class MessageViewModel(
val text: String,
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
index 4be539d9396d..4425f9ffcb5e 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
@@ -18,7 +18,7 @@ package com.android.systemui.bouncer.ui.viewmodel
import android.content.Context
import android.util.TypedValue
-import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.authentication.shared.model.AuthenticationPatternCoordinate
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import kotlin.math.max
import kotlin.math.min
@@ -193,8 +193,8 @@ data class PatternDotViewModel(
val x: Int,
val y: Int,
) {
- fun toCoordinate(): AuthenticationMethodModel.Pattern.PatternCoordinate {
- return AuthenticationMethodModel.Pattern.PatternCoordinate(
+ fun toCoordinate(): AuthenticationPatternCoordinate {
+ return AuthenticationPatternCoordinate(
x = x,
y = y,
)
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index f6257c46e6a7..970d00b2f4bd 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -29,6 +29,7 @@ import com.android.systemui.BootCompleteCache;
import com.android.systemui.BootCompleteCacheImpl;
import com.android.systemui.accessibility.AccessibilityModule;
import com.android.systemui.accessibility.data.repository.AccessibilityRepositoryModule;
+import com.android.systemui.aconfig.AConfigModule;
import com.android.systemui.appops.dagger.AppOpsModule;
import com.android.systemui.assist.AssistModule;
import com.android.systemui.authentication.AuthenticationModule;
@@ -156,6 +157,7 @@ import javax.inject.Named;
@Module(includes = {
AccessibilityModule.class,
AccessibilityRepositoryModule.class,
+ AConfigModule.class,
AppOpsModule.class,
AssistModule.class,
AuthenticationModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
index 2c11d78f534b..4c78e4ce4fe4 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
@@ -32,7 +32,6 @@ import android.content.IntentFilter;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.UserHandle;
-import android.provider.DeviceConfig;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -94,8 +93,7 @@ public class FeatureFlagsDebug implements FeatureFlags {
shouldRestart = true;
}
} else if (mStringFlagCache.containsKey(flag.getName())) {
- String newValue = value == null ? "" : value;
- if (mStringFlagCache.get(flag.getName()) != value) {
+ if (!mStringFlagCache.get(flag.getName()).equals(value)) {
shouldRestart = true;
}
} else if (mIntFlagCache.containsKey(flag.getName())) {
@@ -203,8 +201,7 @@ public class FeatureFlagsDebug implements FeatureFlags {
String name = flag.getName();
if (!mStringFlagCache.containsKey(name)) {
mStringFlagCache.put(name,
- readFlagValueInternal(
- flag.getId(), name, flag.getDefault(), StringFlagSerializer.INSTANCE));
+ readFlagValueInternal(name, flag.getDefault(), StringFlagSerializer.INSTANCE));
}
return mStringFlagCache.get(name);
@@ -216,36 +213,30 @@ public class FeatureFlagsDebug implements FeatureFlags {
String name = flag.getName();
if (!mStringFlagCache.containsKey(name)) {
mStringFlagCache.put(name,
- readFlagValueInternal(
- flag.getId(), name, mResources.getString(flag.getResourceId()),
+ readFlagValueInternal(name, mResources.getString(flag.getResourceId()),
StringFlagSerializer.INSTANCE));
}
return mStringFlagCache.get(name);
}
-
- @NonNull
@Override
public int getInt(@NonNull IntFlag flag) {
String name = flag.getName();
if (!mIntFlagCache.containsKey(name)) {
mIntFlagCache.put(name,
- readFlagValueInternal(
- flag.getId(), name, flag.getDefault(), IntFlagSerializer.INSTANCE));
+ readFlagValueInternal(name, flag.getDefault(), IntFlagSerializer.INSTANCE));
}
return mIntFlagCache.get(name);
}
- @NonNull
@Override
public int getInt(@NonNull ResourceIntFlag flag) {
String name = flag.getName();
if (!mIntFlagCache.containsKey(name)) {
mIntFlagCache.put(name,
- readFlagValueInternal(
- flag.getId(), name, mResources.getInteger(flag.getResourceId()),
+ readFlagValueInternal(name, mResources.getInteger(flag.getResourceId()),
IntFlagSerializer.INSTANCE));
}
@@ -255,13 +246,6 @@ public class FeatureFlagsDebug implements FeatureFlags {
/** Specific override for Boolean flags that checks against the teamfood list.*/
private boolean readBooleanFlagInternal(Flag<Boolean> flag, boolean defaultValue) {
Boolean result = readBooleanFlagOverride(flag.getName());
- if (result == null) {
- result = readBooleanFlagOverride(flag.getId());
- if (result != null) {
- // Move overrides from id to name
- setFlagValueInternal(flag.getName(), result, BooleanFlagSerializer.INSTANCE);
- }
- }
boolean hasServerOverride = mServerFlagReader.hasOverride(
flag.getNamespace(), flag.getName());
@@ -279,45 +263,22 @@ public class FeatureFlagsDebug implements FeatureFlags {
flag.getNamespace(), flag.getName(), defaultValue) : result;
}
- private Boolean readBooleanFlagOverride(int id) {
- return readFlagValueInternal(id, BooleanFlagSerializer.INSTANCE);
- }
private Boolean readBooleanFlagOverride(String name) {
return readFlagValueInternal(name, BooleanFlagSerializer.INSTANCE);
}
- // TODO(b/265188950): Remove id from this method once ids are fully deprecated.
@NonNull
private <T> T readFlagValueInternal(
- int id, String name, @NonNull T defaultValue, FlagSerializer<T> serializer) {
+ String name, @NonNull T defaultValue, FlagSerializer<T> serializer) {
requireNonNull(defaultValue, "defaultValue");
T resultForName = readFlagValueInternal(name, serializer);
if (resultForName == null) {
- T resultForId = readFlagValueInternal(id, serializer);
- if (resultForId == null) {
- return defaultValue;
- } else {
- setFlagValue(name, resultForId, serializer);
- return resultForId;
- }
+ return defaultValue;
}
return resultForName;
}
-
- /** Returns the stored value or null if not set. */
- // TODO(b/265188950): Remove method this once ids are fully deprecated.
- @Nullable
- private <T> T readFlagValueInternal(int id, FlagSerializer<T> serializer) {
- try {
- return mFlagManager.readFlagValue(id, serializer);
- } catch (Exception e) {
- eraseInternal(id);
- }
- return null;
- }
-
/** Returns the stored value or null if not set. */
@Nullable
private <T> T readFlagValueInternal(String name, FlagSerializer<T> serializer) {
@@ -385,15 +346,6 @@ public class FeatureFlagsDebug implements FeatureFlags {
}
/** Works just like {@link #eraseFlag(String)} except that it doesn't restart SystemUI. */
- // TODO(b/265188950): Remove method this once ids are fully deprecated.
- private void eraseInternal(int id) {
- // We can't actually "erase" things from settings, but we can set them to empty!
- mGlobalSettings.putStringForUser(mFlagManager.idToSettingsKey(id), "",
- UserHandle.USER_CURRENT);
- Log.i(TAG, "Erase name " + id);
- }
-
- /** Works just like {@link #eraseFlag(String)} except that it doesn't restart SystemUI. */
private void eraseInternal(String name) {
// We can't actually "erase" things from settings, but we can set them to empty!
mGlobalSettings.putStringForUser(mFlagManager.nameToSettingsKey(name), "",
@@ -434,7 +386,7 @@ public class FeatureFlagsDebug implements FeatureFlags {
setFlagValue(flag.getName(), value, BooleanFlagSerializer.INSTANCE);
} else if (flag instanceof SysPropBooleanFlag) {
// Store SysProp flags in SystemProperties where they can read by outside parties.
- mSystemProperties.setBoolean(((SysPropBooleanFlag) flag).getName(), value);
+ mSystemProperties.setBoolean(flag.getName(), value);
dispatchListenersAndMaybeRestart(
flag.getName(),
suppressRestart -> restartSystemUI(
@@ -527,7 +479,7 @@ public class FeatureFlagsDebug implements FeatureFlags {
}
} catch (IllegalArgumentException e) {
Log.w(TAG,
- "Unable to set " + flag.getId() + " of type " + flag.getClass()
+ "Unable to set " + flag.getName() + " of type " + flag.getClass()
+ " to value of type " + (value == null ? null : value.getClass()));
}
}
@@ -545,21 +497,18 @@ public class FeatureFlagsDebug implements FeatureFlags {
if (f instanceof ReleasedFlag) {
enabled = isEnabled((ReleasedFlag) f);
- overridden = readBooleanFlagOverride(f.getName()) != null
- || readBooleanFlagOverride(f.getId()) != null;
+ overridden = readBooleanFlagOverride(f.getName()) != null;
} else if (f instanceof UnreleasedFlag) {
enabled = isEnabled((UnreleasedFlag) f);
- overridden = readBooleanFlagOverride(f.getName()) != null
- || readBooleanFlagOverride(f.getId()) != null;
+ overridden = readBooleanFlagOverride(f.getName()) != null;
} else if (f instanceof ResourceBooleanFlag) {
enabled = isEnabled((ResourceBooleanFlag) f);
- overridden = readBooleanFlagOverride(f.getName()) != null
- || readBooleanFlagOverride(f.getId()) != null;
+ overridden = readBooleanFlagOverride(f.getName()) != null;
} else if (f instanceof SysPropBooleanFlag) {
// TODO(b/223379190): Teamfood not supported for sysprop flags yet.
enabled = isEnabled((SysPropBooleanFlag) f);
teamfood = false;
- overridden = !mSystemProperties.get(((SysPropBooleanFlag) f).getName()).isEmpty();
+ overridden = !mSystemProperties.get(f.getName()).isEmpty();
} else {
// TODO: add support for other flag types.
Log.w(TAG, "Unsupported Flag Type. Please file a bug.");
@@ -567,11 +516,9 @@ public class FeatureFlagsDebug implements FeatureFlags {
}
if (enabled) {
- return new ReleasedFlag(
- f.getId(), f.getName(), f.getNamespace(), teamfood, overridden);
+ return new ReleasedFlag(f.getName(), f.getNamespace(), teamfood, overridden);
} else {
- return new UnreleasedFlag(
- f.getId(), f.getName(), f.getNamespace(), teamfood, overridden);
+ return new UnreleasedFlag(f.getName(), f.getNamespace(), teamfood, overridden);
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java
index 9d19a7dc4604..e03b43873e05 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java
@@ -67,7 +67,7 @@ public class FeatureFlagsRelease implements FeatureFlags {
}
} else if (mStringCache.containsKey(flag.getName())) {
String newValue = value == null ? "" : value;
- if (mStringCache.get(flag.getName()) != newValue) {
+ if (!mStringCache.get(flag.getName()).equals(newValue)) {
shouldRestart = true;
}
} else if (mIntCache.containsKey(flag.getName())) {
@@ -185,14 +185,12 @@ public class FeatureFlagsRelease implements FeatureFlags {
return mStringCache.get(name);
}
- @NonNull
@Override
public int getInt(@NonNull IntFlag flag) {
// Fill the cache.
return getIntInternal(flag.getName(), flag.getDefault());
}
- @NonNull
@Override
public int getInt(@NonNull ResourceIntFlag flag) {
// Fill the cache.
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java b/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java
index daf9429344a7..bd0ed482c961 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java
@@ -219,17 +219,6 @@ public class FlagCommand implements Command {
return 0;
}
- private int flagNameToId(String flagName) {
- Map<String, Flag<?>> flagFields = FlagsFactory.INSTANCE.getKnownFlags();
- for (String fieldName : flagFields.keySet()) {
- if (flagName.equals(fieldName)) {
- return flagFields.get(fieldName).getId();
- }
- }
-
- return 0;
- }
-
private void printKnownFlags(PrintWriter pw) {
Map<String, Flag<?>> fields = FlagsFactory.INSTANCE.getKnownFlags();
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index ab219371ffc6..e77d355ac15f 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -36,30 +36,29 @@ import com.android.systemui.flags.FlagsFactory.unreleasedFlag
* See [FeatureFlagsDebug] for instructions on flipping the flags via adb.
*/
object Flags {
- @JvmField val TEAMFOOD = unreleasedFlag(1, "teamfood")
+ @JvmField val TEAMFOOD = unreleasedFlag("teamfood")
// 100 - notification
// TODO(b/254512751): Tracking Bug
val NOTIFICATION_PIPELINE_DEVELOPER_LOGGING =
- unreleasedFlag(103, "notification_pipeline_developer_logging")
+ unreleasedFlag("notification_pipeline_developer_logging")
// TODO(b/254512732): Tracking Bug
- @JvmField val NSSL_DEBUG_LINES = unreleasedFlag(105, "nssl_debug_lines")
+ @JvmField val NSSL_DEBUG_LINES = unreleasedFlag("nssl_debug_lines")
// TODO(b/254512505): Tracking Bug
- @JvmField val NSSL_DEBUG_REMOVE_ANIMATION = unreleasedFlag(106, "nssl_debug_remove_animation")
+ @JvmField val NSSL_DEBUG_REMOVE_ANIMATION = unreleasedFlag("nssl_debug_remove_animation")
// TODO(b/254512624): Tracking Bug
@JvmField
val NOTIFICATION_DRAG_TO_CONTENTS =
resourceBooleanFlag(
- 108,
R.bool.config_notificationToContents,
"notification_drag_to_contents"
)
// TODO(b/254512538): Tracking Bug
- val INSTANT_VOICE_REPLY = unreleasedFlag(111, "instant_voice_reply")
+ val INSTANT_VOICE_REPLY = unreleasedFlag("instant_voice_reply")
/**
* This flag controls whether we register a listener for StatsD notification memory reports.
@@ -67,48 +66,47 @@ object Flags {
* enabled as well.
*/
val NOTIFICATION_MEMORY_LOGGING_ENABLED =
- releasedFlag(119, "notification_memory_logging_enabled")
+ releasedFlag("notification_memory_logging_enabled")
// TODO(b/260335638): Tracking Bug
@JvmField
val NOTIFICATION_INLINE_REPLY_ANIMATION =
- unreleasedFlag(174148361, "notification_inline_reply_animation")
+ unreleasedFlag("notification_inline_reply_animation")
/** Makes sure notification panel is updated before the user switch is complete. */
// TODO(b/278873737): Tracking Bug
@JvmField
val LOAD_NOTIFICATIONS_BEFORE_THE_USER_SWITCH_IS_COMPLETE =
- releasedFlag(278873737, "load_notifications_before_the_user_switch_is_complete")
+ releasedFlag("load_notifications_before_the_user_switch_is_complete")
// TODO(b/277338665): Tracking Bug
@JvmField
val NOTIFICATION_SHELF_REFACTOR =
- unreleasedFlag(271161129, "notification_shelf_refactor", teamfood = true)
+ unreleasedFlag("notification_shelf_refactor", teamfood = true)
// TODO(b/290787599): Tracking Bug
@JvmField
val NOTIFICATION_ICON_CONTAINER_REFACTOR =
- unreleasedFlag(278765923, "notification_icon_container_refactor")
+ unreleasedFlag("notification_icon_container_refactor")
// TODO(b/288326013): Tracking Bug
@JvmField
val NOTIFICATION_ASYNC_HYBRID_VIEW_INFLATION =
- unreleasedFlag(288326013, "notification_async_hybrid_view_inflation", teamfood = false)
+ unreleasedFlag("notification_async_hybrid_view_inflation", teamfood = false)
@JvmField
val ANIMATED_NOTIFICATION_SHADE_INSETS =
- releasedFlag(270682168, "animated_notification_shade_insets")
+ releasedFlag("animated_notification_shade_insets")
// TODO(b/268005230): Tracking Bug
@JvmField
- val SENSITIVE_REVEAL_ANIM = unreleasedFlag(268005230, "sensitive_reveal_anim", teamfood = true)
+ val SENSITIVE_REVEAL_ANIM = unreleasedFlag("sensitive_reveal_anim", teamfood = true)
// TODO(b/280783617): Tracking Bug
@Keep
@JvmField
val BUILDER_EXTRAS_OVERRIDE =
sysPropBooleanFlag(
- 128,
"persist.sysui.notification.builder_extras_override",
default = true
)
@@ -117,27 +115,26 @@ object Flags {
// TODO(b/292213543): Tracking Bug
@JvmField
val NOTIFICATION_GROUP_EXPANSION_CHANGE =
- unreleasedFlag(292213543, "notification_group_expansion_change", teamfood = false)
+ unreleasedFlag("notification_group_expansion_change", teamfood = false)
// 200 - keyguard/lockscreen
// ** Flag retired **
// public static final BooleanFlag KEYGUARD_LAYOUT =
- // new BooleanFlag(200, true);
+ // new BooleanFlag(true);
// TODO(b/254512750): Tracking Bug
- val NEW_UNLOCK_SWIPE_ANIMATION = releasedFlag(202, "new_unlock_swipe_animation")
- val CHARGING_RIPPLE = resourceBooleanFlag(203, R.bool.flag_charging_ripple, "charging_ripple")
+ val NEW_UNLOCK_SWIPE_ANIMATION = releasedFlag("new_unlock_swipe_animation")
+ val CHARGING_RIPPLE = resourceBooleanFlag(R.bool.flag_charging_ripple, "charging_ripple")
// TODO(b/254512281): Tracking Bug
@JvmField
val BOUNCER_USER_SWITCHER =
- resourceBooleanFlag(204, R.bool.config_enableBouncerUserSwitcher, "bouncer_user_switcher")
+ resourceBooleanFlag(R.bool.config_enableBouncerUserSwitcher, "bouncer_user_switcher")
// TODO(b/254512676): Tracking Bug
@JvmField
val LOCKSCREEN_CUSTOM_CLOCKS =
resourceBooleanFlag(
- 207,
R.bool.config_enableLockScreenCustomClocks,
"lockscreen_custom_clocks"
)
@@ -145,28 +142,28 @@ object Flags {
// TODO(b/275694445): Tracking Bug
@JvmField
val LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING =
- releasedFlag(208, "lockscreen_without_secure_lock_when_dreaming")
+ releasedFlag("lockscreen_without_secure_lock_when_dreaming")
// TODO(b/286092087): Tracking Bug
@JvmField
- val ENABLE_SYSTEM_UI_DREAM_CONTROLLER = unreleasedFlag(301, "enable_system_ui_dream_controller")
+ val ENABLE_SYSTEM_UI_DREAM_CONTROLLER = unreleasedFlag("enable_system_ui_dream_controller")
// TODO(b/288287730): Tracking Bug
@JvmField
- val ENABLE_SYSTEM_UI_DREAM_HOSTING = unreleasedFlag(302, "enable_system_ui_dream_hosting")
+ val ENABLE_SYSTEM_UI_DREAM_HOSTING = unreleasedFlag("enable_system_ui_dream_hosting")
/**
* Whether the clock on a wide lock screen should use the new "stepping" animation for moving
* the digits when the clock moves.
*/
- @JvmField val STEP_CLOCK_ANIMATION = releasedFlag(212, "step_clock_animation")
+ @JvmField val STEP_CLOCK_ANIMATION = releasedFlag("step_clock_animation")
/**
* Migration from the legacy isDozing/dozeAmount paths to the new KeyguardTransitionRepository
* will occur in stages. This is one stage of many to come.
*/
// TODO(b/255607168): Tracking Bug
- @JvmField val DOZING_MIGRATION_1 = unreleasedFlag(213, "dozing_migration_1")
+ @JvmField val DOZING_MIGRATION_1 = unreleasedFlag("dozing_migration_1")
/**
* Migrates control of the LightRevealScrim's reveal effect and amount from legacy code to the
@@ -174,80 +171,76 @@ object Flags {
*/
// TODO(b/281655028): Tracking bug
@JvmField
- val LIGHT_REVEAL_MIGRATION = unreleasedFlag(218, "light_reveal_migration", teamfood = false)
+ val LIGHT_REVEAL_MIGRATION = unreleasedFlag("light_reveal_migration", teamfood = false)
/** Flag to control the migration of face auth to modern architecture. */
// TODO(b/262838215): Tracking bug
- @JvmField val FACE_AUTH_REFACTOR = unreleasedFlag(220, "face_auth_refactor")
+ @JvmField val FACE_AUTH_REFACTOR = unreleasedFlag("face_auth_refactor")
/** Flag to control the revamp of keyguard biometrics progress animation */
// TODO(b/244313043): Tracking bug
- @JvmField val BIOMETRICS_ANIMATION_REVAMP = unreleasedFlag(221, "biometrics_animation_revamp")
+ @JvmField val BIOMETRICS_ANIMATION_REVAMP = unreleasedFlag("biometrics_animation_revamp")
// TODO(b/262780002): Tracking Bug
- @JvmField val REVAMPED_WALLPAPER_UI = releasedFlag(222, "revamped_wallpaper_ui")
+ @JvmField val REVAMPED_WALLPAPER_UI = releasedFlag("revamped_wallpaper_ui")
// flag for controlling auto pin confirmation and material u shapes in bouncer
@JvmField
- val AUTO_PIN_CONFIRMATION = releasedFlag(224, "auto_pin_confirmation", "auto_pin_confirmation")
+ val AUTO_PIN_CONFIRMATION = releasedFlag("auto_pin_confirmation", "auto_pin_confirmation")
// TODO(b/262859270): Tracking Bug
- @JvmField val FALSING_OFF_FOR_UNFOLDED = releasedFlag(225, "falsing_off_for_unfolded")
+ @JvmField val FALSING_OFF_FOR_UNFOLDED = releasedFlag("falsing_off_for_unfolded")
/** Enables code to show contextual loyalty cards in wallet entrypoints */
// TODO(b/294110497): Tracking Bug
@JvmField
val ENABLE_WALLET_CONTEXTUAL_LOYALTY_CARDS =
- unreleasedFlag(226, "enable_wallet_contextual_loyalty_cards", teamfood = true)
+ unreleasedFlag("enable_wallet_contextual_loyalty_cards", teamfood = true)
// TODO(b/242908637): Tracking Bug
- @JvmField val WALLPAPER_FULLSCREEN_PREVIEW = releasedFlag(227, "wallpaper_fullscreen_preview")
+ @JvmField val WALLPAPER_FULLSCREEN_PREVIEW = releasedFlag("wallpaper_fullscreen_preview")
/** Whether the long-press gesture to open wallpaper picker is enabled. */
// TODO(b/266242192): Tracking Bug
@JvmField
- val LOCK_SCREEN_LONG_PRESS_ENABLED = releasedFlag(228, "lock_screen_long_press_enabled")
+ val LOCK_SCREEN_LONG_PRESS_ENABLED = releasedFlag("lock_screen_long_press_enabled")
/** Enables UI updates for AI wallpapers in the wallpaper picker. */
// TODO(b/267722622): Tracking Bug
- @JvmField val WALLPAPER_PICKER_UI_FOR_AIWP = releasedFlag(229, "wallpaper_picker_ui_for_aiwp")
+ @JvmField val WALLPAPER_PICKER_UI_FOR_AIWP = releasedFlag("wallpaper_picker_ui_for_aiwp")
/** Whether to use a new data source for intents to run on keyguard dismissal. */
// TODO(b/275069969): Tracking bug.
@JvmField
- val REFACTOR_KEYGUARD_DISMISS_INTENT = unreleasedFlag(231, "refactor_keyguard_dismiss_intent")
+ val REFACTOR_KEYGUARD_DISMISS_INTENT = unreleasedFlag("refactor_keyguard_dismiss_intent")
/** Whether to allow long-press on the lock screen to directly open wallpaper picker. */
// TODO(b/277220285): Tracking bug.
@JvmField
val LOCK_SCREEN_LONG_PRESS_DIRECT_TO_WPP =
- unreleasedFlag(232, "lock_screen_long_press_directly_opens_wallpaper_picker")
+ unreleasedFlag("lock_screen_long_press_directly_opens_wallpaper_picker")
/** Whether page transition animations in the wallpaper picker are enabled */
// TODO(b/291710220): Tracking bug.
@JvmField
val WALLPAPER_PICKER_PAGE_TRANSITIONS =
- unreleasedFlag(291710220, "wallpaper_picker_page_transitions")
+ unreleasedFlag("wallpaper_picker_page_transitions")
/** Whether to run the new udfps keyguard refactor code. */
// TODO(b/279440316): Tracking bug.
@JvmField
- val REFACTOR_UDFPS_KEYGUARD_VIEWS = unreleasedFlag(233, "refactor_udfps_keyguard_views")
+ val REFACTOR_UDFPS_KEYGUARD_VIEWS = unreleasedFlag("refactor_udfps_keyguard_views")
/** Provide new auth messages on the bouncer. */
// TODO(b/277961132): Tracking bug.
- @JvmField val REVAMPED_BOUNCER_MESSAGES = unreleasedFlag(234, "revamped_bouncer_messages")
+ @JvmField val REVAMPED_BOUNCER_MESSAGES = unreleasedFlag("revamped_bouncer_messages")
/** Whether to delay showing bouncer UI when face auth or active unlock are enrolled. */
// TODO(b/279794160): Tracking bug.
- @JvmField val DELAY_BOUNCER = releasedFlag(235, "delay_bouncer")
+ @JvmField val DELAY_BOUNCER = releasedFlag("delay_bouncer")
/** Keyguard Migration */
- /** Migrate the indication area to the new keyguard root view. */
- // TODO(b/280067944): Tracking bug.
- @JvmField val MIGRATE_INDICATION_AREA = releasedFlag(236, "migrate_indication_area")
-
/**
* Migrate the bottom area to the new keyguard root view. Because there is no such thing as a
* "bottom area" after this, this also breaks it up into many smaller, modular pieces.
@@ -255,203 +248,213 @@ object Flags {
// TODO(b/290652751): Tracking bug.
@JvmField
val MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA =
- unreleasedFlag(290652751, "migrate_split_keyguard_bottom_area")
+ unreleasedFlag("migrate_split_keyguard_bottom_area")
/** Whether to listen for fingerprint authentication over keyguard occluding activities. */
// TODO(b/283260512): Tracking bug.
- @JvmField val FP_LISTEN_OCCLUDING_APPS = unreleasedFlag(237, "fp_listen_occluding_apps")
+ @JvmField val FP_LISTEN_OCCLUDING_APPS = unreleasedFlag("fp_listen_occluding_apps",
+ teamfood = true)
/** Flag meant to guard the talkback fix for the KeyguardIndicationTextView */
// TODO(b/286563884): Tracking bug
- @JvmField val KEYGUARD_TALKBACK_FIX = releasedFlag(238, "keyguard_talkback_fix")
+ @JvmField val KEYGUARD_TALKBACK_FIX = releasedFlag("keyguard_talkback_fix")
// TODO(b/287268101): Tracking bug.
- @JvmField val TRANSIT_CLOCK = unreleasedFlag(239, "lockscreen_custom_transit_clock", teamfood = true)
+ @JvmField val TRANSIT_CLOCK = releasedFlag("lockscreen_custom_transit_clock")
/** Migrate the lock icon view to the new keyguard root view. */
// TODO(b/286552209): Tracking bug.
- @JvmField val MIGRATE_LOCK_ICON = unreleasedFlag(240, "migrate_lock_icon")
+ @JvmField val MIGRATE_LOCK_ICON = unreleasedFlag("migrate_lock_icon")
// TODO(b/288276738): Tracking bug.
- @JvmField val WIDGET_ON_KEYGUARD = unreleasedFlag(241, "widget_on_keyguard")
+ @JvmField val WIDGET_ON_KEYGUARD = unreleasedFlag("widget_on_keyguard")
/** Migrate the NSSL to the a sibling to both the panel and keyguard root view. */
// TODO(b/288074305): Tracking bug.
- @JvmField val MIGRATE_NSSL = unreleasedFlag(242, "migrate_nssl")
+ @JvmField val MIGRATE_NSSL = unreleasedFlag("migrate_nssl")
/** Migrate the status view from the notification panel to keyguard root view. */
// TODO(b/291767565): Tracking bug.
- @JvmField val MIGRATE_KEYGUARD_STATUS_VIEW = unreleasedFlag(243, "migrate_keyguard_status_view")
+ @JvmField val MIGRATE_KEYGUARD_STATUS_VIEW = unreleasedFlag("migrate_keyguard_status_view")
/** Enables preview loading animation in the wallpaper picker. */
// TODO(b/274443705): Tracking Bug
@JvmField
val WALLPAPER_PICKER_PREVIEW_ANIMATION =
unreleasedFlag(
- 244,
- "wallpaper_picker_preview_animation"
+ "wallpaper_picker_preview_animation",
+ teamfood = true
)
+ /** Stop running face auth when the display state changes to OFF. */
+ // TODO(b/294221702): Tracking bug.
+ @JvmField val STOP_FACE_AUTH_ON_DISPLAY_OFF = resourceBooleanFlag(
+ R.bool.flag_stop_face_auth_on_display_off, "stop_face_auth_on_display_off")
+
// 300 - power menu
// TODO(b/254512600): Tracking Bug
- @JvmField val POWER_MENU_LITE = releasedFlag(300, "power_menu_lite")
+ @JvmField val POWER_MENU_LITE = releasedFlag("power_menu_lite")
// 400 - smartspace
// TODO(b/254513100): Tracking Bug
val SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED =
- releasedFlag(401, "smartspace_shared_element_transition_enabled")
+ releasedFlag("smartspace_shared_element_transition_enabled")
// TODO(b/258517050): Clean up after the feature is launched.
@JvmField
val SMARTSPACE_DATE_WEATHER_DECOUPLED =
- sysPropBooleanFlag(403, "persist.sysui.ss.dw_decoupled", default = true)
+ sysPropBooleanFlag("persist.sysui.ss.dw_decoupled", default = true)
// TODO(b/270223352): Tracking Bug
@JvmField
- val HIDE_SMARTSPACE_ON_DREAM_OVERLAY = releasedFlag(404, "hide_smartspace_on_dream_overlay")
+ val HIDE_SMARTSPACE_ON_DREAM_OVERLAY = releasedFlag("hide_smartspace_on_dream_overlay")
// TODO(b/271460958): Tracking Bug
@JvmField
val SHOW_WEATHER_COMPLICATION_ON_DREAM_OVERLAY =
- releasedFlag(405, "show_weather_complication_on_dream_overlay")
+ releasedFlag("show_weather_complication_on_dream_overlay")
// 500 - quick settings
- val PEOPLE_TILE = resourceBooleanFlag(502, R.bool.flag_conversations, "people_tile")
+ val PEOPLE_TILE = resourceBooleanFlag(R.bool.flag_conversations, "people_tile")
@JvmField
val QS_USER_DETAIL_SHORTCUT =
resourceBooleanFlag(
- 503,
R.bool.flag_lockscreen_qs_user_detail_shortcut,
"qs_user_detail_shortcut"
)
@JvmField
- val QS_PIPELINE_NEW_HOST = unreleasedFlag(504, "qs_pipeline_new_host", teamfood = true)
+ val QS_PIPELINE_NEW_HOST = unreleasedFlag("qs_pipeline_new_host", teamfood = true)
// TODO(b/278068252): Tracking Bug
@JvmField
- val QS_PIPELINE_AUTO_ADD = unreleasedFlag(505, "qs_pipeline_auto_add", teamfood = false)
+ val QS_PIPELINE_AUTO_ADD = unreleasedFlag("qs_pipeline_auto_add", teamfood = false)
// TODO(b/254512383): Tracking Bug
@JvmField
val FULL_SCREEN_USER_SWITCHER =
resourceBooleanFlag(
- 506,
R.bool.config_enableFullscreenUserSwitcher,
"full_screen_user_switcher"
)
// TODO(b/244064524): Tracking Bug
- @JvmField val QS_SECONDARY_DATA_SUB_INFO = releasedFlag(508, "qs_secondary_data_sub_info")
+ @JvmField val QS_SECONDARY_DATA_SUB_INFO = releasedFlag("qs_secondary_data_sub_info")
/** Enables Font Scaling Quick Settings tile */
// TODO(b/269341316): Tracking Bug
- @JvmField val ENABLE_FONT_SCALING_TILE = releasedFlag(509, "enable_font_scaling_tile")
+ @JvmField val ENABLE_FONT_SCALING_TILE = releasedFlag("enable_font_scaling_tile")
/** Enables new QS Edit Mode visual refresh */
// TODO(b/269787742): Tracking Bug
@JvmField
- val ENABLE_NEW_QS_EDIT_MODE = unreleasedFlag(510, "enable_new_qs_edit_mode", teamfood = false)
+ val ENABLE_NEW_QS_EDIT_MODE = unreleasedFlag("enable_new_qs_edit_mode", teamfood = false)
// 600- status bar
// TODO(b/265892345): Tracking Bug
- val PLUG_IN_STATUS_BAR_CHIP = releasedFlag(265892345, "plug_in_status_bar_chip")
+ val PLUG_IN_STATUS_BAR_CHIP = releasedFlag("plug_in_status_bar_chip")
// TODO(b/280426085): Tracking Bug
- @JvmField val NEW_BLUETOOTH_REPOSITORY = releasedFlag(612, "new_bluetooth_repository")
+ @JvmField val NEW_BLUETOOTH_REPOSITORY = releasedFlag("new_bluetooth_repository")
// TODO(b/292533677): Tracking Bug
val WIFI_TRACKER_LIB_FOR_WIFI_ICON =
- unreleasedFlag(613, "wifi_tracker_lib_for_wifi_icon")
+ unreleasedFlag("wifi_tracker_lib_for_wifi_icon")
+
+ // TODO(b/293863612): Tracking Bug
+ @JvmField val INCOMPATIBLE_CHARGING_BATTERY_ICON =
+ unreleasedFlag("incompatible_charging_battery_icon")
+
+ // TODO(b/293585143): Tracking Bug
+ val INSTANT_TETHER = unreleasedFlag("instant_tether")
// 700 - dialer/calls
// TODO(b/254512734): Tracking Bug
- val ONGOING_CALL_STATUS_BAR_CHIP = releasedFlag(700, "ongoing_call_status_bar_chip")
+ val ONGOING_CALL_STATUS_BAR_CHIP = releasedFlag("ongoing_call_status_bar_chip")
// TODO(b/254512681): Tracking Bug
- val ONGOING_CALL_IN_IMMERSIVE = releasedFlag(701, "ongoing_call_in_immersive")
+ val ONGOING_CALL_IN_IMMERSIVE = releasedFlag("ongoing_call_in_immersive")
// TODO(b/254512753): Tracking Bug
- val ONGOING_CALL_IN_IMMERSIVE_CHIP_TAP = releasedFlag(702, "ongoing_call_in_immersive_chip_tap")
+ val ONGOING_CALL_IN_IMMERSIVE_CHIP_TAP = releasedFlag("ongoing_call_in_immersive_chip_tap")
// 800 - general visual/theme
- @JvmField val MONET = resourceBooleanFlag(800, R.bool.flag_monet, "monet")
+ @JvmField val MONET = resourceBooleanFlag(R.bool.flag_monet, "monet")
// 801 - region sampling
// TODO(b/254512848): Tracking Bug
- val REGION_SAMPLING = unreleasedFlag(801, "region_sampling")
+ val REGION_SAMPLING = unreleasedFlag("region_sampling")
// 803 - screen contents translation
// TODO(b/254513187): Tracking Bug
- val SCREEN_CONTENTS_TRANSLATION = unreleasedFlag(803, "screen_contents_translation")
+ val SCREEN_CONTENTS_TRANSLATION = unreleasedFlag("screen_contents_translation")
// 804 - monochromatic themes
- @JvmField val MONOCHROMATIC_THEME = releasedFlag(804, "monochromatic")
+ @JvmField val MONOCHROMATIC_THEME = releasedFlag("monochromatic")
// TODO(b/293380347): Tracking Bug
- @JvmField val COLOR_FIDELITY = unreleasedFlag(805, "color_fidelity")
+ @JvmField val COLOR_FIDELITY = unreleasedFlag("color_fidelity")
// 900 - media
// TODO(b/254512697): Tracking Bug
- val MEDIA_TAP_TO_TRANSFER = releasedFlag(900, "media_tap_to_transfer")
+ val MEDIA_TAP_TO_TRANSFER = releasedFlag("media_tap_to_transfer")
// TODO(b/254512502): Tracking Bug
- val MEDIA_SESSION_ACTIONS = unreleasedFlag(901, "media_session_actions")
+ val MEDIA_SESSION_ACTIONS = unreleasedFlag("media_session_actions")
// TODO(b/254512654): Tracking Bug
- @JvmField val DREAM_MEDIA_COMPLICATION = unreleasedFlag(905, "dream_media_complication")
+ @JvmField val DREAM_MEDIA_COMPLICATION = unreleasedFlag("dream_media_complication")
// TODO(b/254512673): Tracking Bug
- @JvmField val DREAM_MEDIA_TAP_TO_OPEN = unreleasedFlag(906, "dream_media_tap_to_open")
+ @JvmField val DREAM_MEDIA_TAP_TO_OPEN = unreleasedFlag("dream_media_tap_to_open")
// TODO(b/254513168): Tracking Bug
- @JvmField val UMO_SURFACE_RIPPLE = releasedFlag(907, "umo_surface_ripple")
+ @JvmField val UMO_SURFACE_RIPPLE = releasedFlag("umo_surface_ripple")
// TODO(b/261734857): Tracking Bug
- @JvmField val UMO_TURBULENCE_NOISE = releasedFlag(909, "umo_turbulence_noise")
+ @JvmField val UMO_TURBULENCE_NOISE = releasedFlag("umo_turbulence_noise")
// TODO(b/263272731): Tracking Bug
- val MEDIA_TTT_RECEIVER_SUCCESS_RIPPLE = releasedFlag(910, "media_ttt_receiver_success_ripple")
+ val MEDIA_TTT_RECEIVER_SUCCESS_RIPPLE = releasedFlag("media_ttt_receiver_success_ripple")
// TODO(b/266157412): Tracking Bug
- val MEDIA_RETAIN_SESSIONS = unreleasedFlag(913, "media_retain_sessions")
+ val MEDIA_RETAIN_SESSIONS = unreleasedFlag("media_retain_sessions")
// TODO(b/267007629): Tracking Bug
- val MEDIA_RESUME_PROGRESS = releasedFlag(915, "media_resume_progress")
+ val MEDIA_RESUME_PROGRESS = releasedFlag("media_resume_progress")
// TODO(b/267166152) : Tracking Bug
- val MEDIA_RETAIN_RECOMMENDATIONS = unreleasedFlag(916, "media_retain_recommendations")
+ val MEDIA_RETAIN_RECOMMENDATIONS = unreleasedFlag("media_retain_recommendations")
// TODO(b/270437894): Tracking Bug
- val MEDIA_REMOTE_RESUME = unreleasedFlag(917, "media_remote_resume")
+ val MEDIA_REMOTE_RESUME = unreleasedFlag("media_remote_resume")
// 1000 - dock
- val SIMULATE_DOCK_THROUGH_CHARGING = releasedFlag(1000, "simulate_dock_through_charging")
+ val SIMULATE_DOCK_THROUGH_CHARGING = releasedFlag("simulate_dock_through_charging")
// TODO(b/254512758): Tracking Bug
- @JvmField val ROUNDED_BOX_RIPPLE = releasedFlag(1002, "rounded_box_ripple")
+ @JvmField val ROUNDED_BOX_RIPPLE = releasedFlag("rounded_box_ripple")
// TODO(b/273509374): Tracking Bug
@JvmField
val ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS =
- releasedFlag(1006, "always_show_home_controls_on_dreams")
+ releasedFlag("always_show_home_controls_on_dreams")
// 1100 - windowing
@Keep
@JvmField
val WM_ENABLE_SHELL_TRANSITIONS =
- sysPropBooleanFlag(1100, "persist.wm.debug.shell_transit", default = true)
+ sysPropBooleanFlag("persist.wm.debug.shell_transit", default = true)
// TODO(b/254513207): Tracking Bug
@Keep
@JvmField
val WM_ENABLE_PARTIAL_SCREEN_SHARING =
unreleasedFlag(
- 1102,
name = "record_task_content",
namespace = DeviceConfig.NAMESPACE_WINDOW_MANAGER,
teamfood = true
@@ -461,50 +464,49 @@ object Flags {
@Keep
@JvmField
val HIDE_NAVBAR_WINDOW =
- sysPropBooleanFlag(1103, "persist.wm.debug.hide_navbar_window", default = false)
+ sysPropBooleanFlag("persist.wm.debug.hide_navbar_window", default = false)
@Keep
@JvmField
val WM_DESKTOP_WINDOWING =
- sysPropBooleanFlag(1104, "persist.wm.debug.desktop_mode", default = false)
+ sysPropBooleanFlag("persist.wm.debug.desktop_mode", default = false)
@Keep
@JvmField
val WM_CAPTION_ON_SHELL =
- sysPropBooleanFlag(1105, "persist.wm.debug.caption_on_shell", default = true)
+ sysPropBooleanFlag("persist.wm.debug.caption_on_shell", default = true)
@Keep
@JvmField
val ENABLE_FLING_TO_DISMISS_BUBBLE =
- sysPropBooleanFlag(1108, "persist.wm.debug.fling_to_dismiss_bubble", default = true)
+ sysPropBooleanFlag("persist.wm.debug.fling_to_dismiss_bubble", default = true)
@Keep
@JvmField
val ENABLE_FLING_TO_DISMISS_PIP =
- sysPropBooleanFlag(1109, "persist.wm.debug.fling_to_dismiss_pip", default = true)
+ sysPropBooleanFlag("persist.wm.debug.fling_to_dismiss_pip", default = true)
@Keep
@JvmField
val ENABLE_PIP_KEEP_CLEAR_ALGORITHM =
- sysPropBooleanFlag(1110, "persist.wm.debug.enable_pip_keep_clear_algorithm", default = true)
+ sysPropBooleanFlag("persist.wm.debug.enable_pip_keep_clear_algorithm", default = true)
// TODO(b/256873975): Tracking Bug
@JvmField
@Keep
- val WM_BUBBLE_BAR = sysPropBooleanFlag(1111, "persist.wm.debug.bubble_bar", default = false)
+ val WM_BUBBLE_BAR = sysPropBooleanFlag("persist.wm.debug.bubble_bar", default = false)
// TODO(b/260271148): Tracking bug
@Keep
@JvmField
val WM_DESKTOP_WINDOWING_2 =
- sysPropBooleanFlag(1112, "persist.wm.debug.desktop_mode_2", default = false)
+ sysPropBooleanFlag("persist.wm.debug.desktop_mode_2", default = false)
// TODO(b/254513207): Tracking Bug to delete
@Keep
@JvmField
val WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES =
unreleasedFlag(
- 1113,
name = "screen_record_enterprise_policies",
namespace = DeviceConfig.NAMESPACE_WINDOW_MANAGER,
teamfood = false
@@ -514,233 +516,238 @@ object Flags {
@Keep
@JvmField
val ENABLE_PIP_SIZE_LARGE_SCREEN =
- sysPropBooleanFlag(1114, "persist.wm.debug.enable_pip_size_large_screen", default = true)
+ sysPropBooleanFlag("persist.wm.debug.enable_pip_size_large_screen", default = true)
// TODO(b/265998256): Tracking bug
@Keep
@JvmField
val ENABLE_PIP_APP_ICON_OVERLAY =
- sysPropBooleanFlag(1115, "persist.wm.debug.enable_pip_app_icon_overlay", default = true)
+ sysPropBooleanFlag("persist.wm.debug.enable_pip_app_icon_overlay", default = true)
// TODO(b/273443374): Tracking Bug
@Keep
@JvmField
val LOCKSCREEN_LIVE_WALLPAPER =
- sysPropBooleanFlag(1117, "persist.wm.debug.lockscreen_live_wallpaper", default = true)
+ sysPropBooleanFlag("persist.wm.debug.lockscreen_live_wallpaper", default = true)
// TODO(b/281648899): Tracking bug
@Keep
@JvmField
val WALLPAPER_MULTI_CROP =
- sysPropBooleanFlag(1118, "persist.wm.debug.wallpaper_multi_crop", default = false)
+ sysPropBooleanFlag("persist.wm.debug.wallpaper_multi_crop", default = false)
// TODO(b/290220798): Tracking Bug
@Keep
@JvmField
val ENABLE_PIP2_IMPLEMENTATION =
- sysPropBooleanFlag(1119, "persist.wm.debug.enable_pip2_implementation", default = false)
+ sysPropBooleanFlag("persist.wm.debug.enable_pip2_implementation", default = false)
// 1200 - predictive back
@Keep
@JvmField
val WM_ENABLE_PREDICTIVE_BACK =
- sysPropBooleanFlag(1200, "persist.wm.debug.predictive_back", default = true)
+ sysPropBooleanFlag("persist.wm.debug.predictive_back", default = true)
@Keep
@JvmField
val WM_ENABLE_PREDICTIVE_BACK_ANIM =
- sysPropBooleanFlag(1201, "persist.wm.debug.predictive_back_anim", default = true)
+ sysPropBooleanFlag("persist.wm.debug.predictive_back_anim", default = true)
@Keep
@JvmField
val WM_ALWAYS_ENFORCE_PREDICTIVE_BACK =
- sysPropBooleanFlag(1202, "persist.wm.debug.predictive_back_always_enforce", default = false)
+ sysPropBooleanFlag("persist.wm.debug.predictive_back_always_enforce", default = false)
// TODO(b/254512728): Tracking Bug
- @JvmField val NEW_BACK_AFFORDANCE = releasedFlag(1203, "new_back_affordance")
+ @JvmField val NEW_BACK_AFFORDANCE = releasedFlag("new_back_affordance")
// TODO(b/255854141): Tracking Bug
@JvmField
val WM_ENABLE_PREDICTIVE_BACK_SYSUI =
- unreleasedFlag(1204, "persist.wm.debug.predictive_back_sysui_enable", teamfood = true)
+ unreleasedFlag("persist.wm.debug.predictive_back_sysui_enable", teamfood = true)
// TODO(b/270987164): Tracking Bug
- @JvmField val TRACKPAD_GESTURE_FEATURES = releasedFlag(1205, "trackpad_gesture_features")
+ @JvmField val TRACKPAD_GESTURE_FEATURES = releasedFlag("trackpad_gesture_features")
// TODO(b/263826204): Tracking Bug
@JvmField
val WM_ENABLE_PREDICTIVE_BACK_BOUNCER_ANIM =
- unreleasedFlag(1206, "persist.wm.debug.predictive_back_bouncer_anim", teamfood = true)
+ unreleasedFlag("persist.wm.debug.predictive_back_bouncer_anim", teamfood = true)
// TODO(b/238475428): Tracking Bug
@JvmField
val WM_SHADE_ALLOW_BACK_GESTURE =
- sysPropBooleanFlag(1207, "persist.wm.debug.shade_allow_back_gesture", default = false)
+ sysPropBooleanFlag("persist.wm.debug.shade_allow_back_gesture", default = false)
// TODO(b/238475428): Tracking Bug
@JvmField
val WM_SHADE_ANIMATE_BACK_GESTURE =
- unreleasedFlag(1208, "persist.wm.debug.shade_animate_back_gesture", teamfood = false)
+ unreleasedFlag("persist.wm.debug.shade_animate_back_gesture", teamfood = false)
// TODO(b/265639042): Tracking Bug
@JvmField
val WM_ENABLE_PREDICTIVE_BACK_QS_DIALOG_ANIM =
- unreleasedFlag(1209, "persist.wm.debug.predictive_back_qs_dialog_anim", teamfood = true)
+ unreleasedFlag("persist.wm.debug.predictive_back_qs_dialog_anim", teamfood = true)
// TODO(b/273800936): Tracking Bug
- @JvmField val TRACKPAD_GESTURE_COMMON = releasedFlag(1210, "trackpad_gesture_common")
+ @JvmField val TRACKPAD_GESTURE_COMMON = releasedFlag("trackpad_gesture_common")
// 1300 - screenshots
// TODO(b/264916608): Tracking Bug
- @JvmField val SCREENSHOT_METADATA = unreleasedFlag(1302, "screenshot_metadata")
+ @JvmField val SCREENSHOT_METADATA = unreleasedFlag("screenshot_metadata")
// TODO(b/266955521): Tracking bug
- @JvmField val SCREENSHOT_DETECTION = releasedFlag(1303, "screenshot_detection")
+ @JvmField val SCREENSHOT_DETECTION = releasedFlag("screenshot_detection")
// TODO(b/251205791): Tracking Bug
- @JvmField val SCREENSHOT_APP_CLIPS = releasedFlag(1304, "screenshot_app_clips")
+ @JvmField val SCREENSHOT_APP_CLIPS = releasedFlag("screenshot_app_clips")
// 1400 - columbus
// TODO(b/254512756): Tracking Bug
- val QUICK_TAP_IN_PCC = releasedFlag(1400, "quick_tap_in_pcc")
+ val QUICK_TAP_IN_PCC = releasedFlag("quick_tap_in_pcc")
// TODO(b/261979569): Tracking Bug
val QUICK_TAP_FLOW_FRAMEWORK =
- unreleasedFlag(1401, "quick_tap_flow_framework", teamfood = false)
+ unreleasedFlag("quick_tap_flow_framework", teamfood = false)
// 1500 - chooser aka sharesheet
// 1700 - clipboard
- @JvmField val CLIPBOARD_REMOTE_BEHAVIOR = releasedFlag(1701, "clipboard_remote_behavior")
+ @JvmField val CLIPBOARD_REMOTE_BEHAVIOR = releasedFlag("clipboard_remote_behavior")
// TODO(b/278714186) Tracking Bug
@JvmField
- val CLIPBOARD_IMAGE_TIMEOUT = unreleasedFlag(1702, "clipboard_image_timeout", teamfood = true)
+ val CLIPBOARD_IMAGE_TIMEOUT = unreleasedFlag("clipboard_image_timeout", teamfood = true)
// TODO(b/279405451): Tracking Bug
@JvmField
val CLIPBOARD_SHARED_TRANSITIONS =
- unreleasedFlag(1703, "clipboard_shared_transitions", teamfood = true)
+ unreleasedFlag("clipboard_shared_transitions", teamfood = true)
// TODO(b/283300105): Tracking Bug
- @JvmField val SCENE_CONTAINER = unreleasedFlag(1802, "scene_container")
+ @JvmField val SCENE_CONTAINER = unreleasedFlag("scene_container")
// 1900
- @JvmField val NOTE_TASKS = releasedFlag(1900, "keycode_flag")
+ @JvmField val NOTE_TASKS = releasedFlag("keycode_flag")
// 2000 - device controls
- @JvmField val APP_PANELS_ALL_APPS_ALLOWED = releasedFlag(2001, "app_panels_all_apps_allowed")
+ @JvmField val APP_PANELS_ALL_APPS_ALLOWED = releasedFlag("app_panels_all_apps_allowed")
// 2200 - biometrics (udfps, sfps, BiometricPrompt, etc.)
// TODO(b/259264861): Tracking Bug
- @JvmField val UDFPS_NEW_TOUCH_DETECTION = releasedFlag(2200, "udfps_new_touch_detection")
- @JvmField val UDFPS_ELLIPSE_DETECTION = releasedFlag(2201, "udfps_ellipse_detection")
+ @JvmField val UDFPS_NEW_TOUCH_DETECTION = releasedFlag("udfps_new_touch_detection")
+ @JvmField val UDFPS_ELLIPSE_DETECTION = releasedFlag("udfps_ellipse_detection")
// TODO(b/278622168): Tracking Bug
- @JvmField val BIOMETRIC_BP_STRONG = releasedFlag(2202, "biometric_bp_strong")
+ @JvmField val BIOMETRIC_BP_STRONG = releasedFlag("biometric_bp_strong")
// 2300 - stylus
- @JvmField val TRACK_STYLUS_EVER_USED = releasedFlag(2300, "track_stylus_ever_used")
- @JvmField val ENABLE_STYLUS_CHARGING_UI = releasedFlag(2301, "enable_stylus_charging_ui")
+ @JvmField val TRACK_STYLUS_EVER_USED = releasedFlag("track_stylus_ever_used")
+ @JvmField val ENABLE_STYLUS_CHARGING_UI = releasedFlag("enable_stylus_charging_ui")
@JvmField
- val ENABLE_USI_BATTERY_NOTIFICATIONS = releasedFlag(2302, "enable_usi_battery_notifications")
- @JvmField val ENABLE_STYLUS_EDUCATION = releasedFlag(2303, "enable_stylus_education")
+ val ENABLE_USI_BATTERY_NOTIFICATIONS = releasedFlag("enable_usi_battery_notifications")
+ @JvmField val ENABLE_STYLUS_EDUCATION = releasedFlag("enable_stylus_education")
// 2400 - performance tools and debugging info
// TODO(b/238923086): Tracking Bug
@JvmField
val WARN_ON_BLOCKING_BINDER_TRANSACTIONS =
- unreleasedFlag(2400, "warn_on_blocking_binder_transactions")
+ unreleasedFlag("warn_on_blocking_binder_transactions")
// TODO(b/283071711): Tracking bug
@JvmField
val TRIM_RESOURCES_WITH_BACKGROUND_TRIM_AT_LOCK =
- unreleasedFlag(2401, "trim_resources_with_background_trim_on_lock")
+ unreleasedFlag("trim_resources_with_background_trim_on_lock")
// TODO:(b/283203305): Tracking bug
- @JvmField val TRIM_FONT_CACHES_AT_UNLOCK = unreleasedFlag(2402, "trim_font_caches_on_unlock")
+ @JvmField val TRIM_FONT_CACHES_AT_UNLOCK = unreleasedFlag("trim_font_caches_on_unlock")
// 2700 - unfold transitions
// TODO(b/265764985): Tracking Bug
@Keep
@JvmField
val ENABLE_DARK_VIGNETTE_WHEN_FOLDING =
- unreleasedFlag(2700, "enable_dark_vignette_when_folding")
+ unreleasedFlag("enable_dark_vignette_when_folding")
// TODO(b/265764985): Tracking Bug
@Keep
@JvmField
val ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS =
- unreleasedFlag(2701, "enable_unfold_status_bar_animations")
+ unreleasedFlag("enable_unfold_status_bar_animations")
// TODO(b259590361): Tracking bug
- val EXPERIMENTAL_FLAG = unreleasedFlag(2, "exp_flag_release")
+ val EXPERIMENTAL_FLAG = unreleasedFlag("exp_flag_release")
// 2600 - keyboard
// TODO(b/259352579): Tracking Bug
- @JvmField val SHORTCUT_LIST_SEARCH_LAYOUT = releasedFlag(2600, "shortcut_list_search_layout")
+ @JvmField val SHORTCUT_LIST_SEARCH_LAYOUT = releasedFlag("shortcut_list_search_layout")
// TODO(b/259428678): Tracking Bug
- @JvmField val KEYBOARD_BACKLIGHT_INDICATOR = releasedFlag(2601, "keyboard_backlight_indicator")
+ @JvmField val KEYBOARD_BACKLIGHT_INDICATOR = releasedFlag("keyboard_backlight_indicator")
// TODO(b/277192623): Tracking Bug
- @JvmField val KEYBOARD_EDUCATION = unreleasedFlag(2603, "keyboard_education", teamfood = false)
+ @JvmField val KEYBOARD_EDUCATION = unreleasedFlag("keyboard_education", teamfood = false)
// TODO(b/277201412): Tracking Bug
@JvmField
- val SPLIT_SHADE_SUBPIXEL_OPTIMIZATION = releasedFlag(2805, "split_shade_subpixel_optimization")
+ val SPLIT_SHADE_SUBPIXEL_OPTIMIZATION = releasedFlag("split_shade_subpixel_optimization")
// TODO(b/288868056): Tracking Bug
@JvmField
- val PARTIAL_SCREEN_SHARING_TASK_SWITCHER = unreleasedFlag(288868056, "pss_task_switcher")
+ val PARTIAL_SCREEN_SHARING_TASK_SWITCHER = unreleasedFlag("pss_task_switcher")
// TODO(b/278761837): Tracking Bug
- @JvmField val USE_NEW_ACTIVITY_STARTER = releasedFlag(2801, name = "use_new_activity_starter")
+ @JvmField val USE_NEW_ACTIVITY_STARTER = releasedFlag(name = "use_new_activity_starter")
// 2900 - Zero Jank fixes. Naming convention is: zj_<bug number>_<cuj name>
// TODO:(b/285623104): Tracking bug
@JvmField
val ZJ_285570694_LOCKSCREEN_TRANSITION_FROM_AOD =
- releasedFlag(2900, "zj_285570694_lockscreen_transition_from_aod")
+ releasedFlag("zj_285570694_lockscreen_transition_from_aod")
// 3000 - dream
// TODO(b/285059790) : Tracking Bug
@JvmField
val LOCKSCREEN_WALLPAPER_DREAM_ENABLED =
- unreleasedFlag(3000, name = "enable_lockscreen_wallpaper_dream", teamfood = true)
+ unreleasedFlag(name = "enable_lockscreen_wallpaper_dream", teamfood = true)
// TODO(b/283084712): Tracking Bug
- @JvmField val IMPROVED_HUN_ANIMATIONS = unreleasedFlag(283084712, "improved_hun_animations")
+ @JvmField val IMPROVED_HUN_ANIMATIONS = unreleasedFlag("improved_hun_animations")
// TODO(b/283447257): Tracking bug
@JvmField
val BIGPICTURE_NOTIFICATION_LAZY_LOADING =
- unreleasedFlag(283447257, "bigpicture_notification_lazy_loading")
+ unreleasedFlag("bigpicture_notification_lazy_loading")
+
+ // TODO(b/292062937): Tracking bug
+ @JvmField
+ val NOTIFICATION_CLEARABLE_REFACTOR =
+ unreleasedFlag("notification_clearable_refactor")
// TODO(b/283740863): Tracking Bug
@JvmField
val ENABLE_NEW_PRIVACY_DIALOG =
- unreleasedFlag(283740863, "enable_new_privacy_dialog", teamfood = true)
+ unreleasedFlag("enable_new_privacy_dialog", teamfood = true)
// TODO(b/289573946): Tracking Bug
- @JvmField val PRECOMPUTED_TEXT = unreleasedFlag(289573946, "precomputed_text")
+ @JvmField val PRECOMPUTED_TEXT = unreleasedFlag("precomputed_text")
// 2900 - CentralSurfaces-related flags
// TODO(b/285174336): Tracking Bug
@JvmField
val USE_REPOS_FOR_BOUNCER_SHOWING =
- unreleasedFlag(2900, "use_repos_for_bouncer_showing", teamfood = true)
+ unreleasedFlag("use_repos_for_bouncer_showing", teamfood = true)
// 3100 - Haptic interactions
// TODO(b/290213663): Tracking Bug
@JvmField
- val ONE_WAY_HAPTICS_API_MIGRATION = unreleasedFlag(3100, "oneway_haptics_api_migration")
+ val ONE_WAY_HAPTICS_API_MIGRATION = unreleasedFlag("oneway_haptics_api_migration")
/** Enable the Compose implementation of the PeopleSpaceActivity. */
@JvmField
- val COMPOSE_PEOPLE_SPACE = unreleasedFlag(293570761, "compose_people_space")
+ val COMPOSE_PEOPLE_SPACE = unreleasedFlag("compose_people_space")
/** Enable the Compose implementation of the Quick Settings footer actions. */
@JvmField
- val COMPOSE_QS_FOOTER_ACTIONS = unreleasedFlag(293569320, "compose_qs_footer_actions")
+ val COMPOSE_QS_FOOTER_ACTIONS = unreleasedFlag("compose_qs_footer_actions")
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 489d2ab4d342..9a09df4828d3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -929,28 +929,41 @@ class KeyguardUnlockAnimationController @Inject constructor(
/**
* Called by [KeyguardViewMediator] to let us know that the remote animation has finished, and
- * we should clean up all of our state.
+ * we should clean up all of our state. [showKeyguard] will tell us which surface should be
+ * visible after the animation has been completed or canceled.
*
* This is generally triggered by us, calling
* [KeyguardViewMediator.finishSurfaceBehindRemoteAnimation].
*/
- fun notifyFinishedKeyguardExitAnimation(cancelled: Boolean) {
+ fun notifyFinishedKeyguardExitAnimation(showKeyguard: Boolean) {
// Cancel any pending actions.
handler.removeCallbacksAndMessages(null)
- // Make sure we made the surface behind fully visible, just in case. It should already be
- // fully visible. The exit animation is finished, and we should not hold the leash anymore,
- // so forcing it to 1f.
- surfaceBehindAlpha = 1f
- setSurfaceBehindAppearAmount(1f)
+ // The lockscreen surface is gone, so it is now safe to re-show the smartspace.
+ if (lockscreenSmartspace?.visibility == View.INVISIBLE) {
+ lockscreenSmartspace?.visibility = View.VISIBLE
+ }
+
+ if (!showKeyguard) {
+ // Make sure we made the surface behind fully visible, just in case. It should already be
+ // fully visible. The exit animation is finished, and we should not hold the leash anymore,
+ // so forcing it to 1f.
+ surfaceBehindAlpha = 1f
+ setSurfaceBehindAppearAmount(1f)
+
+ try {
+ launcherUnlockController?.setUnlockAmount(1f, false /* forceIfAnimating */)
+ } catch (e: RemoteException) {
+ Log.e(TAG, "Remote exception in notifyFinishedKeyguardExitAnimation", e)
+ }
+ }
+
+ listeners.forEach { it.onUnlockAnimationFinished() }
+
+ // Reset all state
surfaceBehindAlphaAnimator.cancel()
surfaceBehindEntryAnimator.cancel()
wallpaperCannedUnlockAnimator.cancel()
- try {
- launcherUnlockController?.setUnlockAmount(1f, false /* forceIfAnimating */)
- } catch (e: RemoteException) {
- Log.e(TAG, "Remote exception in notifyFinishedKeyguardExitAnimation", e)
- }
// That target is no longer valid since the animation finished, null it out.
surfaceBehindRemoteAnimationTargets = null
@@ -960,13 +973,6 @@ class KeyguardUnlockAnimationController @Inject constructor(
dismissAmountThresholdsReached = false
willUnlockWithInWindowLauncherAnimations = false
willUnlockWithSmartspaceTransition = false
-
- // The lockscreen surface is gone, so it is now safe to re-show the smartspace.
- if (lockscreenSmartspace?.visibility == View.INVISIBLE) {
- lockscreenSmartspace?.visibility = View.VISIBLE
- }
-
- listeners.forEach { it.onUnlockAnimationFinished() }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index 6213265cb66e..2b6f77d280f8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -20,6 +20,8 @@ package com.android.systemui.keyguard
import android.content.res.Configuration
import android.view.View
import android.view.ViewGroup
+import com.android.keyguard.KeyguardStatusViewController
+import com.android.keyguard.dagger.KeyguardStatusViewComponent
import com.android.systemui.CoreStartable
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
@@ -80,6 +82,7 @@ constructor(
private val chipbarCoordinator: ChipbarCoordinator,
private val keyguardBlueprintCommandListener: KeyguardBlueprintCommandListener,
private val keyguardBlueprintViewModel: KeyguardBlueprintViewModel,
+ private val keyguardStatusViewComponentFactory: KeyguardStatusViewComponent.Factory,
) : CoreStartable {
private var rootViewHandle: DisposableHandle? = null
@@ -88,6 +91,7 @@ constructor(
private var rightShortcutHandle: KeyguardQuickAffordanceViewBinder.Binding? = null
private var ambientIndicationAreaHandle: KeyguardAmbientIndicationAreaViewBinder.Binding? = null
private var settingsPopupMenuHandle: DisposableHandle? = null
+ private var keyguardStatusViewController: KeyguardStatusViewController? = null
override fun start() {
bindKeyguardRootView()
@@ -96,6 +100,7 @@ constructor(
unbindKeyguardBottomArea(notificationPanel)
bindIndicationArea()
bindLockIconView(notificationPanel)
+ bindKeyguardStatusView(notificationPanel)
setupNotificationStackScrollLayout(notificationPanel)
bindLeftShortcut()
bindRightShortcut()
@@ -117,7 +122,7 @@ constructor(
sharedNotificationContainer.addNotificationStackScrollLayout(nssl)
SharedNotificationContainerBinder.bind(
sharedNotificationContainer,
- sharedNotificationContainerViewModel
+ sharedNotificationContainerViewModel,
)
}
}
@@ -132,14 +137,6 @@ constructor(
fun bindIndicationArea() {
indicationAreaHandle?.dispose()
- // At startup, 2 views with the ID `R.id.keyguard_indication_area` will be available.
- // Disable one of them
- if (!featureFlags.isEnabled(Flags.MIGRATE_INDICATION_AREA)) {
- keyguardRootView.findViewById<View?>(R.id.keyguard_indication_area)?.let {
- keyguardRootView.removeView(it)
- }
- }
-
indicationAreaHandle =
KeyguardIndicationAreaBinder.bind(
notificationShadeWindowView,
@@ -255,4 +252,31 @@ constructor(
}
}
}
+
+ fun bindKeyguardStatusView(legacyParent: ViewGroup) {
+ // At startup, 2 views with the ID `R.id.keyguard_status_view` will be available.
+ // Disable one of them
+ if (featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+ legacyParent.findViewById<View>(R.id.keyguard_status_view)?.let {
+ legacyParent.removeView(it)
+ }
+
+ val keyguardStatusView = keyguardRootView.addStatusView()
+ val statusViewComponent = keyguardStatusViewComponentFactory.build(keyguardStatusView)
+ val controller = statusViewComponent.getKeyguardStatusViewController()
+ controller.init()
+ keyguardStatusViewController = controller
+ } else {
+ keyguardRootView.findViewById<View?>(R.id.keyguard_status_view)?.let {
+ keyguardRootView.removeView(it)
+ }
+ }
+ }
+
+ /**
+ * Temporary, to allow NotificationPanelViewController to use the same instance while code is
+ * migrated: b/288242803
+ */
+ fun getKeyguardStatusViewController() = keyguardStatusViewController
+ fun getKeyguardRootView() = keyguardRootView
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 66de371ab6e0..f861d5e94540 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2561,7 +2561,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
} else if (mSurfaceBehindRemoteAnimationRunning) {
// We're already running the keyguard exit animation, likely due to an in-progress swipe
// to unlock.
- exitKeyguardAndFinishSurfaceBehindRemoteAnimation(false /* cancelled */);
+ exitKeyguardAndFinishSurfaceBehindRemoteAnimation(false /* showKeyguard */);
} else if (!mHideAnimationRun) {
if (DEBUG) Log.d(TAG, "tryKeyguardDone: starting pre-hide animation");
mHideAnimationRun = true;
@@ -3003,7 +3003,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mContext.getMainExecutor().execute(() -> {
if (finishedCallback == null) {
mKeyguardUnlockAnimationControllerLazy.get()
- .notifyFinishedKeyguardExitAnimation(false /* cancelled */);
+ .notifyFinishedKeyguardExitAnimation(false /* showKeyguard */);
mInteractionJankMonitor.end(CUJ_LOCKSCREEN_UNLOCK_ANIMATION);
return;
}
@@ -3120,7 +3120,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
// A lock is pending, meaning the keyguard exit animation was cancelled because we're
// re-locking. We should just end the surface-behind animation without exiting the
// keyguard. The pending lock will be handled by onFinishedGoingToSleep().
- finishSurfaceBehindRemoteAnimation(true);
+ finishSurfaceBehindRemoteAnimation(true /* showKeyguard */);
maybeHandlePendingLock();
} else {
Log.d(TAG, "#handleCancelKeyguardExitAnimation: keyguard exit animation cancelled. "
@@ -3129,7 +3129,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
// No lock is pending, so the animation was cancelled during the unlock sequence, but
// we should end up unlocked. Show the surface and exit the keyguard.
showSurfaceBehindKeyguard();
- exitKeyguardAndFinishSurfaceBehindRemoteAnimation(true /* cancelled */);
+ exitKeyguardAndFinishSurfaceBehindRemoteAnimation(false /* showKeyguard */);
}
}
@@ -3140,12 +3140,13 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
* with the RemoteAnimation, actually hide the keyguard, and clean up state related to the
* keyguard exit animation.
*
- * @param cancelled {@code true} if the animation was cancelled before it finishes.
+ * @param showKeyguard {@code true} if the animation was cancelled and keyguard should remain
+ * visible
*/
- public void exitKeyguardAndFinishSurfaceBehindRemoteAnimation(boolean cancelled) {
+ public void exitKeyguardAndFinishSurfaceBehindRemoteAnimation(boolean showKeyguard) {
Log.d(TAG, "onKeyguardExitRemoteAnimationFinished");
if (!mSurfaceBehindRemoteAnimationRunning && !mSurfaceBehindRemoteAnimationRequested) {
- Log.d(TAG, "skip onKeyguardExitRemoteAnimationFinished cancelled=" + cancelled
+ Log.d(TAG, "skip onKeyguardExitRemoteAnimationFinished showKeyguard=" + showKeyguard
+ " surfaceAnimationRunning=" + mSurfaceBehindRemoteAnimationRunning
+ " surfaceAnimationRequested=" + mSurfaceBehindRemoteAnimationRequested);
return;
@@ -3170,9 +3171,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
+ " wasShowing=" + wasShowing);
}
- mKeyguardUnlockAnimationControllerLazy.get()
- .notifyFinishedKeyguardExitAnimation(cancelled);
- finishSurfaceBehindRemoteAnimation(cancelled);
+ finishSurfaceBehindRemoteAnimation(showKeyguard);
// Dispatch the callback on animation finishes.
mUpdateMonitor.dispatchKeyguardDismissAnimationFinished();
@@ -3236,7 +3235,10 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
* This does not set keyguard state to either locked or unlocked, it simply ends the remote
* animation on the surface behind the keyguard. This can be called by
*/
- void finishSurfaceBehindRemoteAnimation(boolean cancelled) {
+ void finishSurfaceBehindRemoteAnimation(boolean showKeyguard) {
+ mKeyguardUnlockAnimationControllerLazy.get()
+ .notifyFinishedKeyguardExitAnimation(showKeyguard);
+
mSurfaceBehindRemoteAnimationRequested = false;
mSurfaceBehindRemoteAnimationRunning = false;
mKeyguardStateController.notifyKeyguardGoingAway(false);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
index 20ed549e42d4..45277b833ea3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
@@ -78,16 +78,8 @@ constructor(
override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState {
return when {
- !controller.isAvailableOnDevice ->
+ !isEnabledForPickerStateOption() ->
KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
- !controller.isAbleToOpenCameraApp -> {
- KeyguardQuickAffordanceConfig.PickerScreenState.Disabled(
- explanation =
- context.getString(
- R.string.qr_scanner_quick_affordance_unavailable_explanation
- ),
- )
- }
else -> KeyguardQuickAffordanceConfig.PickerScreenState.Default()
}
}
@@ -118,6 +110,11 @@ constructor(
}
}
+ /** Returns whether QR scanner be shown as one of available lockscreen shortcut option. */
+ private fun isEnabledForPickerStateOption(): Boolean {
+ return controller.isAbleToLaunchScannerActivity && controller.isAllowedOnLockScreen
+ }
+
companion object {
private const val TAG = "QrCodeScannerKeyguardQuickAffordanceConfig"
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index f1b344199516..e35c3699aabf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -199,13 +199,16 @@ interface KeyguardRepository {
fun setAnimateDozingTransitions(animate: Boolean)
/** Sets the current amount of alpha that should be used for rendering the bottom area. */
- @Deprecated("Deprecated as part of b/278057014")
- fun setBottomAreaAlpha(alpha: Float)
+ @Deprecated("Deprecated as part of b/278057014") fun setBottomAreaAlpha(alpha: Float)
/** Sets the current amount of alpha that should be used for rendering the keyguard. */
fun setKeyguardAlpha(alpha: Float)
- fun setKeyguardVisibility(statusBarState: Int, goingToFullShade: Boolean, occlusionTransitionRunning: Boolean)
+ fun setKeyguardVisibility(
+ statusBarState: Int,
+ goingToFullShade: Boolean,
+ occlusionTransitionRunning: Boolean
+ )
/**
* Sets the relative offset of the lock-screen clock from its natural position on the screen.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt
deleted file mode 100644
index 278c68d3c55b..000000000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.keyguard.domain.interactor
-
-import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
-import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
-import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
-
-/** Hosts business and application state accessing logic for the lockscreen scene. */
-@SysUISingleton
-class LockscreenSceneInteractor
-@Inject
-constructor(
- @Application applicationScope: CoroutineScope,
- private val authenticationInteractor: AuthenticationInteractor,
- private val bouncerInteractor: BouncerInteractor,
-) {
- /** Whether the device is currently locked. */
- val isDeviceLocked: StateFlow<Boolean> =
- authenticationInteractor.isUnlocked
- .map { !it }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = !authenticationInteractor.isUnlocked.value,
- )
-
- /** Whether it's currently possible to swipe up to dismiss the lockscreen. */
- val isSwipeToDismissEnabled: StateFlow<Boolean> =
- authenticationInteractor.isUnlocked
- .map { isUnlocked ->
- !isUnlocked &&
- authenticationInteractor.getAuthenticationMethod() is
- AuthenticationMethodModel.Swipe
- }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = false,
- )
-
- /** Attempts to dismiss the lockscreen. This will cause the bouncer to show, if needed. */
- fun dismissLockscreen() {
- bouncerInteractor.showOrUnlockDevice()
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt
index e60901f922c3..a94874176a34 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt
@@ -24,6 +24,7 @@ import android.view.View
import android.widget.ImageView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.res.ResourcesCompat
+import com.android.keyguard.KeyguardStatusView
import com.android.keyguard.LockIconView
import com.android.systemui.R
import com.android.systemui.animation.view.LaunchableImageView
@@ -38,6 +39,8 @@ class KeyguardRootView(
attrs,
) {
+ private var statusView: KeyguardStatusView? = null
+
init {
addIndicationTextArea()
addLockIconView()
@@ -45,6 +48,7 @@ class KeyguardRootView(
addLeftShortcut()
addRightShortcut()
addSettingsPopupMenu()
+ addStatusView()
}
private fun addIndicationTextArea() {
@@ -119,4 +123,19 @@ class KeyguardRootView(
}
addView(view)
}
+
+ fun addStatusView(): KeyguardStatusView {
+ // StatusView may need to be rebuilt on config changes. Remove and reinflate
+ statusView?.let { removeView(it) }
+ val view =
+ (LayoutInflater.from(context).inflate(R.layout.keyguard_status_view, this, false)
+ as KeyguardStatusView)
+ .apply {
+ setClipChildren(false)
+ statusView = this
+ }
+
+ addView(view)
+ return view
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt
index 5538fe7e7006..518df0719aaa 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt
@@ -25,6 +25,8 @@ import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAr
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultLockIconSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultSettingsPopupMenuSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection
+import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusViewSection
+import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeGuidelines
import javax.inject.Inject
/**
@@ -42,6 +44,8 @@ constructor(
private val defaultShortcutsSection: DefaultShortcutsSection,
private val defaultAmbientIndicationAreaSection: DefaultAmbientIndicationAreaSection,
private val defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection,
+ private val defaultStatusViewSection: DefaultStatusViewSection,
+ private val splitShadeGuidelines: SplitShadeGuidelines,
) : KeyguardBlueprint {
override val id: String = DEFAULT
@@ -51,6 +55,8 @@ constructor(
defaultShortcutsSection.apply(constraintSet)
defaultAmbientIndicationAreaSection.apply(constraintSet)
defaultSettingsPopupMenuSection.apply(constraintSet)
+ defaultStatusViewSection.apply(constraintSet)
+ splitShadeGuidelines.apply(constraintSet)
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt
index 19410e4ba89d..54c27960db3c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt
@@ -27,6 +27,8 @@ import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAr
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultLockIconSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultSettingsPopupMenuSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection
+import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusViewSection
+import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeGuidelines
import javax.inject.Inject
/** Vertically aligns the shortcuts with the udfps. */
@@ -41,6 +43,8 @@ constructor(
private val defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection,
private val alignShortcutsToUdfpsSection: AlignShortcutsToUdfpsSection,
private val defaultShortcutsSection: DefaultShortcutsSection,
+ private val defaultStatusViewSection: DefaultStatusViewSection,
+ private val splitShadeGuidelines: SplitShadeGuidelines,
) : KeyguardBlueprint {
override val id: String = SHORTCUTS_BESIDE_UDFPS
@@ -54,6 +58,8 @@ constructor(
} else {
defaultShortcutsSection.apply(constraintSet)
}
+ defaultStatusViewSection.apply(constraintSet)
+ splitShadeGuidelines.apply(constraintSet)
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
new file mode 100644
index 000000000000..3f319ba2d0e4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.ui.view.layout.sections
+
+import android.content.Context
+import android.view.ViewGroup
+import androidx.constraintlayout.widget.ConstraintSet
+import com.android.systemui.R
+import com.android.systemui.keyguard.data.repository.KeyguardSection
+import javax.inject.Inject
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
+import androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT
+import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
+import androidx.constraintlayout.widget.ConstraintSet.START
+import androidx.constraintlayout.widget.ConstraintSet.TOP
+import androidx.constraintlayout.widget.ConstraintSet.END
+
+class DefaultStatusViewSection @Inject constructor(private val context: Context) :
+ KeyguardSection {
+ private val statusViewId = R.id.keyguard_status_view
+
+ override fun apply(constraintSet: ConstraintSet) {
+ constraintSet.apply {
+ constrainWidth(statusViewId, MATCH_CONSTRAINT)
+ constrainHeight(statusViewId, WRAP_CONTENT)
+ connect(statusViewId, TOP, PARENT_ID, TOP)
+ connect(statusViewId, START, PARENT_ID, START)
+ connect(statusViewId, END, PARENT_ID, END)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeGuidelines.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeGuidelines.kt
new file mode 100644
index 000000000000..668b17ffeba0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeGuidelines.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.ui.view.layout.sections
+
+import android.content.Context
+import android.view.ViewGroup
+import androidx.constraintlayout.widget.ConstraintSet
+import com.android.systemui.R
+import com.android.systemui.keyguard.data.repository.KeyguardSection
+import javax.inject.Inject
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
+import androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT
+import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
+import androidx.constraintlayout.widget.ConstraintSet.START
+import androidx.constraintlayout.widget.ConstraintSet.TOP
+import androidx.constraintlayout.widget.ConstraintSet.END
+import androidx.constraintlayout.widget.ConstraintSet.VERTICAL
+
+class SplitShadeGuidelines @Inject constructor(private val context: Context) :
+ KeyguardSection {
+
+ override fun apply(constraintSet: ConstraintSet) {
+ constraintSet.apply {
+ // For use on large screens, it will provide a guideline vertically in the center to
+ // enable items to be aligned on the left or right sides
+ create(R.id.split_shade_guideline, VERTICAL)
+ setGuidelinePercent(R.id.split_shade_guideline, 0.5f)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
index abd178ca6c1d..f46d0eb449a0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
@@ -17,14 +17,17 @@
package com.android.systemui.keyguard.ui.viewmodel
import com.android.systemui.R
+import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
+import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
+import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
import com.android.systemui.scene.shared.model.SceneKey
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
@@ -36,36 +39,37 @@ class LockscreenSceneViewModel
@Inject
constructor(
@Application applicationScope: CoroutineScope,
- private val interactor: LockscreenSceneInteractor,
+ authenticationInteractor: AuthenticationInteractor,
+ private val bouncerInteractor: BouncerInteractor,
) {
/** The icon for the "lock" button on the lockscreen. */
val lockButtonIcon: StateFlow<Icon> =
- interactor.isDeviceLocked
- .map { isLocked -> lockIcon(isLocked = isLocked) }
+ authenticationInteractor.isUnlocked
+ .map { isUnlocked -> lockIcon(isUnlocked = isUnlocked) }
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = lockIcon(isLocked = interactor.isDeviceLocked.value),
+ initialValue = lockIcon(isUnlocked = authenticationInteractor.isUnlocked.value),
)
/** The key of the scene we should switch to when swiping up. */
- val upDestinationSceneKey: StateFlow<SceneKey> =
- interactor.isSwipeToDismissEnabled
- .map { isSwipeToUnlockEnabled -> upDestinationSceneKey(isSwipeToUnlockEnabled) }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = upDestinationSceneKey(interactor.isSwipeToDismissEnabled.value),
- )
+ val upDestinationSceneKey: Flow<SceneKey> =
+ authenticationInteractor.authenticationMethod.map { authenticationMethod ->
+ if (authenticationMethod is AuthenticationMethodModel.Swipe) {
+ SceneKey.Gone
+ } else {
+ SceneKey.Bouncer
+ }
+ }
/** Notifies that the lock button on the lock screen was clicked. */
fun onLockButtonClicked() {
- interactor.dismissLockscreen()
+ bouncerInteractor.showOrUnlockDevice()
}
/** Notifies that some content on the lock screen was clicked. */
fun onContentClicked() {
- interactor.dismissLockscreen()
+ bouncerInteractor.showOrUnlockDevice()
}
private fun upDestinationSceneKey(
@@ -75,22 +79,22 @@ constructor(
}
private fun lockIcon(
- isLocked: Boolean,
+ isUnlocked: Boolean,
): Icon {
return Icon.Resource(
res =
- if (isLocked) {
- R.drawable.ic_device_lock_on
- } else {
+ if (isUnlocked) {
R.drawable.ic_device_lock_off
+ } else {
+ R.drawable.ic_device_lock_on
},
contentDescription =
ContentDescription.Resource(
res =
- if (isLocked) {
- R.string.accessibility_lock_icon
- } else {
+ if (isUnlocked) {
R.string.accessibility_unlock_button
+ } else {
+ R.string.accessibility_lock_icon
}
)
)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
index fdb3ddd7294f..8f884d24ad21 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
@@ -30,11 +30,16 @@ import android.os.IBinder
import android.os.ResultReceiver
import android.os.UserHandle
import android.view.ViewGroup
-import com.android.intentresolver.AbstractMultiProfilePagerAdapter.EmptyStateProvider
-import com.android.intentresolver.AbstractMultiProfilePagerAdapter.MyUserIdProvider
-import com.android.intentresolver.ChooserActivity
-import com.android.intentresolver.chooser.TargetInfo
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.LifecycleRegistry
import com.android.internal.annotations.VisibleForTesting
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyStateProvider
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.MyUserIdProvider
+import com.android.internal.app.ChooserActivity
+import com.android.internal.app.ResolverListController
+import com.android.internal.app.chooser.NotSelectableTargetInfo
+import com.android.internal.app.chooser.TargetInfo
import com.android.systemui.R
import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorComponent
import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorController
@@ -51,8 +56,12 @@ class MediaProjectionAppSelectorActivity(
private val activityLauncher: AsyncActivityLauncher,
/** This is used to override the dependency in a screenshot test */
@VisibleForTesting
- private val listControllerFactory: ((userHandle: UserHandle) -> ChooserListController)?
-) : ChooserActivity(), MediaProjectionAppSelectorView, MediaProjectionAppSelectorResultHandler {
+ private val listControllerFactory: ((userHandle: UserHandle) -> ResolverListController)?
+) :
+ ChooserActivity(),
+ MediaProjectionAppSelectorView,
+ MediaProjectionAppSelectorResultHandler,
+ LifecycleOwner {
@Inject
constructor(
@@ -60,6 +69,8 @@ class MediaProjectionAppSelectorActivity(
activityLauncher: AsyncActivityLauncher
) : this(componentFactory, activityLauncher, listControllerFactory = null)
+ private val lifecycleRegistry = LifecycleRegistry(this)
+ override val lifecycle = lifecycleRegistry
private lateinit var configurationController: ConfigurationController
private lateinit var controller: MediaProjectionAppSelectorController
private lateinit var recentsViewController: MediaProjectionRecentsViewController
@@ -73,7 +84,8 @@ class MediaProjectionAppSelectorActivity(
override fun getLayoutResource() = R.layout.media_projection_app_selector
public override fun onCreate(bundle: Bundle?) {
- component = componentFactory.create(view = this, resultHandler = this)
+ lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
+ component = componentFactory.create(activity = this, view = this, resultHandler = this)
component.lifecycleObservers.forEach { lifecycle.addObserver(it) }
// Create a separate configuration controller for this activity as the configuration
@@ -95,6 +107,26 @@ class MediaProjectionAppSelectorActivity(
controller.init()
}
+ override fun onStart() {
+ super.onStart()
+ lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
+ }
+
+ override fun onResume() {
+ super.onResume()
+ lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
+ }
+
+ override fun onPause() {
+ lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
+ super.onPause()
+ }
+
+ override fun onStop() {
+ lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
+ super.onStop()
+ }
+
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
configurationController.onConfigurationChanged(newConfig)
@@ -105,13 +137,13 @@ class MediaProjectionAppSelectorActivity(
override fun createBlockerEmptyStateProvider(): EmptyStateProvider =
component.emptyStateProvider
- override fun createListController(userHandle: UserHandle): ChooserListController =
+ override fun createListController(userHandle: UserHandle): ResolverListController =
listControllerFactory?.invoke(userHandle) ?: super.createListController(userHandle)
override fun startSelected(which: Int, always: Boolean, filtered: Boolean) {
val currentListAdapter = mChooserMultiProfilePagerAdapter.activeListAdapter
val targetInfo = currentListAdapter.targetInfoForPosition(which, filtered) ?: return
- if (targetInfo.isNotSelectableTargetInfo) return
+ if (targetInfo is NotSelectableTargetInfo) return
val intent = createIntent(targetInfo)
@@ -151,6 +183,7 @@ class MediaProjectionAppSelectorActivity(
}
override fun onDestroy() {
+ lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
component.lifecycleObservers.forEach { lifecycle.removeObserver(it) }
// onDestroy is also called when an app is selected, in that case we only want to send
// RECORD_CONTENT_TASK but not RECORD_CANCEL
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index 7712690de195..3a1d8b0e238e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -296,7 +296,10 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
@Override
public void stop() {
- if (isBroadcastSupported() && mIsLeBroadcastCallbackRegistered) {
+ // unregister broadcast callback should only depend on profile and registered flag
+ // rather than remote device or broadcast state
+ // otherwise it might have risks of leaking registered callback handle
+ if (mMediaOutputController.isBroadcastSupported() && mIsLeBroadcastCallbackRegistered) {
mMediaOutputController.unregisterLeBroadcastServiceCallback(mBroadcastCallback);
mIsLeBroadcastCallbackRegistered = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index f3865f52e863..e5a6bb523916 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -104,11 +104,16 @@ public class MediaOutputDialog extends MediaOutputBaseDialog {
@Override
public boolean isBroadcastSupported() {
boolean isBluetoothLeDevice = false;
+ boolean isBroadcastEnabled = false;
if (FeatureFlagUtils.isEnabled(mContext,
FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST)) {
if (mMediaOutputController.getCurrentConnectedMediaDevice() != null) {
isBluetoothLeDevice = mMediaOutputController.isBluetoothLeDevice(
mMediaOutputController.getCurrentConnectedMediaDevice());
+ // if broadcast is active, broadcast should be considered as supported
+ // there could be a valid case that broadcast is ongoing
+ // without active LEA device connected
+ isBroadcastEnabled = mMediaOutputController.isBluetoothLeBroadcastEnabled();
}
} else {
// To decouple LE Audio Broadcast and Unicast, it always displays the button when there
@@ -116,7 +121,8 @@ public class MediaOutputDialog extends MediaOutputBaseDialog {
isBluetoothLeDevice = true;
}
- return mMediaOutputController.isBroadcastSupported() && isBluetoothLeDevice;
+ return mMediaOutputController.isBroadcastSupported()
+ && (isBluetoothLeDevice || isBroadcastEnabled);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
index e0869ac6498e..11538fadf24e 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
@@ -161,6 +161,7 @@ interface MediaProjectionAppSelectorComponent {
interface Factory {
/** Create a factory to inject the activity into the graph */
fun create(
+ @BindsInstance activity: MediaProjectionAppSelectorActivity,
@BindsInstance view: MediaProjectionAppSelectorView,
@BindsInstance resultHandler: MediaProjectionAppSelectorResultHandler,
): MediaProjectionAppSelectorComponent
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionBlockerEmptyStateProvider.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionBlockerEmptyStateProvider.kt
index fd14e2b9a96b..829b0ddbe3a8 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionBlockerEmptyStateProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionBlockerEmptyStateProvider.kt
@@ -17,10 +17,10 @@ package com.android.systemui.mediaprojection.appselector
import android.content.Context
import android.os.UserHandle
-import com.android.intentresolver.AbstractMultiProfilePagerAdapter.EmptyState
-import com.android.intentresolver.AbstractMultiProfilePagerAdapter.EmptyStateProvider
-import com.android.intentresolver.ResolverListAdapter
import com.android.internal.R as AndroidR
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyState
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyStateProvider
+import com.android.internal.app.ResolverListAdapter
import com.android.systemui.R
import com.android.systemui.mediaprojection.devicepolicy.PersonalProfile
import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
deleted file mode 100644
index d1d3e3de39f0..000000000000
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.people;
-
-import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID;
-import static android.appwidget.AppWidgetManager.INVALID_APPWIDGET_ID;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.ViewGroup;
-
-import androidx.activity.ComponentActivity;
-import androidx.lifecycle.ViewModelProvider;
-
-import com.android.systemui.compose.ComposeFacade;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
-import com.android.systemui.people.ui.view.PeopleViewBinder;
-import com.android.systemui.people.ui.viewmodel.PeopleViewModel;
-
-import javax.inject.Inject;
-
-import kotlin.Unit;
-import kotlin.jvm.functions.Function1;
-
-/** People Tile Widget configuration activity that shows the user their conversation tiles. */
-public class PeopleSpaceActivity extends ComponentActivity {
-
- private static final String TAG = "PeopleSpaceActivity";
- private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
-
- private final PeopleViewModel.Factory mViewModelFactory;
- private final FeatureFlags mFeatureFlags;
-
- @Inject
- public PeopleSpaceActivity(PeopleViewModel.Factory viewModelFactory,
- FeatureFlags featureFlags) {
- super();
- mViewModelFactory = viewModelFactory;
- mFeatureFlags = featureFlags;
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setResult(RESULT_CANCELED);
-
- PeopleViewModel viewModel = new ViewModelProvider(this, mViewModelFactory).get(
- PeopleViewModel.class);
-
- // Update the widget ID coming from the intent.
- int widgetId = getIntent().getIntExtra(EXTRA_APPWIDGET_ID, INVALID_APPWIDGET_ID);
- viewModel.onWidgetIdChanged(widgetId);
-
- Function1<PeopleViewModel.Result, Unit> onResult = (result) -> {
- finishActivity(result);
- return null;
- };
-
- if (mFeatureFlags.isEnabled(Flags.COMPOSE_PEOPLE_SPACE)
- && ComposeFacade.INSTANCE.isComposeAvailable()) {
- Log.d(TAG, "Using the Compose implementation of the PeopleSpaceActivity");
- ComposeFacade.INSTANCE.setPeopleSpaceActivityContent(this, viewModel, onResult);
- } else {
- Log.d(TAG, "Using the View implementation of the PeopleSpaceActivity");
- ViewGroup view = PeopleViewBinder.create(this);
- PeopleViewBinder.bind(view, viewModel, /* lifecycleOwner= */ this, onResult);
- setContentView(view);
- }
- }
-
- private void finishActivity(PeopleViewModel.Result result) {
- if (result instanceof PeopleViewModel.Result.Success) {
- if (DEBUG) Log.d(TAG, "Widget added!");
- Intent data = ((PeopleViewModel.Result.Success) result).getData();
- setResult(RESULT_OK, data);
- } else {
- if (DEBUG) Log.d(TAG, "Activity dismissed with no widgets added!");
- setResult(RESULT_CANCELED);
- }
- finish();
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.kt b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.kt
new file mode 100644
index 000000000000..5b7eb454597c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.people
+
+import android.appwidget.AppWidgetManager
+import android.os.Bundle
+import android.util.Log
+import androidx.activity.ComponentActivity
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.compose.ComposeFacade.isComposeAvailable
+import com.android.systemui.compose.ComposeFacade.setPeopleSpaceActivityContent
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.people.ui.view.PeopleViewBinder
+import com.android.systemui.people.ui.view.PeopleViewBinder.bind
+import com.android.systemui.people.ui.viewmodel.PeopleViewModel
+import javax.inject.Inject
+import kotlinx.coroutines.launch
+
+/** People Tile Widget configuration activity that shows the user their conversation tiles. */
+class PeopleSpaceActivity
+@Inject
+constructor(
+ private val viewModelFactory: PeopleViewModel.Factory,
+ private val featureFlags: FeatureFlags,
+) : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setResult(RESULT_CANCELED)
+
+ // Update the widget ID coming from the intent.
+ val viewModel = ViewModelProvider(this, viewModelFactory)[PeopleViewModel::class.java]
+ val widgetId =
+ intent.getIntExtra(
+ AppWidgetManager.EXTRA_APPWIDGET_ID,
+ AppWidgetManager.INVALID_APPWIDGET_ID,
+ )
+ viewModel.onWidgetIdChanged(widgetId)
+
+ // Make sure to refresh the tiles/conversations when the lifecycle is resumed, so that it
+ // updates them when going back to the Activity after leaving it.
+ // Note that we do this here instead of inside an effect in the PeopleScreen() composable
+ // because otherwise onTileRefreshRequested() will be called after the first composition,
+ // which will trigger a new recomposition and redraw, affecting the GPU memory (see
+ // b/276871425).
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.RESUMED) { viewModel.onTileRefreshRequested() }
+ }
+
+ // Set the content of the activity, using either the View or Compose implementation.
+ if (featureFlags.isEnabled(Flags.COMPOSE_PEOPLE_SPACE) && isComposeAvailable()) {
+ Log.d(TAG, "Using the Compose implementation of the PeopleSpaceActivity")
+ setPeopleSpaceActivityContent(
+ activity = this,
+ viewModel,
+ onResult = { finishActivity(it) },
+ )
+ } else {
+ Log.d(TAG, "Using the View implementation of the PeopleSpaceActivity")
+ val view = PeopleViewBinder.create(this)
+ bind(view, viewModel, lifecycleOwner = this, onResult = { finishActivity(it) })
+ setContentView(view)
+ }
+ }
+
+ private fun finishActivity(result: PeopleViewModel.Result) {
+ if (result is PeopleViewModel.Result.Success) {
+ if (DEBUG) Log.d(TAG, "Widget added!")
+ setResult(RESULT_OK, result.data)
+ } else {
+ if (DEBUG) Log.d(TAG, "Activity dismissed with no widgets added!")
+ setResult(RESULT_CANCELED)
+ }
+
+ finish()
+ }
+
+ companion object {
+ private const val TAG = "PeopleSpaceActivity"
+ private const val DEBUG = PeopleSpaceUtils.DEBUG
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/people/ui/view/PeopleViewBinder.kt b/packages/SystemUI/src/com/android/systemui/people/ui/view/PeopleViewBinder.kt
index d8a429e5bb1a..5f338c30c966 100644
--- a/packages/SystemUI/src/com/android/systemui/people/ui/view/PeopleViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/people/ui/view/PeopleViewBinder.kt
@@ -109,14 +109,6 @@ object PeopleViewBinder {
}
}
}
-
- // Make sure to refresh the tiles/conversations when the Activity is resumed, so that it
- // updates them when going back to the Activity after leaving it.
- lifecycleOwner.lifecycleScope.launch {
- lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
- viewModel.onTileRefreshRequested()
- }
- }
}
private fun setNoConversationsContent(view: ViewGroup, onGotItClicked: () -> Unit) {
diff --git a/packages/SystemUI/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerController.java b/packages/SystemUI/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerController.java
index fa3f878ff431..2d460a0d28fb 100644
--- a/packages/SystemUI/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerController.java
+++ b/packages/SystemUI/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerController.java
@@ -120,6 +120,7 @@ public class QRCodeScannerController implements
mUserTracker = userTracker;
mConfigEnableLockScreenButton = mContext.getResources().getBoolean(
android.R.bool.config_enableQrCodeScannerOnLockScreen);
+ mExecutor.execute(this::updateQRCodeScannerActivityDetails);
}
/**
@@ -158,18 +159,18 @@ public class QRCodeScannerController implements
* Returns true if lock screen entry point for QR Code Scanner is to be enabled.
*/
public boolean isEnabledForLockScreenButton() {
- return mQRCodeScannerEnabled && isAbleToOpenCameraApp() && isAvailableOnDevice();
+ return mQRCodeScannerEnabled && isAbleToLaunchScannerActivity() && isAllowedOnLockScreen();
}
- /** Returns whether the feature is available on the device. */
- public boolean isAvailableOnDevice() {
+ /** Returns whether the QR scanner button is allowed on lockscreen. */
+ public boolean isAllowedOnLockScreen() {
return mConfigEnableLockScreenButton;
}
/**
- * Returns true if the feature can open a camera app on the device.
+ * Returns true if the feature can open the configured QR scanner activity.
*/
- public boolean isAbleToOpenCameraApp() {
+ public boolean isAbleToLaunchScannerActivity() {
return mIntent != null && isActivityCallable(mIntent);
}
@@ -355,9 +356,6 @@ public class QRCodeScannerController implements
// Reset cached values to default as we are no longer listening
mOnDefaultQRCodeScannerChangedListener = null;
- mQRCodeScannerActivity = null;
- mIntent = null;
- mComponentName = null;
}
private void notifyQRCodeScannerActivityChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 7523d6e976ce..ddd9463affd9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -7,6 +7,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Bundle;
@@ -549,10 +550,8 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
return mPages.get(0).mRecords.size();
}
- public void startTileReveal(Set<String> tileSpecs, final Runnable postAnimation) {
- if (tileSpecs.isEmpty() || mPages.size() < 2 || getScrollX() != 0 || !beginFakeDrag()) {
- // Do not start the reveal animation unless there are tiles to animate, multiple
- // TileLayouts available and the user has not already started dragging.
+ public void startTileReveal(Set<String> tilesToReveal, final Runnable postAnimation) {
+ if (shouldNotRunAnimation(tilesToReveal)) {
return;
}
@@ -560,13 +559,13 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
final TileLayout lastPage = mPages.get(lastPageNumber);
final ArrayList<Animator> bounceAnims = new ArrayList<>();
for (TileRecord tr : lastPage.mRecords) {
- if (tileSpecs.contains(tr.tile.getTileSpec())) {
+ if (tilesToReveal.contains(tr.tile.getTileSpec())) {
bounceAnims.add(setupBounceAnimator(tr.tileView, bounceAnims.size()));
}
}
if (bounceAnims.isEmpty()) {
- // All tileSpecs are on the first page. Nothing to do.
+ // All tilesToReveal are on the first page. Nothing to do.
// TODO: potentially show a bounce animation for first page QS tiles
endFakeDrag();
return;
@@ -588,6 +587,16 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
postInvalidateOnAnimation();
}
+ private boolean shouldNotRunAnimation(Set<String> tilesToReveal) {
+ boolean noAnimationNeeded = tilesToReveal.isEmpty() || mPages.size() < 2;
+ boolean scrollingInProgress = getScrollX() != 0 || !beginFakeDrag();
+ // isRunningInTestHarness() to disable animation in functional testing as it caused
+ // flakiness and is not needed there. Alternative solutions were more complex and would
+ // still be either potentially flaky or modify internal data.
+ // For more info see b/253493927 and b/293234595
+ return noAnimationNeeded || scrollingInProgress || ActivityManager.isRunningInTestHarness();
+ }
+
private int sanitizePageAction(int action) {
int pageLeftId = AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT.getId();
int pageRightId = AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT.getId();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java
index 9e365d34bed9..1ba377bc9702 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java
@@ -120,7 +120,7 @@ public class QRCodeScannerTile extends QSTileImpl<QSTile.State> {
state.label = mContext.getString(R.string.qr_code_scanner_title);
state.contentDescription = state.label;
state.icon = ResourceIcon.get(R.drawable.ic_qr_code_scanner);
- state.state = mQRCodeScannerController.isAbleToOpenCameraApp() ? Tile.STATE_INACTIVE
+ state.state = mQRCodeScannerController.isAbleToLaunchScannerActivity() ? Tile.STATE_INACTIVE
: Tile.STATE_UNAVAILABLE;
// The assumption is that if the OEM has the QR code scanner module enabled then the scanner
// would go to "Unavailable" state only when GMS core is updating.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
index 5e6a44bf8130..4c6281e1cdb0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
@@ -16,19 +16,17 @@
package com.android.systemui.qs.ui.viewmodel
+import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
import javax.inject.Inject
/** Models UI state and handles user input for the quick settings scene. */
@SysUISingleton
class QuickSettingsSceneViewModel
@Inject
-constructor(
- private val lockscreenSceneInteractor: LockscreenSceneInteractor,
-) {
+constructor(private val bouncerInteractor: BouncerInteractor) {
/** Notifies that some content in quick settings was clicked. */
fun onContentClicked() {
- lockscreenSceneInteractor.dismissLockscreen()
+ bouncerInteractor.showOrUnlockDevice()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
index fee3960ff0e1..350fa38f2052 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
@@ -18,50 +18,49 @@
package com.android.systemui.scene.data.repository
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
-import com.android.systemui.scene.shared.model.SceneTransitionModel
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.stateIn
/** Source of truth for scene framework application state. */
class SceneContainerRepository
@Inject
constructor(
+ @Application applicationScope: CoroutineScope,
private val config: SceneContainerConfig,
) {
+ private val _desiredScene = MutableStateFlow(SceneModel(config.initialSceneKey))
+ val desiredScene: StateFlow<SceneModel> = _desiredScene.asStateFlow()
private val _isVisible = MutableStateFlow(true)
val isVisible: StateFlow<Boolean> = _isVisible.asStateFlow()
- private val _currentScene = MutableStateFlow(SceneModel(config.initialSceneKey))
- val currentScene: StateFlow<SceneModel> = _currentScene.asStateFlow()
-
- private val transitionState = MutableStateFlow<Flow<ObservableTransitionState>?>(null)
- val transitionProgress: Flow<Float> =
- transitionState.flatMapLatest { observableTransitionStateFlow ->
- observableTransitionStateFlow?.flatMapLatest { observableTransitionState ->
- when (observableTransitionState) {
- is ObservableTransitionState.Idle -> flowOf(1f)
- is ObservableTransitionState.Transition -> observableTransitionState.progress
- }
- }
- ?: flowOf(1f)
- }
-
- private val _transitions = MutableStateFlow<SceneTransitionModel?>(null)
- val transitions: StateFlow<SceneTransitionModel?> = _transitions.asStateFlow()
+ private val defaultTransitionState = ObservableTransitionState.Idle(config.initialSceneKey)
+ private val _transitionState = MutableStateFlow<Flow<ObservableTransitionState>?>(null)
+ val transitionState: StateFlow<ObservableTransitionState> =
+ _transitionState
+ .flatMapLatest { innerFlowOrNull -> innerFlowOrNull ?: flowOf(defaultTransitionState) }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = defaultTransitionState,
+ )
/**
- * Returns the keys to all scenes in the container with the given name.
+ * Returns the keys to all scenes in the container.
*
* The scenes will be sorted in z-order such that the last one is the one that should be
* rendered on top of all previous ones.
@@ -70,40 +69,19 @@ constructor(
return config.sceneKeys
}
- /** Sets the current scene in the container with the given name. */
- fun setCurrentScene(scene: SceneModel) {
+ fun setDesiredScene(scene: SceneModel) {
check(allSceneKeys().contains(scene.key)) {
"""
- Cannot set current scene key to "${scene.key}". The configuration does not contain a
- scene with that key.
- """
- .trimIndent()
- }
-
- _currentScene.value = scene
- }
-
- /** Sets the scene transition in the container with the given name. */
- fun setSceneTransition(from: SceneKey, to: SceneKey) {
- check(allSceneKeys().contains(from)) {
- """
- Cannot set current scene key to "$from". The configuration does not contain a scene
- with that key.
- """
- .trimIndent()
- }
- check(allSceneKeys().contains(to)) {
- """
- Cannot set current scene key to "$to". The configuration does not contain a scene
- with that key.
+ Cannot set the desired scene key to "${scene.key}". The configuration does not
+ contain a scene with that key.
"""
.trimIndent()
}
- _transitions.value = SceneTransitionModel(from = from, to = to)
+ _desiredScene.value = scene
}
- /** Sets whether the container with the given name is visible. */
+ /** Sets whether the container is visible. */
fun setVisible(isVisible: Boolean) {
_isVisible.value = isVisible
}
@@ -114,6 +92,6 @@ constructor(
* Note that you must call is with `null` when the UI is done or risk a memory leak.
*/
fun setTransitionState(transitionState: Flow<ObservableTransitionState>?) {
- this.transitionState.value = transitionState
+ _transitionState.value = transitionState
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index 64715bc26674..cf7abdd34b70 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -23,12 +23,15 @@ import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.RemoteUserInput
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
-import com.android.systemui.scene.shared.model.SceneTransitionModel
+import com.android.systemui.util.kotlin.pairwise
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.mapNotNull
/**
* Generic business logic and app state accessors for the scene framework.
@@ -46,7 +49,54 @@ constructor(
) {
/**
- * Returns the keys of all scenes in the container with the given name.
+ * The currently *desired* scene.
+ *
+ * **Important:** this value will _commonly be different_ from what is being rendered in the UI,
+ * by design.
+ *
+ * There are two intended sources for this value:
+ * 1. Programmatic requests to transition to another scene (calls to [changeScene]).
+ * 2. Reports from the UI about completing a transition to another scene (calls to
+ * [onSceneChanged]).
+ *
+ * Both the sources above cause the value of this flow to change; however, they cause mismatches
+ * in different ways.
+ *
+ * **Updates from programmatic transitions**
+ *
+ * When an external bit of code asks the framework to switch to another scene, the value here
+ * will update immediately. Downstream, the UI will detect this change and initiate the
+ * transition animation. As the transition animation progresses, a threshold will be reached, at
+ * which point the UI and the state here will match each other.
+ *
+ * **Updates from the UI**
+ *
+ * When the user interacts with the UI, the UI runs a transition animation that tracks the user
+ * pointer (for example, the user's finger). During this time, the state value here and what the
+ * UI shows will likely not match. Once/if a threshold is met, the UI reports it and commits the
+ * change, making the value here match the UI again.
+ */
+ val desiredScene: StateFlow<SceneModel> = repository.desiredScene
+
+ /**
+ * The current state of the transition.
+ *
+ * Consumers should use this state to know:
+ * 1. Whether there is an ongoing transition or if the system is at rest.
+ * 2. When transitioning, which scenes are being transitioned between.
+ * 3. When transitioning, what the progress of the transition is.
+ */
+ val transitionState: StateFlow<ObservableTransitionState> = repository.transitionState
+
+ /** Whether the scene container is visible. */
+ val isVisible: StateFlow<Boolean> = repository.isVisible
+
+ private val _remoteUserInput: MutableStateFlow<RemoteUserInput?> = MutableStateFlow(null)
+ /** A flow of motion events originating from outside of the scene framework. */
+ val remoteUserInput: StateFlow<RemoteUserInput?> = _remoteUserInput.asStateFlow()
+
+ /**
+ * Returns the keys of all scenes in the container.
*
* The scenes will be sorted in z-order such that the last one is the one that should be
* rendered on top of all previous ones.
@@ -55,26 +105,20 @@ constructor(
return repository.allSceneKeys()
}
- /** Sets the scene in the container with the given name. */
- fun setCurrentScene(scene: SceneModel, loggingReason: String) {
- val currentSceneKey = repository.currentScene.value.key
- if (currentSceneKey == scene.key) {
- return
- }
-
- logger.logSceneChange(
- from = currentSceneKey,
- to = scene.key,
- reason = loggingReason,
- )
- repository.setCurrentScene(scene)
- repository.setSceneTransition(from = currentSceneKey, to = scene.key)
+ /**
+ * Requests a scene change to the given scene.
+ *
+ * The change is animated. Therefore, while the value in [desiredScene] will update immediately,
+ * it will be some time before the UI will switch to the desired scene. The scene change
+ * requested is remembered here but served by the UI layer, which will start a transition
+ * animation. Once enough of the transition has occurred, the system will come into agreement
+ * between the [desiredScene] and the UI.
+ */
+ fun changeScene(scene: SceneModel, loggingReason: String) {
+ updateDesiredScene(scene, loggingReason, logger::logSceneChangeRequested)
}
- /** The current scene in the container with the given name. */
- val currentScene: StateFlow<SceneModel> = repository.currentScene
-
- /** Sets the visibility of the container with the given name. */
+ /** Sets the visibility of the container. */
fun setVisible(isVisible: Boolean, loggingReason: String) {
val wasVisible = repository.isVisible.value
if (wasVisible == isVisible) {
@@ -89,9 +133,6 @@ constructor(
return repository.setVisible(isVisible)
}
- /** Whether the container with the given name is visible. */
- val isVisible: StateFlow<Boolean> = repository.isVisible
-
/**
* Binds the given flow so the system remembers it.
*
@@ -101,23 +142,53 @@ constructor(
repository.setTransitionState(transitionState)
}
- /** Progress of the transition into the current scene in the container with the given name. */
- val transitionProgress: Flow<Float> = repository.transitionProgress
-
/**
- * Scene transitions as pairs of keys. A new value is emitted exactly once, each time a scene
- * transition occurs. The flow begins with a `null` value at first, because the initial scene is
- * not something that we transition to from another scene.
+ * Returns a stream of events that emits one [Unit] every time the framework transitions from
+ * [from] to [to].
*/
- val transitions: StateFlow<SceneTransitionModel?> = repository.transitions
-
- private val _remoteUserInput: MutableStateFlow<RemoteUserInput?> = MutableStateFlow(null)
-
- /** A flow of motion events originating from outside of the scene framework. */
- val remoteUserInput: StateFlow<RemoteUserInput?> = _remoteUserInput.asStateFlow()
+ fun finishedSceneTransitions(from: SceneKey, to: SceneKey): Flow<Unit> {
+ return transitionState
+ .mapNotNull { it as? ObservableTransitionState.Idle }
+ .map { idleState -> idleState.scene }
+ .distinctUntilChanged()
+ .pairwise()
+ .mapNotNull { (previousSceneKey, currentSceneKey) ->
+ Unit.takeIf { previousSceneKey == from && currentSceneKey == to }
+ }
+ }
/** Handles a remote user input. */
fun onRemoteUserInput(input: RemoteUserInput) {
_remoteUserInput.value = input
}
+
+ /**
+ * Notifies that the UI has transitioned sufficiently to the given scene.
+ *
+ * *Not intended for external use!*
+ *
+ * Once a transition between one scene and another passes a threshold, the UI invokes this
+ * method to report it, updating the value in [desiredScene] to match what the UI shows.
+ */
+ internal fun onSceneChanged(scene: SceneModel, loggingReason: String) {
+ updateDesiredScene(scene, loggingReason, logger::logSceneChangeCommitted)
+ }
+
+ private fun updateDesiredScene(
+ scene: SceneModel,
+ loggingReason: String,
+ log: (from: SceneKey, to: SceneKey, loggingReason: String) -> Unit,
+ ) {
+ val currentSceneKey = desiredScene.value.key
+ if (currentSceneKey == scene.key) {
+ return
+ }
+
+ log(
+ /* from= */ currentSceneKey,
+ /* to= */ scene.key,
+ /* loggingReason= */ loggingReason,
+ )
+ repository.setDesiredScene(scene)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index 20ee393e8dac..afefccb27214 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -18,6 +18,7 @@ package com.android.systemui.scene.domain.startable
import com.android.systemui.CoreStartable
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
+import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.DisplayId
@@ -29,6 +30,7 @@ import com.android.systemui.model.SysUiState
import com.android.systemui.model.updateFlags
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.logger.SceneLogger
+import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING
@@ -39,8 +41,8 @@ import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_B
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.launch
/**
@@ -72,14 +74,31 @@ constructor(
}
}
- /** Updates the visibility of the scene container based on the current scene. */
+ /** Updates the visibility of the scene container. */
private fun hydrateVisibility() {
applicationScope.launch {
- sceneInteractor.currentScene
- .map { it.key }
+ sceneInteractor.transitionState
+ .mapNotNull { state ->
+ when (state) {
+ is ObservableTransitionState.Idle -> {
+ if (state.scene != SceneKey.Gone) {
+ true to "scene is not Gone"
+ } else {
+ false to "scene is Gone"
+ }
+ }
+ is ObservableTransitionState.Transition -> {
+ if (state.fromScene == SceneKey.Gone) {
+ true to "scene transitioning away from Gone"
+ } else {
+ null
+ }
+ }
+ }
+ }
.distinctUntilChanged()
- .collect { sceneKey ->
- sceneInteractor.setVisible(sceneKey != SceneKey.Gone, "scene is $sceneKey")
+ .collect { (isVisible, loggingReason) ->
+ sceneInteractor.setVisible(isVisible, loggingReason)
}
}
}
@@ -88,43 +107,55 @@ constructor(
private fun automaticallySwitchScenes() {
applicationScope.launch {
authenticationInteractor.isUnlocked
- .map { isUnlocked ->
- val currentSceneKey = sceneInteractor.currentScene.value.key
+ .mapNotNull { isUnlocked ->
+ val renderedScenes =
+ when (val transitionState = sceneInteractor.transitionState.value) {
+ is ObservableTransitionState.Idle -> setOf(transitionState.scene)
+ is ObservableTransitionState.Transition ->
+ setOf(
+ transitionState.progress,
+ transitionState.toScene,
+ )
+ }
val isBypassEnabled = authenticationInteractor.isBypassEnabled()
when {
isUnlocked ->
- when (currentSceneKey) {
+ when {
// When the device becomes unlocked in Bouncer, go to Gone.
- is SceneKey.Bouncer ->
+ renderedScenes.contains(SceneKey.Bouncer) ->
SceneKey.Gone to "device unlocked in Bouncer scene"
+
// When the device becomes unlocked in Lockscreen, go to Gone if
// bypass is enabled.
- is SceneKey.Lockscreen ->
+ renderedScenes.contains(SceneKey.Lockscreen) ->
if (isBypassEnabled) {
SceneKey.Gone to
"device unlocked in Lockscreen scene with bypass"
} else {
null
}
+
// We got unlocked while on a scene that's not Lockscreen or
// Bouncer, no need to change scenes.
else -> null
}
+
// When the device becomes locked, to Lockscreen.
!isUnlocked ->
- when (currentSceneKey) {
+ when {
// Already on lockscreen or bouncer, no need to change scenes.
- is SceneKey.Lockscreen,
- is SceneKey.Bouncer -> null
+ renderedScenes.contains(SceneKey.Lockscreen) ||
+ renderedScenes.contains(SceneKey.Bouncer) -> null
+
// We got locked while on a scene that's not Lockscreen or Bouncer,
// go to Lockscreen.
else ->
- SceneKey.Lockscreen to "device locked in $currentSceneKey scene"
+ SceneKey.Lockscreen to
+ "device locked in non-Lockscreen and non-Bouncer scene"
}
else -> null
}
}
- .filterNotNull()
.collect { (targetSceneKey, loggingReason) ->
switchToScene(
targetSceneKey = targetSceneKey,
@@ -135,22 +166,27 @@ constructor(
applicationScope.launch {
keyguardInteractor.wakefulnessModel
- .map { it.state == WakefulnessState.ASLEEP }
+ .map { wakefulnessModel -> wakefulnessModel.state }
.distinctUntilChanged()
- .collect { isAsleep ->
- if (isAsleep) {
- // When the device goes to sleep, reset the current scene.
- val isUnlocked = authenticationInteractor.isUnlocked.value
- val (targetSceneKey, loggingReason) =
- if (isUnlocked) {
- SceneKey.Gone to "device is asleep while unlocked"
- } else {
- SceneKey.Lockscreen to "device is asleep while locked"
+ .collect { wakefulnessState ->
+ when (wakefulnessState) {
+ WakefulnessState.STARTING_TO_SLEEP -> {
+ switchToScene(
+ targetSceneKey = SceneKey.Lockscreen,
+ loggingReason = "device is starting to sleep",
+ )
+ }
+ WakefulnessState.STARTING_TO_WAKE -> {
+ val authMethod = authenticationInteractor.getAuthenticationMethod()
+ if (authMethod == AuthenticationMethodModel.None) {
+ switchToScene(
+ targetSceneKey = SceneKey.Gone,
+ loggingReason =
+ "device is starting to wake up while auth method is None",
+ )
}
- switchToScene(
- targetSceneKey = targetSceneKey,
- loggingReason = loggingReason,
- )
+ }
+ else -> Unit
}
}
}
@@ -159,8 +195,9 @@ constructor(
/** Keeps [SysUiState] up-to-date */
private fun hydrateSystemUiState() {
applicationScope.launch {
- sceneInteractor.currentScene
- .map { it.key }
+ sceneInteractor.transitionState
+ .mapNotNull { it as? ObservableTransitionState.Idle }
+ .map { it.scene }
.distinctUntilChanged()
.collect { sceneKey ->
sysUiState.updateFlags(
@@ -177,7 +214,7 @@ constructor(
}
private fun switchToScene(targetSceneKey: SceneKey, loggingReason: String) {
- sceneInteractor.setCurrentScene(
+ sceneInteractor.changeScene(
scene = SceneModel(targetSceneKey),
loggingReason = loggingReason,
)
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
index 0adbd5ad19a7..62136dcd8e1d 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
@@ -37,7 +37,7 @@ class SceneLogger @Inject constructor(@SceneFrameworkLog private val logBuffer:
)
}
- fun logSceneChange(
+ fun logSceneChangeRequested(
from: SceneKey,
to: SceneKey,
reason: String,
@@ -50,7 +50,24 @@ class SceneLogger @Inject constructor(@SceneFrameworkLog private val logBuffer:
str2 = to.toString()
str3 = reason
},
- messagePrinter = { "$str1 → $str2, reason: $str3" },
+ messagePrinter = { "Scene change requested: $str1 → $str2, reason: $str3" },
+ )
+ }
+
+ fun logSceneChangeCommitted(
+ from: SceneKey,
+ to: SceneKey,
+ reason: String,
+ ) {
+ logBuffer.log(
+ tag = TAG,
+ level = LogLevel.INFO,
+ messageInitializer = {
+ str1 = from.toString()
+ str2 = to.toString()
+ str3 = reason
+ },
+ messagePrinter = { "Scene change committed: $str1 → $str2, reason: $str3" },
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneTransitionModel.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneTransitionModel.kt
deleted file mode 100644
index c8f46a72d64f..000000000000
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneTransitionModel.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.scene.shared.model
-
-/** Models a transition between two scenes. */
-data class SceneTransitionModel(
- /** The scene we transitioned away from. */
- val from: SceneKey,
- /** The scene we transitioned into. */
- val to: SceneKey,
-)
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
index b4ebaece21f1..3e9bbe464e2c 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
@@ -45,15 +45,15 @@ constructor(
*/
val allSceneKeys: List<SceneKey> = interactor.allSceneKeys()
- /** The current scene. */
- val currentScene: StateFlow<SceneModel> = interactor.currentScene
+ /** The scene that should be rendered. */
+ val currentScene: StateFlow<SceneModel> = interactor.desiredScene
/** Whether the container is visible. */
val isVisible: StateFlow<Boolean> = interactor.isVisible
- /** Requests a transition to the scene with the given key. */
- fun setCurrentScene(scene: SceneModel) {
- interactor.setCurrentScene(
+ /** Notifies that the UI has transitioned sufficiently to the given scene. */
+ fun onSceneChanged(scene: SceneModel) {
+ interactor.onSceneChanged(
scene = scene,
loggingReason = SCENE_TRANSITION_LOGGING_REASON,
)
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
index a8f99bef2423..05a0416f8f64 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
@@ -19,6 +19,7 @@ package com.android.systemui.screenshot
import android.content.ClipData
import android.content.ClipDescription
import android.content.ComponentName
+import android.content.ContentProvider
import android.content.Context
import android.content.Intent
import android.net.Uri
@@ -26,21 +27,19 @@ import com.android.systemui.R
object ActionIntentCreator {
/** @return a chooser intent to share the given URI. */
- fun createShareIntent(uri: Uri) = createShareIntent(uri, null, null)
+ fun createShare(uri: Uri): Intent = createShare(uri, subject = null, text = null)
/** @return a chooser intent to share the given URI with the optional provided subject. */
- fun createShareIntentWithSubject(uri: Uri, subject: String?) =
- createShareIntent(uri, subject = subject)
+ fun createShareWithSubject(uri: Uri, subject: String): Intent =
+ createShare(uri, subject = subject)
/** @return a chooser intent to share the given URI with the optional provided extra text. */
- fun createShareIntentWithExtraText(uri: Uri, extraText: String?) =
- createShareIntent(uri, extraText = extraText)
+ fun createShareWithText(uri: Uri, extraText: String): Intent =
+ createShare(uri, text = extraText)
+
+ private fun createShare(rawUri: Uri, subject: String? = null, text: String? = null): Intent {
+ val uri = uriWithoutUserId(rawUri)
- private fun createShareIntent(
- uri: Uri,
- subject: String? = null,
- extraText: String? = null
- ): Intent {
// Create a share intent, this will always go through the chooser activity first
// which should not trigger auto-enter PiP
val sharingIntent =
@@ -56,8 +55,8 @@ object ActionIntentCreator {
ClipData.Item(uri)
)
- putExtra(Intent.EXTRA_SUBJECT, subject)
- putExtra(Intent.EXTRA_TEXT, extraText)
+ subject?.let { putExtra(Intent.EXTRA_SUBJECT, subject) }
+ text?.let { putExtra(Intent.EXTRA_TEXT, text) }
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
}
@@ -72,13 +71,13 @@ object ActionIntentCreator {
* @return an ACTION_EDIT intent for the given URI, directed to config_screenshotEditor if
* available.
*/
- fun createEditIntent(uri: Uri, context: Context): Intent {
+ fun createEdit(rawUri: Uri, context: Context): Intent {
+ val uri = uriWithoutUserId(rawUri)
val editIntent = Intent(Intent.ACTION_EDIT)
- context.getString(R.string.config_screenshotEditor)?.let {
- if (it.isNotEmpty()) {
- editIntent.component = ComponentName.unflattenFromString(it)
- }
+ val editor = context.getString(R.string.config_screenshotEditor)
+ if (editor.isNotEmpty()) {
+ editIntent.component = ComponentName.unflattenFromString(editor)
}
return editIntent
@@ -89,3 +88,12 @@ object ActionIntentCreator {
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
}
}
+
+/**
+ * URIs here are passed only via Intent which are sent to the target user via Intent. Because of
+ * this, the userId component can be removed to prevent compatibility issues when an app attempts
+ * valid a URI containing a userId within the authority.
+ */
+private fun uriWithoutUserId(uri: Uri): Uri {
+ return ContentProvider.getUriWithoutUserId(uri)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
index 187019a4851d..ecd456887fa4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
@@ -19,6 +19,7 @@ package com.android.systemui.screenshot
import android.content.Context
import android.content.Intent
import android.os.Bundle
+import android.os.Process.myUserHandle
import android.os.RemoteException
import android.os.UserHandle
import android.util.Log
@@ -44,10 +45,10 @@ import kotlinx.coroutines.withContext
class ActionIntentExecutor
@Inject
constructor(
+ private val context: Context,
@Application private val applicationScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
- private val context: Context,
- private val displayTracker: DisplayTracker
+ private val displayTracker: DisplayTracker,
) {
/**
* Execute the given intent with startActivity while performing operations for screenshot action
@@ -58,25 +59,25 @@ constructor(
*/
fun launchIntentAsync(
intent: Intent,
- bundle: Bundle,
- userId: Int,
+ options: Bundle?,
+ user: UserHandle,
overrideTransition: Boolean,
) {
- applicationScope.launch { launchIntent(intent, bundle, userId, overrideTransition) }
+ applicationScope.launch { launchIntent(intent, options, user, overrideTransition) }
}
suspend fun launchIntent(
intent: Intent,
- bundle: Bundle,
- userId: Int,
+ options: Bundle?,
+ user: UserHandle,
overrideTransition: Boolean,
) {
dismissKeyguard()
- if (userId == UserHandle.myUserId()) {
- withContext(mainDispatcher) { context.startActivity(intent, bundle) }
+ if (user == myUserHandle()) {
+ withContext(mainDispatcher) { context.startActivity(intent, options) }
} else {
- launchCrossProfileIntent(userId, intent, bundle)
+ launchCrossProfileIntent(user, intent, options)
}
if (overrideTransition) {
@@ -111,17 +112,21 @@ constructor(
completion.await()
}
- private fun getCrossProfileConnector(userId: Int): ServiceConnector<ICrossProfileService> =
+ private fun getCrossProfileConnector(user: UserHandle): ServiceConnector<ICrossProfileService> =
ServiceConnector.Impl<ICrossProfileService>(
context,
Intent(context, ScreenshotCrossProfileService::class.java),
Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE,
- userId,
+ user.identifier,
ICrossProfileService.Stub::asInterface,
)
- private suspend fun launchCrossProfileIntent(userId: Int, intent: Intent, bundle: Bundle) {
- val connector = getCrossProfileConnector(userId)
+ private suspend fun launchCrossProfileIntent(
+ user: UserHandle,
+ intent: Intent,
+ bundle: Bundle?
+ ) {
+ val connector = getCrossProfileConnector(user)
val completion = CompletableDeferred<Unit>()
connector.post {
it.launchIntent(intent, bundle)
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
index e6e1faccc3e2..53dbe7624806 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -334,9 +334,9 @@ public class LongScreenshotActivity extends Activity {
if (mScreenshotUserHandle != Process.myUserHandle()) {
// TODO: Fix transition for work profile. Omitting it in the meantime.
mActionExecutor.launchIntentAsync(
- ActionIntentCreator.INSTANCE.createEditIntent(uri, this),
+ ActionIntentCreator.INSTANCE.createEdit(uri, this),
null,
- mScreenshotUserHandle.getIdentifier(), false);
+ mScreenshotUserHandle, false);
} else {
String editorPackage = getString(R.string.config_screenshotEditor);
Intent intent = new Intent(Intent.ACTION_EDIT);
@@ -362,9 +362,8 @@ public class LongScreenshotActivity extends Activity {
}
private void doShare(Uri uri) {
- Intent shareIntent = ActionIntentCreator.INSTANCE.createShareIntent(uri);
- mActionExecutor.launchIntentAsync(shareIntent, null,
- mScreenshotUserHandle.getIdentifier(), false);
+ Intent shareIntent = ActionIntentCreator.INSTANCE.createShare(uri);
+ mActionExecutor.launchIntentAsync(shareIntent, null, mScreenshotUserHandle, false);
}
private void onClicked(View v) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 093c09fff995..3903bb2815ef 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -801,31 +801,31 @@ public class ScreenshotView extends FrameLayout implements
Intent shareIntent;
if (mFlags.isEnabled(Flags.SCREENSHOT_METADATA) && mScreenshotData != null
&& mScreenshotData.getContextUrl() != null) {
- shareIntent = ActionIntentCreator.INSTANCE.createShareIntentWithExtraText(
+ shareIntent = ActionIntentCreator.INSTANCE.createShareWithText(
imageData.uri, mScreenshotData.getContextUrl().toString());
} else {
- shareIntent = ActionIntentCreator.INSTANCE.createShareIntentWithSubject(
+ shareIntent = ActionIntentCreator.INSTANCE.createShareWithSubject(
imageData.uri, imageData.subject);
}
mActionExecutor.launchIntentAsync(shareIntent,
imageData.shareTransition.get().bundle,
- imageData.owner.getIdentifier(), false);
+ imageData.owner, false);
});
mEditChip.setOnClickListener(v -> {
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EDIT_TAPPED, 0, mPackageName);
prepareSharedTransition();
mActionExecutor.launchIntentAsync(
- ActionIntentCreator.INSTANCE.createEditIntent(imageData.uri, mContext),
+ ActionIntentCreator.INSTANCE.createEdit(imageData.uri, mContext),
imageData.editTransition.get().bundle,
- imageData.owner.getIdentifier(), true);
+ imageData.owner, true);
});
mScreenshotPreview.setOnClickListener(v -> {
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED, 0, mPackageName);
prepareSharedTransition();
mActionExecutor.launchIntentAsync(
- ActionIntentCreator.INSTANCE.createEditIntent(imageData.uri, mContext),
+ ActionIntentCreator.INSTANCE.createEdit(imageData.uri, mContext),
imageData.editTransition.get().bundle,
- imageData.owner.getIdentifier(), true);
+ imageData.owner, true);
});
if (mQuickShareChip != null) {
if (imageData.quickShareAction != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
index d33d113f6cbd..2f0fc5127009 100644
--- a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
@@ -228,6 +228,8 @@ open class SensorUseStartedActivity @Inject constructor(
}
override fun onDismiss(dialog: DialogInterface?) {
- finish()
+ if (!isChangingConfigurations) {
+ finish()
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/DisplayTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/DisplayTracker.kt
index 468a75d8276e..e7ee961e1888 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/DisplayTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/DisplayTracker.kt
@@ -48,6 +48,9 @@ interface DisplayTracker {
/** Remove a [Callback] previously added. */
fun removeCallback(callback: Callback)
+ /** Gets the Display with the given displayId */
+ fun getDisplay(displayId: Int): Display
+
/** Ćallback for notifying of changes. */
interface Callback {
diff --git a/packages/SystemUI/src/com/android/systemui/settings/DisplayTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/DisplayTrackerImpl.kt
index 5169f88c373c..68cc483fbe80 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/DisplayTrackerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/DisplayTrackerImpl.kt
@@ -115,6 +115,10 @@ internal constructor(
}
}
+ override fun getDisplay(displayId: Int): Display {
+ return displayManager.getDisplay(displayId)
+ }
+
@WorkerThread
private fun onDisplayAdded(displayId: Int, list: List<DisplayTrackerDataItem>) {
Assert.isNotMainThread()
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 416f147b7429..35fd98cf34c6 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -90,6 +90,8 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
+import androidx.constraintlayout.widget.ConstraintLayout;
+
import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
@@ -1053,10 +1055,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
mKeyguardStatusBarViewController.init();
mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent);
- updateViewControllers(
- mView.findViewById(R.id.keyguard_status_view),
- userAvatarContainer,
- keyguardUserSwitcherView);
+ updateViewControllers(userAvatarContainer, keyguardUserSwitcherView);
mNotificationStackScrollLayoutController.setOnHeightChangedListener(
new NsslHeightChangedListener());
@@ -1218,18 +1217,31 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
mQsController.loadDimens();
}
- private void updateViewControllers(KeyguardStatusView keyguardStatusView,
+ private void updateViewControllers(
FrameLayout userAvatarView,
KeyguardUserSwitcherView keyguardUserSwitcherView) {
+ // Re-associate the KeyguardStatusViewController
if (mKeyguardStatusViewController != null) {
mKeyguardStatusViewController.onDestroy();
}
- // Re-associate the KeyguardStatusViewController
- KeyguardStatusViewComponent statusViewComponent =
+
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+ // Need a shared controller until mKeyguardStatusViewController can be removed from
+ // here, due to important state being set in that controller. Rebind in order to pick
+ // up config changes
+ mKeyguardViewConfigurator.bindKeyguardStatusView(mView);
+ mKeyguardStatusViewController =
+ mKeyguardViewConfigurator.getKeyguardStatusViewController();
+ } else {
+ KeyguardStatusView keyguardStatusView = mView.getRootView().findViewById(
+ R.id.keyguard_status_view);
+ KeyguardStatusViewComponent statusViewComponent =
mKeyguardStatusViewComponentFactory.build(keyguardStatusView);
- mKeyguardStatusViewController = statusViewComponent.getKeyguardStatusViewController();
- mKeyguardStatusViewController.init();
+ mKeyguardStatusViewController = statusViewComponent.getKeyguardStatusViewController();
+ mKeyguardStatusViewController.init();
+ }
mKeyguardStatusViewController.setSplitShadeEnabled(mSplitShadeEnabled);
+
updateClockAppearance();
if (mKeyguardUserSwitcherController != null) {
@@ -1335,15 +1347,22 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
void reInflateViews() {
debugLog("reInflateViews");
// Re-inflate the status view group.
- KeyguardStatusView keyguardStatusView =
- mNotificationContainerParent.findViewById(R.id.keyguard_status_view);
- int statusIndex = mNotificationContainerParent.indexOfChild(keyguardStatusView);
- mNotificationContainerParent.removeView(keyguardStatusView);
- keyguardStatusView = (KeyguardStatusView) mLayoutInflater.inflate(
- R.layout.keyguard_status_view, mNotificationContainerParent, false);
- mNotificationContainerParent.addView(keyguardStatusView, statusIndex);
- attachSplitShadeMediaPlayerContainer(
- keyguardStatusView.findViewById(R.id.status_view_media_container));
+ if (!mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+ KeyguardStatusView keyguardStatusView =
+ mNotificationContainerParent.findViewById(R.id.keyguard_status_view);
+ int statusIndex = mNotificationContainerParent.indexOfChild(keyguardStatusView);
+ mNotificationContainerParent.removeView(keyguardStatusView);
+ keyguardStatusView = (KeyguardStatusView) mLayoutInflater.inflate(
+ R.layout.keyguard_status_view, mNotificationContainerParent, false);
+ mNotificationContainerParent.addView(keyguardStatusView, statusIndex);
+
+ attachSplitShadeMediaPlayerContainer(
+ keyguardStatusView.findViewById(R.id.status_view_media_container));
+ } else {
+ attachSplitShadeMediaPlayerContainer(
+ mKeyguardViewConfigurator.getKeyguardRootView()
+ .findViewById(R.id.status_view_media_container));
+ }
// we need to update KeyguardStatusView constraints after reinflating it
updateResources();
@@ -1369,8 +1388,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
R.layout.keyguard_user_switcher /* layoutId */,
showKeyguardUserSwitcher /* enabled */);
- updateViewControllers(mView.findViewById(R.id.keyguard_status_view), userAvatarView,
- keyguardUserSwitcherView);
+ updateViewControllers(userAvatarView, keyguardUserSwitcherView);
if (!mFeatureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
// Update keyguard bottom area
@@ -1666,8 +1684,14 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
private void updateKeyguardStatusViewAlignment(boolean animate) {
boolean shouldBeCentered = shouldKeyguardStatusViewBeCentered();
+ ConstraintLayout layout;
+ if (mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+ layout = mKeyguardViewConfigurator.getKeyguardRootView();
+ } else {
+ layout = mNotificationContainerParent;
+ }
mKeyguardStatusViewController.updateAlignment(
- mNotificationContainerParent, mSplitShadeEnabled, shouldBeCentered, animate);
+ layout, mSplitShadeEnabled, shouldBeCentered, animate);
mKeyguardUnfoldTransition.ifPresent(t -> t.setStatusViewCentered(shouldBeCentered));
}
@@ -3390,7 +3414,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
ipw.print("mPanelFlingOvershootAmount="); ipw.println(mPanelFlingOvershootAmount);
ipw.print("mLastGesturedOverExpansion="); ipw.println(mLastGesturedOverExpansion);
ipw.print("mIsSpringBackAnimation="); ipw.println(mIsSpringBackAnimation);
- ipw.print("mSplitShadeEnabled="); ipw.println(mSplitShadeEnabled);
ipw.print("mHintDistance="); ipw.println(mHintDistance);
ipw.print("mInitialOffsetOnTouch="); ipw.println(mInitialOffsetOnTouch);
ipw.print("mCollapsedAndHeadsUpOnDown="); ipw.println(mCollapsedAndHeadsUpOnDown);
@@ -3423,7 +3446,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
ipw.print("mGestureWaitForTouchSlop="); ipw.println(mGestureWaitForTouchSlop);
ipw.print("mIgnoreXTouchSlop="); ipw.println(mIgnoreXTouchSlop);
ipw.print("mExpandLatencyTracking="); ipw.println(mExpandLatencyTracking);
- ipw.print("mExpandLatencyTracking="); ipw.println(mExpandLatencyTracking);
ipw.println("gestureExclusionRect:" + calculateGestureExclusionRect());
new DumpsysTableLogger(
TAG,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 18e964462189..5b5785e36ccc 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -508,6 +508,7 @@ public class NotificationShadeWindowViewController {
MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
}
+ Log.w(TAG, "Canceling current touch event (should be very rare)");
mView.dispatchTouchEvent(event);
event.recycle();
mTouchCancelled = true;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
index 5c1dd5670d8a..941254223965 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
@@ -155,10 +155,8 @@ class NotificationsQSContainerController @Inject constructor(
largeScreenShadeHeaderActive = LargeScreenUtils.shouldUseLargeScreenShadeHeader(resources)
notificationsBottomMargin = resources.getDimensionPixelSize(
R.dimen.notification_panel_margin_bottom)
- largeScreenShadeHeaderHeight =
- resources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height)
- shadeHeaderHeight =
- resources.getDimensionPixelSize(R.dimen.qs_header_height)
+ largeScreenShadeHeaderHeight = calculateLargeShadeHeaderHeight()
+ shadeHeaderHeight = calculateShadeHeaderHeight()
panelMarginHorizontal = resources.getDimensionPixelSize(
R.dimen.notification_panel_margin_horizontal)
topMargin = if (largeScreenShadeHeaderActive) {
@@ -182,6 +180,23 @@ class NotificationsQSContainerController @Inject constructor(
}
}
+ private fun calculateLargeShadeHeaderHeight(): Int {
+ return resources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height)
+ }
+
+ private fun calculateShadeHeaderHeight(): Int {
+ val minHeight = resources.getDimensionPixelSize(R.dimen.qs_header_height)
+
+ // Following the constraints in xml/qs_header, the total needed height would be the sum of
+ // 1. privacy_container height (R.dimen.large_screen_shade_header_min_height)
+ // 2. carrier_group height (R.dimen.large_screen_shade_header_min_height)
+ // 3. date height (R.dimen.new_qs_header_non_clickable_element_height)
+ val estimatedHeight =
+ 2 * resources.getDimensionPixelSize(R.dimen.large_screen_shade_header_min_height) +
+ resources.getDimensionPixelSize(R.dimen.new_qs_header_non_clickable_element_height)
+ return estimatedHeight.coerceAtLeast(minHeight)
+ }
+
override fun setCustomizerAnimating(animating: Boolean) {
if (isQSCustomizerAnimating != animating) {
isQSCustomizerAnimating = animating
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index baac57ca44ba..e85024e3f5d1 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -1011,6 +1011,7 @@ public class QuickSettingsController implements Dumpable {
&& mPanelViewControllerLazy.get().mAnimateBack) {
mPanelViewControllerLazy.get().adjustBackAnimationScale(adjustedExpansionFraction);
}
+ mShadeExpansionStateManager.onQsExpansionFractionChanged(qsExpansionFraction);
mMediaHierarchyManager.setQsExpansion(qsExpansionFraction);
int qsPanelBottomY = calculateBottomPosition(qsExpansionFraction);
mScrimController.setQsPosition(qsExpansionFraction, qsPanelBottomY);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
index 2db47aeb9e90..0554c5855d61 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
@@ -38,6 +38,8 @@ class ShadeExpansionStateManager @Inject constructor() : ShadeStateEvents {
private val expansionListeners = CopyOnWriteArrayList<ShadeExpansionListener>()
private val fullExpansionListeners = CopyOnWriteArrayList<ShadeFullExpansionListener>()
private val qsExpansionListeners = CopyOnWriteArrayList<ShadeQsExpansionListener>()
+ private val qsExpansionFractionListeners =
+ CopyOnWriteArrayList<ShadeQsExpansionFractionListener>()
private val stateListeners = CopyOnWriteArrayList<ShadeStateListener>()
private val shadeStateEventsListeners = CopyOnWriteArrayList<ShadeStateEventsListener>()
@@ -45,6 +47,7 @@ class ShadeExpansionStateManager @Inject constructor() : ShadeStateEvents {
@FloatRange(from = 0.0, to = 1.0) private var fraction: Float = 0f
private var expanded: Boolean = false
private var qsExpanded: Boolean = false
+ private var qsExpansionFraction = 0f
private var tracking: Boolean = false
private var dragDownPxAmount: Float = 0f
@@ -82,6 +85,15 @@ class ShadeExpansionStateManager @Inject constructor() : ShadeStateEvents {
qsExpansionListeners.remove(listener)
}
+ fun addQsExpansionFractionListener(listener: ShadeQsExpansionFractionListener) {
+ qsExpansionFractionListeners.add(listener)
+ listener.onQsExpansionFractionChanged(qsExpansionFraction)
+ }
+
+ fun removeQsExpansionFractionListener(listener: ShadeQsExpansionFractionListener) {
+ qsExpansionFractionListeners.remove(listener)
+ }
+
/** Adds a listener that will be notified when the panel state has changed. */
fun addStateListener(listener: ShadeStateListener) {
stateListeners.add(listener)
@@ -175,6 +187,15 @@ class ShadeExpansionStateManager @Inject constructor() : ShadeStateEvents {
qsExpansionListeners.forEach { it.onQsExpansionChanged(qsExpanded) }
}
+ fun onQsExpansionFractionChanged(qsExpansionFraction: Float) {
+ this.qsExpansionFraction = qsExpansionFraction
+
+ debugLog("qsExpansionFraction=$qsExpansionFraction")
+ qsExpansionFractionListeners.forEach {
+ it.onQsExpansionFractionChanged(qsExpansionFraction)
+ }
+ }
+
fun onShadeExpansionFullyChanged(isExpanded: Boolean) {
this.expanded = isExpanded
diff --git a/core/java/android/service/selectiontoolbar/ISelectionToolbarRenderServiceCallback.aidl b/packages/SystemUI/src/com/android/systemui/shade/ShadeQsExpansionFractionListener.kt
index f6c47ddf1e00..c787f49e22ce 100644
--- a/core/java/android/service/selectiontoolbar/ISelectionToolbarRenderServiceCallback.aidl
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeQsExpansionFractionListener.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (c) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,15 +14,10 @@
* limitations under the License.
*/
-package android.service.selectiontoolbar;
+package com.android.systemui.shade
-import android.os.IBinder;
-
-/**
- * The interface from the SelectionToolbarRenderService to the system.
- *
- * @hide
- */
-oneway interface ISelectionToolbarRenderServiceCallback {
- void transferTouch(in IBinder source, in IBinder target);
+/** A listener interface to be notified of expansion events for the quick settings panel. */
+fun interface ShadeQsExpansionFractionListener {
+ /** Invoked whenever the quick settings expansion fraction changes */
+ fun onQsExpansionFractionChanged(qsExpansionFraction: Float)
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
index 29551188c5c7..6e7678407805 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
@@ -273,6 +273,7 @@ abstract class ShadeViewProviderModule {
tunerService: TunerService,
@Main mainHandler: Handler,
contentResolver: ContentResolver,
+ featureFlags: FeatureFlags,
batteryController: BatteryController,
): BatteryMeterViewController {
return BatteryMeterViewController(
@@ -283,6 +284,7 @@ abstract class ShadeViewProviderModule {
tunerService,
mainHandler,
contentResolver,
+ featureFlags,
batteryController,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
index 0b3ed5601c2e..87abc9208d45 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
@@ -16,9 +16,10 @@
package com.android.systemui.shade.ui.viewmodel
+import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
+import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
import com.android.systemui.scene.shared.model.SceneKey
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -33,29 +34,30 @@ class ShadeSceneViewModel
@Inject
constructor(
@Application private val applicationScope: CoroutineScope,
- private val lockscreenSceneInteractor: LockscreenSceneInteractor,
+ authenticationInteractor: AuthenticationInteractor,
+ private val bouncerInteractor: BouncerInteractor,
) {
/** The key of the scene we should switch to when swiping up. */
val upDestinationSceneKey: StateFlow<SceneKey> =
- lockscreenSceneInteractor.isDeviceLocked
- .map { isLocked -> upDestinationSceneKey(isLocked = isLocked) }
+ authenticationInteractor.isUnlocked
+ .map { isUnlocked -> upDestinationSceneKey(isUnlocked = isUnlocked) }
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
initialValue =
upDestinationSceneKey(
- isLocked = lockscreenSceneInteractor.isDeviceLocked.value,
+ isUnlocked = authenticationInteractor.isUnlocked.value,
),
)
/** Notifies that some content in the shade was clicked. */
fun onContentClicked() {
- lockscreenSceneInteractor.dismissLockscreen()
+ bouncerInteractor.showOrUnlockDevice()
}
private fun upDestinationSceneKey(
- isLocked: Boolean,
+ isUnlocked: Boolean,
): SceneKey {
- return if (isLocked) SceneKey.Lockscreen else SceneKey.Gone
+ return if (isUnlocked) SceneKey.Gone else SceneKey.Lockscreen
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index 94251ffc74c8..efd7d2ef2718 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -446,6 +446,12 @@ constructor(
session?.requestSmartspaceUpdate()
}
+ fun removeViewsFromParent(viewGroup: ViewGroup) {
+ smartspaceViews.toList().forEach {
+ viewGroup.removeView(it as View)
+ }
+ }
+
/**
* Disconnects the smartspace view from the smartspace service and cleans up any resources.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index 5c72731e71a7..e763797d9966 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -99,6 +99,7 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.Ra
import com.android.systemui.statusbar.notification.collection.notifcollection.RankingUpdatedEvent;
import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider;
import com.android.systemui.util.Assert;
+import com.android.systemui.util.NamedListenerSet;
import com.android.systemui.util.time.SystemClock;
import java.io.PrintWriter;
@@ -161,7 +162,8 @@ public class NotifCollection implements Dumpable, PipelineDumpable {
private final HashMap<String, FutureDismissal> mFutureDismissals = new HashMap<>();
@Nullable private CollectionReadyForBuildListener mBuildListener;
- private final List<NotifCollectionListener> mNotifCollectionListeners = new ArrayList<>();
+ private final NamedListenerSet<NotifCollectionListener>
+ mNotifCollectionListeners = new NamedListenerSet<>();
private final List<NotifLifetimeExtender> mLifetimeExtenders = new ArrayList<>();
private final List<NotifDismissInterceptor> mDismissInterceptors = new ArrayList<>();
@@ -236,7 +238,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable {
/** @see NotifPipeline#addCollectionListener(NotifCollectionListener) */
void addCollectionListener(NotifCollectionListener listener) {
Assert.isMainThread();
- mNotifCollectionListeners.add(listener);
+ mNotifCollectionListeners.addIfAbsent(listener);
}
/** @see NotifPipeline#removeCollectionListener(NotifCollectionListener) */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImpl.kt
index d95d593778a9..5acc50ab878f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImpl.kt
@@ -21,7 +21,6 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.util.Assert
import com.android.systemui.util.ListenerSet
-import com.android.systemui.util.isNotEmpty
import com.android.systemui.util.traceSection
import java.util.Collections.unmodifiableList
import java.util.concurrent.Executor
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index 02055237c2b3..240ae0c13ac7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -69,6 +69,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga
import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
import com.android.systemui.util.Assert;
+import com.android.systemui.util.NamedListenerSet;
import com.android.systemui.util.time.SystemClock;
import java.io.PrintWriter;
@@ -121,14 +122,14 @@ public class ShadeListBuilder implements Dumpable, PipelineDumpable {
private final List<NotifSection> mNotifSections = new ArrayList<>();
private NotifStabilityManager mNotifStabilityManager;
- private final List<OnBeforeTransformGroupsListener> mOnBeforeTransformGroupsListeners =
- new ArrayList<>();
- private final List<OnBeforeSortListener> mOnBeforeSortListeners =
- new ArrayList<>();
- private final List<OnBeforeFinalizeFilterListener> mOnBeforeFinalizeFilterListeners =
- new ArrayList<>();
- private final List<OnBeforeRenderListListener> mOnBeforeRenderListListeners =
- new ArrayList<>();
+ private final NamedListenerSet<OnBeforeTransformGroupsListener>
+ mOnBeforeTransformGroupsListeners = new NamedListenerSet<>();
+ private final NamedListenerSet<OnBeforeSortListener>
+ mOnBeforeSortListeners = new NamedListenerSet<>();
+ private final NamedListenerSet<OnBeforeFinalizeFilterListener>
+ mOnBeforeFinalizeFilterListeners = new NamedListenerSet<>();
+ private final NamedListenerSet<OnBeforeRenderListListener>
+ mOnBeforeRenderListListeners = new NamedListenerSet<>();
@Nullable private OnRenderListListener mOnRenderListListener;
private List<ListEntry> mReadOnlyNotifList = Collections.unmodifiableList(mNotifList);
@@ -184,28 +185,28 @@ public class ShadeListBuilder implements Dumpable, PipelineDumpable {
Assert.isMainThread();
mPipelineState.requireState(STATE_IDLE);
- mOnBeforeTransformGroupsListeners.add(listener);
+ mOnBeforeTransformGroupsListeners.addIfAbsent(listener);
}
void addOnBeforeSortListener(OnBeforeSortListener listener) {
Assert.isMainThread();
mPipelineState.requireState(STATE_IDLE);
- mOnBeforeSortListeners.add(listener);
+ mOnBeforeSortListeners.addIfAbsent(listener);
}
void addOnBeforeFinalizeFilterListener(OnBeforeFinalizeFilterListener listener) {
Assert.isMainThread();
mPipelineState.requireState(STATE_IDLE);
- mOnBeforeFinalizeFilterListeners.add(listener);
+ mOnBeforeFinalizeFilterListeners.addIfAbsent(listener);
}
void addOnBeforeRenderListListener(OnBeforeRenderListListener listener) {
Assert.isMainThread();
mPipelineState.requireState(STATE_IDLE);
- mOnBeforeRenderListListeners.add(listener);
+ mOnBeforeRenderListListeners.addIfAbsent(listener);
}
void addPreRenderInvalidator(Invalidator invalidator) {
@@ -496,7 +497,9 @@ public class ShadeListBuilder implements Dumpable, PipelineDumpable {
mTempSectionMembers.add(entry);
}
}
+ Trace.beginSection(section.getLabel());
section.getSectioner().onEntriesUpdated(mTempSectionMembers);
+ Trace.endSection();
mTempSectionMembers.clear();
}
Trace.endSection();
@@ -1430,33 +1433,33 @@ public class ShadeListBuilder implements Dumpable, PipelineDumpable {
private void dispatchOnBeforeTransformGroups(List<ListEntry> entries) {
Trace.beginSection("ShadeListBuilder.dispatchOnBeforeTransformGroups");
- for (int i = 0; i < mOnBeforeTransformGroupsListeners.size(); i++) {
- mOnBeforeTransformGroupsListeners.get(i).onBeforeTransformGroups(entries);
- }
+ mOnBeforeTransformGroupsListeners.forEachTraced(listener -> {
+ listener.onBeforeTransformGroups(entries);
+ });
Trace.endSection();
}
private void dispatchOnBeforeSort(List<ListEntry> entries) {
Trace.beginSection("ShadeListBuilder.dispatchOnBeforeSort");
- for (int i = 0; i < mOnBeforeSortListeners.size(); i++) {
- mOnBeforeSortListeners.get(i).onBeforeSort(entries);
- }
+ mOnBeforeSortListeners.forEachTraced(listener -> {
+ listener.onBeforeSort(entries);
+ });
Trace.endSection();
}
private void dispatchOnBeforeFinalizeFilter(List<ListEntry> entries) {
Trace.beginSection("ShadeListBuilder.dispatchOnBeforeFinalizeFilter");
- for (int i = 0; i < mOnBeforeFinalizeFilterListeners.size(); i++) {
- mOnBeforeFinalizeFilterListeners.get(i).onBeforeFinalizeFilter(entries);
- }
+ mOnBeforeFinalizeFilterListeners.forEachTraced(listener -> {
+ listener.onBeforeFinalizeFilter(entries);
+ });
Trace.endSection();
}
private void dispatchOnBeforeRenderList(List<ListEntry> entries) {
Trace.beginSection("ShadeListBuilder.dispatchOnBeforeRenderList");
- for (int i = 0; i < mOnBeforeRenderListListeners.size(); i++) {
- mOnBeforeRenderListListeners.get(i).onBeforeRenderList(entries);
- }
+ mOnBeforeRenderListListeners.forEachTraced(listener -> {
+ listener.onBeforeRenderList(entries);
+ });
Trace.endSection();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
index 6500ff7fa210..73decfc326a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
@@ -23,6 +23,7 @@ import static java.util.Objects.requireNonNull;
import android.annotation.IntDef;
import android.os.RemoteException;
+import android.os.Trace;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -342,11 +343,13 @@ public class PreparationCoordinator implements Coordinator {
private void inflateEntry(NotificationEntry entry,
NotifUiAdjustment newAdjustment,
String reason) {
+ Trace.beginSection("PrepCoord.inflateEntry");
abortInflation(entry, reason);
mInflationAdjustments.put(entry, newAdjustment);
mInflatingNotifs.add(entry);
NotifInflater.Params params = getInflaterParams(newAdjustment, reason);
mNotifInflater.inflateViews(entry, params, this::onInflationFinished);
+ Trace.endSection();
}
private void rebind(NotificationEntry entry,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt
index e20f0e50af6d..e06e2d014329 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt
@@ -22,6 +22,8 @@ import android.service.notification.NotificationListenerService.RankingMap
import android.service.notification.StatusBarNotification
import com.android.systemui.statusbar.notification.collection.NotifCollection
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.util.NamedListenerSet
+import com.android.systemui.util.traceSection
/**
* Set of classes that represent the various events that [NotifCollection] can dispatch to
@@ -30,10 +32,10 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry
* These events build up in a queue and are periodically emitted in chunks by the collection.
*/
-sealed class NotifEvent {
- fun dispatchTo(listeners: List<NotifCollectionListener>) {
- for (i in listeners.indices) {
- dispatchToListener(listeners[i])
+sealed class NotifEvent(private val traceName: String) {
+ fun dispatchTo(listeners: NamedListenerSet<NotifCollectionListener>) {
+ traceSection(traceName) {
+ listeners.forEachTraced(::dispatchToListener)
}
}
@@ -43,7 +45,7 @@ sealed class NotifEvent {
data class BindEntryEvent(
val entry: NotificationEntry,
val sbn: StatusBarNotification
-) : NotifEvent() {
+) : NotifEvent("onEntryBind") {
override fun dispatchToListener(listener: NotifCollectionListener) {
listener.onEntryBind(entry, sbn)
}
@@ -51,7 +53,7 @@ data class BindEntryEvent(
data class InitEntryEvent(
val entry: NotificationEntry
-) : NotifEvent() {
+) : NotifEvent("onEntryInit") {
override fun dispatchToListener(listener: NotifCollectionListener) {
listener.onEntryInit(entry)
}
@@ -59,7 +61,7 @@ data class InitEntryEvent(
data class EntryAddedEvent(
val entry: NotificationEntry
-) : NotifEvent() {
+) : NotifEvent("onEntryAdded") {
override fun dispatchToListener(listener: NotifCollectionListener) {
listener.onEntryAdded(entry)
}
@@ -68,7 +70,7 @@ data class EntryAddedEvent(
data class EntryUpdatedEvent(
val entry: NotificationEntry,
val fromSystem: Boolean
-) : NotifEvent() {
+) : NotifEvent(if (fromSystem) "onEntryUpdated" else "onEntryUpdated fromSystem=true") {
override fun dispatchToListener(listener: NotifCollectionListener) {
listener.onEntryUpdated(entry, fromSystem)
}
@@ -77,7 +79,7 @@ data class EntryUpdatedEvent(
data class EntryRemovedEvent(
val entry: NotificationEntry,
val reason: Int
-) : NotifEvent() {
+) : NotifEvent("onEntryRemoved ${cancellationReasonDebugString(reason)}") {
override fun dispatchToListener(listener: NotifCollectionListener) {
listener.onEntryRemoved(entry, reason)
}
@@ -85,7 +87,7 @@ data class EntryRemovedEvent(
data class CleanUpEntryEvent(
val entry: NotificationEntry
-) : NotifEvent() {
+) : NotifEvent("onEntryCleanUp") {
override fun dispatchToListener(listener: NotifCollectionListener) {
listener.onEntryCleanUp(entry)
}
@@ -93,13 +95,13 @@ data class CleanUpEntryEvent(
data class RankingUpdatedEvent(
val rankingMap: RankingMap
-) : NotifEvent() {
+) : NotifEvent("onRankingUpdate") {
override fun dispatchToListener(listener: NotifCollectionListener) {
listener.onRankingUpdate(rankingMap)
}
}
-class RankingAppliedEvent() : NotifEvent() {
+class RankingAppliedEvent : NotifEvent("onRankingApplied") {
override fun dispatchToListener(listener: NotifCollectionListener) {
listener.onRankingApplied()
}
@@ -110,7 +112,7 @@ data class ChannelChangedEvent(
val user: UserHandle,
val channel: NotificationChannel,
val modificationType: Int
-) : NotifEvent() {
+) : NotifEvent("onNotificationChannelModified") {
override fun dispatchToListener(listener: NotifCollectionListener) {
listener.onNotificationChannelModified(pkgName, user, channel, modificationType)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/DebugModeFilterProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/DebugModeFilterProvider.kt
index fd5bae151550..c873e6ad36d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/DebugModeFilterProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/DebugModeFilterProvider.kt
@@ -26,7 +26,6 @@ import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.util.Assert
import com.android.systemui.util.ListenerSet
-import com.android.systemui.util.isNotEmpty
import java.io.PrintWriter
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
index d8965418b4c4..9d953423ec28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
@@ -33,6 +33,7 @@ import com.android.systemui.statusbar.notification.InflationException
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
+import com.android.systemui.util.traceSection
import javax.inject.Inject
/**
@@ -95,7 +96,7 @@ class IconManager @Inject constructor(
* @throws InflationException Exception if required icons are not valid or specified
*/
@Throws(InflationException::class)
- fun createIcons(entry: NotificationEntry) {
+ fun createIcons(entry: NotificationEntry) = traceSection("IconManager.createIcons") {
// Construct the status bar icon view.
val sbIcon = iconBuilder.createIconView(entry)
sbIcon.scaleType = ImageView.ScaleType.CENTER_INSIDE
@@ -143,9 +144,9 @@ class IconManager @Inject constructor(
* @throws InflationException Exception if required icons are not valid or specified
*/
@Throws(InflationException::class)
- fun updateIcons(entry: NotificationEntry) {
+ fun updateIcons(entry: NotificationEntry) = traceSection("IconManager.updateIcons") {
if (!entry.icons.areIconsAvailable) {
- return
+ return@traceSection
}
entry.icons.smallIconDescriptor = null
entry.icons.peopleAvatarDescriptor = null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 5e7e4be60104..1b790fdc35c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -321,7 +321,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
protected void setBackgroundTintColor(int color) {
if (color != mCurrentBackgroundTint) {
mCurrentBackgroundTint = color;
- if (color == mNormalColor) {
+ // TODO(282173943): re-enable this tinting optimization when Resources are thread-safe
+ if (false && color == mNormalColor) {
// We don't need to tint a normal notification
color = 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index a4e8c2ece894..80f5d1939ac0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -21,12 +21,16 @@ import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENAB
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.notification.NotificationUtils.logKey;
+import android.net.Uri;
+import android.os.UserHandle;
+import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
@@ -71,6 +75,10 @@ import javax.inject.Named;
@NotificationRowScope
public class ExpandableNotificationRowController implements NotifViewController {
private static final String TAG = "NotifRowController";
+
+ static final Uri BUBBLES_SETTING_URI =
+ Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BUBBLES);
+ private static final String BUBBLES_SETTING_ENABLED_VALUE = "1";
private final ExpandableNotificationRow mView;
private final NotificationListContainer mListContainer;
private final RemoteInputViewSubcomponent.Factory mRemoteInputViewSubcomponentFactory;
@@ -104,6 +112,23 @@ public class ExpandableNotificationRowController implements NotifViewController
private final ExpandableNotificationRowDragController mDragController;
private final NotificationDismissibilityProvider mDismissibilityProvider;
private final IStatusBarService mStatusBarService;
+
+ private final NotificationSettingsController mSettingsController;
+
+ @VisibleForTesting
+ final NotificationSettingsController.Listener mSettingsListener =
+ new NotificationSettingsController.Listener() {
+ @Override
+ public void onSettingChanged(Uri setting, int userId, String value) {
+ if (BUBBLES_SETTING_URI.equals(setting)) {
+ final int viewUserId = mView.getEntry().getSbn().getUserId();
+ if (viewUserId == UserHandle.USER_ALL || viewUserId == userId) {
+ mView.getPrivateLayout().setBubblesEnabledForUser(
+ BUBBLES_SETTING_ENABLED_VALUE.equals(value));
+ }
+ }
+ }
+ };
private final ExpandableNotificationRow.ExpandableNotificationRowLogger mLoggerCallback =
new ExpandableNotificationRow.ExpandableNotificationRowLogger() {
@Override
@@ -201,6 +226,7 @@ public class ExpandableNotificationRowController implements NotifViewController
FeatureFlags featureFlags,
PeopleNotificationIdentifier peopleNotificationIdentifier,
Optional<BubblesManager> bubblesManagerOptional,
+ NotificationSettingsController settingsController,
ExpandableNotificationRowDragController dragController,
NotificationDismissibilityProvider dismissibilityProvider,
IStatusBarService statusBarService) {
@@ -229,6 +255,7 @@ public class ExpandableNotificationRowController implements NotifViewController
mFeatureFlags = featureFlags;
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
mBubblesManagerOptional = bubblesManagerOptional;
+ mSettingsController = settingsController;
mDragController = dragController;
mMetricsLogger = metricsLogger;
mChildrenContainerLogger = childrenContainerLogger;
@@ -298,12 +325,14 @@ public class ExpandableNotificationRowController implements NotifViewController
NotificationMenuRowPlugin.class, false /* Allow multiple */);
mView.setOnKeyguard(mStatusBarStateController.getState() == KEYGUARD);
mStatusBarStateController.addCallback(mStatusBarStateListener);
+ mSettingsController.addCallback(BUBBLES_SETTING_URI, mSettingsListener);
}
@Override
public void onViewDetachedFromWindow(View v) {
mPluginManager.removePluginListener(mView);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
+ mSettingsController.removeCallback(BUBBLES_SETTING_URI, mSettingsListener);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
index 6bbeebfdb431..0989df61a5e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
@@ -16,11 +16,15 @@
package com.android.systemui.statusbar.notification.row;
+import static android.graphics.PorterDuff.Mode.SRC_ATOP;
+
import android.annotation.ColorInt;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.ColorFilter;
+import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.IndentingPrintWriter;
@@ -157,10 +161,20 @@ public class FooterView extends StackScrollerDecorView {
*/
public void updateColors() {
Resources.Theme theme = mContext.getTheme();
- int textColor = getResources().getColor(R.color.notif_pill_text, theme);
- mClearAllButton.setBackground(theme.getDrawable(R.drawable.notif_footer_btn_background));
+ final @ColorInt int textColor = getResources().getColor(R.color.notif_pill_text, theme);
+ final Drawable clearAllBg = theme.getDrawable(R.drawable.notif_footer_btn_background);
+ final Drawable manageBg = theme.getDrawable(R.drawable.notif_footer_btn_background);
+ // TODO(b/282173943): Remove redundant tinting once Resources are thread-safe
+ final @ColorInt int buttonBgColor =
+ Utils.getColorAttrDefaultColor(mContext, com.android.internal.R.attr.colorSurface);
+ final ColorFilter bgColorFilter = new PorterDuffColorFilter(buttonBgColor, SRC_ATOP);
+ if (buttonBgColor != 0) {
+ clearAllBg.setColorFilter(bgColorFilter);
+ manageBg.setColorFilter(bgColorFilter);
+ }
+ mClearAllButton.setBackground(clearAllBg);
mClearAllButton.setTextColor(textColor);
- mManageButton.setBackground(theme.getDrawable(R.drawable.notif_footer_btn_background));
+ mManageButton.setBackground(manageBg);
mManageButton.setTextColor(textColor);
final @ColorInt int labelTextColor =
Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 03225730619e..065828bee746 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -41,6 +41,8 @@ import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import androidx.annotation.MainThread;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.R;
@@ -65,7 +67,6 @@ import com.android.systemui.statusbar.policy.SmartReplyStateInflaterKt;
import com.android.systemui.statusbar.policy.SmartReplyView;
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
import com.android.systemui.util.Compile;
-import com.android.systemui.wmshell.BubblesManager;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -134,6 +135,7 @@ public class NotificationContentView extends FrameLayout implements Notification
private PeopleNotificationIdentifier mPeopleIdentifier;
private RemoteInputViewSubcomponent.Factory mRemoteInputSubcomponentFactory;
private IStatusBarService mStatusBarService;
+ private boolean mBubblesEnabledForUser;
/**
* List of listeners for when content views become inactive (i.e. not the showing view).
@@ -1440,12 +1442,20 @@ public class NotificationContentView extends FrameLayout implements Notification
}
}
+ @MainThread
+ public void setBubblesEnabledForUser(boolean enabled) {
+ mBubblesEnabledForUser = enabled;
+
+ applyBubbleAction(mExpandedChild, mNotificationEntry);
+ applyBubbleAction(mHeadsUpChild, mNotificationEntry);
+ }
+
@VisibleForTesting
boolean shouldShowBubbleButton(NotificationEntry entry) {
boolean isPersonWithShortcut =
mPeopleIdentifier.getPeopleNotificationType(entry)
>= PeopleNotificationIdentifier.TYPE_FULL_PERSON;
- return BubblesManager.areBubblesEnabled(mContext, entry.getSbn().getUser())
+ return mBubblesEnabledForUser
&& isPersonWithShortcut
&& entry.getBubbleMetadata() != null;
}
@@ -2079,6 +2089,7 @@ public class NotificationContentView extends FrameLayout implements Notification
pw.print("null");
}
pw.println();
+ pw.println("mBubblesEnabledForUser: " + mBubblesEnabledForUser);
pw.print("RemoteInputViews { ");
pw.print(" visibleType: " + mVisibleType);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index 9bc03336c3b0..7134f15d4fec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -48,6 +48,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.transition.ChangeBounds;
@@ -118,6 +119,8 @@ public class NotificationConversationInfo extends LinearLayout implements
private NotificationGuts mGutsContainer;
private OnConversationSettingsClickListener mOnConversationSettingsClickListener;
+ private UserManager mUm;
+
@VisibleForTesting
boolean mSkipPost = false;
private int mActualHeight;
@@ -155,7 +158,9 @@ public class NotificationConversationInfo extends LinearLayout implements
// People Tile add request.
if (mSelectedAction == ACTION_FAVORITE && getPriority() != mSelectedAction) {
mShadeController.animateCollapseShade();
- mPeopleSpaceWidgetManager.requestPinAppWidget(mShortcutInfo, new Bundle());
+ if (mUm.isSameProfileGroup(UserHandle.USER_SYSTEM, mSbn.getNormalizedUserId())) {
+ mPeopleSpaceWidgetManager.requestPinAppWidget(mShortcutInfo, new Bundle());
+ }
}
mGutsContainer.closeControls(v, /* save= */ true);
};
@@ -188,6 +193,7 @@ public class NotificationConversationInfo extends LinearLayout implements
public void bindNotification(
ShortcutManager shortcutManager,
PackageManager pm,
+ UserManager um,
PeopleSpaceWidgetManager peopleSpaceWidgetManager,
INotificationManager iNotificationManager,
OnUserInteractionCallback onUserInteractionCallback,
@@ -211,6 +217,7 @@ public class NotificationConversationInfo extends LinearLayout implements
mEntry = entry;
mSbn = entry.getSbn();
mPm = pm;
+ mUm = um;
mAppName = mPackageName;
mOnSettingsClickListener = onSettingsClick;
mNotificationChannel = notificationChannel;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 7dbca4276fcc..6f79ea8c543b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -30,6 +30,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
@@ -112,6 +113,9 @@ public class NotificationGutsManager implements NotifGutsViewManager {
private Runnable mOpenRunnable;
private final INotificationManager mNotificationManager;
private final PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
+
+ private final UserManager mUserManager;
+
private final LauncherApps mLauncherApps;
private final ShortcutManager mShortcutManager;
private final UserContextProvider mContextTracker;
@@ -128,6 +132,7 @@ public class NotificationGutsManager implements NotifGutsViewManager {
AccessibilityManager accessibilityManager,
HighPriorityProvider highPriorityProvider,
INotificationManager notificationManager,
+ UserManager userManager,
PeopleSpaceWidgetManager peopleSpaceWidgetManager,
LauncherApps launcherApps,
ShortcutManager shortcutManager,
@@ -150,6 +155,7 @@ public class NotificationGutsManager implements NotifGutsViewManager {
mAccessibilityManager = accessibilityManager;
mHighPriorityProvider = highPriorityProvider;
mNotificationManager = notificationManager;
+ mUserManager = userManager;
mPeopleSpaceWidgetManager = peopleSpaceWidgetManager;
mLauncherApps = launcherApps;
mShortcutManager = shortcutManager;
@@ -471,6 +477,7 @@ public class NotificationGutsManager implements NotifGutsViewManager {
notificationInfoView.bindNotification(
mShortcutManager,
pmUser,
+ mUserManager,
mPeopleSpaceWidgetManager,
mNotificationManager,
mOnUserInteractionCallback,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSettingsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSettingsController.java
new file mode 100644
index 000000000000..51e4537d7348
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSettingsController.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+
+import androidx.annotation.MainThread;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.systemui.Dumpable;
+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.settings.UserTracker;
+import com.android.systemui.util.settings.SecureSettings;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import javax.inject.Inject;
+
+/**
+ * Centralized controller for listening to Secure Settings changes and informing in-process
+ * listeners, on a background thread.
+ */
+@SysUISingleton
+public class NotificationSettingsController implements Dumpable {
+
+ private final static String TAG = "NotificationSettingsController";
+ private final UserTracker mUserTracker;
+ private final UserTracker.Callback mCurrentUserTrackerCallback;
+ private final Handler mMainHandler;
+ private final Handler mBackgroundHandler;
+ private final ContentObserver mContentObserver;
+ private final SecureSettings mSecureSettings;
+ private final HashMap<Uri, ArrayList<Listener>> mListeners = new HashMap<>();
+
+ @Inject
+ public NotificationSettingsController(UserTracker userTracker,
+ @Main Handler mainHandler,
+ @Background Handler backgroundHandler,
+ SecureSettings secureSettings,
+ DumpManager dumpManager) {
+ mUserTracker = userTracker;
+ mMainHandler = mainHandler;
+ mBackgroundHandler = backgroundHandler;
+ mSecureSettings = secureSettings;
+ mContentObserver = new ContentObserver(mBackgroundHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ super.onChange(selfChange, uri);
+ synchronized (mListeners) {
+ if (mListeners.containsKey(uri)) {
+ int userId = mUserTracker.getUserId();
+ String value = getCurrentSettingValue(uri, userId);
+ for (Listener listener : mListeners.get(uri)) {
+ mMainHandler.post(() -> listener.onSettingChanged(uri, userId, value));
+ }
+ }
+ }
+ }
+ };
+
+ mCurrentUserTrackerCallback = new UserTracker.Callback() {
+ @Override
+ public void onUserChanged(int newUser, Context userContext) {
+ synchronized (mListeners) {
+ if (mListeners.size() > 0) {
+ mSecureSettings.unregisterContentObserver(mContentObserver);
+ for (Uri uri : mListeners.keySet()) {
+ mSecureSettings.registerContentObserverForUser(
+ uri, false, mContentObserver, newUser);
+ }
+ }
+ }
+ }
+ };
+ mUserTracker.addCallback(
+ mCurrentUserTrackerCallback, new HandlerExecutor(mBackgroundHandler));
+
+ dumpManager.registerNormalDumpable(TAG, this);
+ }
+
+ /**
+ * Register a callback whenever the given secure settings changes.
+ *
+ * On registration, will trigger the listener on the main thread with the current value of
+ * the setting.
+ */
+ @Main
+ public void addCallback(@NonNull Uri uri, @NonNull Listener listener) {
+ if (uri == null || listener == null) {
+ return;
+ }
+ synchronized (mListeners) {
+ ArrayList<Listener> currentListeners = mListeners.get(uri);
+ if (currentListeners == null) {
+ currentListeners = new ArrayList<>();
+ }
+ if (!currentListeners.contains(listener)) {
+ currentListeners.add(listener);
+ }
+ mListeners.put(uri, currentListeners);
+ if (currentListeners.size() == 1) {
+ mSecureSettings.registerContentObserverForUser(
+ uri, false, mContentObserver, mUserTracker.getUserId());
+ }
+ }
+ mBackgroundHandler.post(() -> {
+ int userId = mUserTracker.getUserId();
+ String value = getCurrentSettingValue(uri, userId);
+ mMainHandler.post(() -> listener.onSettingChanged(uri, userId, value));
+ });
+
+ }
+
+ public void removeCallback(Uri uri, Listener listener) {
+ synchronized (mListeners) {
+ ArrayList<Listener> currentListeners = mListeners.get(uri);
+
+ if (currentListeners != null) {
+ currentListeners.remove(listener);
+ }
+ if (currentListeners == null || currentListeners.size() == 0) {
+ mListeners.remove(uri);
+ }
+
+ if (mListeners.size() == 0) {
+ mSecureSettings.unregisterContentObserver(mContentObserver);
+ }
+ }
+ }
+
+ @Override
+ public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
+ synchronized (mListeners) {
+ pw.println("Settings Uri Listener List:");
+ for (Uri uri : mListeners.keySet()) {
+ pw.println(" Uri=" + uri);
+ for (Listener listener : mListeners.get(uri)) {
+ pw.println(" Listener=" + listener.getClass().getName());
+ }
+ }
+ }
+ }
+
+ private String getCurrentSettingValue(Uri uri, int userId) {
+ final String setting = uri == null ? null : uri.getLastPathSegment();
+ return mSecureSettings.getStringForUser(setting, userId);
+ }
+
+ /**
+ * Listener invoked whenever settings are changed.
+ */
+ public interface Listener {
+ @MainThread
+ void onSettingChanged(@NonNull Uri setting, int userId, @Nullable String value);
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
index dcd18dd7d1bf..2ccbc9f2f017 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
@@ -401,7 +401,7 @@ constructor(
isActivityIntent: Boolean,
showOverLockscreen: Boolean,
): Boolean {
- // TODO(b/184121838): Support launch animations when occluded.
+ // TODO(b/294418322): Support launch animations when occluded.
if (keyguardStateController.isOccluded) {
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
index 3a11635f75c3..c1af6df12bd1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
@@ -118,6 +118,11 @@ interface MobileConnectionRepository {
/** The service provider name for this network connection, or the default name */
val networkName: StateFlow<NetworkNameModel>
+ /**
+ * True if this type of connection is allowed while airplane mode is on, and false otherwise.
+ */
+ val isAllowedDuringAirplaneMode: StateFlow<Boolean>
+
companion object {
/** The default number of levels to use for [numberOfLevels]. */
const val DEFAULT_NUM_LEVELS = 4
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
index 6b86432b8171..17d20c297861 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
@@ -186,6 +186,8 @@ class DemoMobileConnectionRepository(
override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived("demo network"))
+ override val isAllowedDuringAirplaneMode = MutableStateFlow(false)
+
/**
* Process a new demo mobile event. Note that [resolvedNetworkType] must be passed in separately
* from the event, due to the requirement to reverse the mobile mappings lookup in the top-level
@@ -217,6 +219,8 @@ class DemoMobileConnectionRepository(
(event.activity ?: TelephonyManager.DATA_ACTIVITY_NONE).toMobileDataActivityModel()
_carrierNetworkChangeActive.value = event.carrierNetworkChange
_resolvedNetworkType.value = resolvedNetworkType
+
+ isAllowedDuringAirplaneMode.value = false
}
fun processCarrierMergedEvent(event: FakeWifiEventModel.CarrierMerged) {
@@ -240,6 +244,7 @@ class DemoMobileConnectionRepository(
_isInService.value = true
_isGsm.value = false
_carrierNetworkChangeActive.value = false
+ isAllowedDuringAirplaneMode.value = true
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt
index a609917351d9..65f486683837 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt
@@ -165,6 +165,13 @@ class CarrierMergedConnectionRepository(
override val isGsm = MutableStateFlow(false).asStateFlow()
override val carrierNetworkChangeActive = MutableStateFlow(false).asStateFlow()
+ /**
+ * Carrier merged connections happen over wifi but are displayed as a mobile triangle. Because
+ * they occur over wifi, it's possible to have a valid carrier merged connection even during
+ * airplane mode. See b/291993542.
+ */
+ override val isAllowedDuringAirplaneMode = MutableStateFlow(true).asStateFlow()
+
override val dataEnabled: StateFlow<Boolean> = wifiRepository.isWifiEnabled
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
index 8869dfe02697..8ba7d2197c14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
@@ -287,6 +287,15 @@ class FullMobileConnectionRepository(
)
.stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.networkName.value)
+ override val isAllowedDuringAirplaneMode =
+ activeRepo
+ .flatMapLatest { it.isAllowedDuringAirplaneMode }
+ .stateIn(
+ scope,
+ SharingStarted.WhileSubscribed(),
+ activeRepo.value.isAllowedDuringAirplaneMode.value,
+ )
+
class Factory
@Inject
constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
index b475183d98c6..aadc975a10de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
@@ -59,8 +59,10 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
@@ -331,6 +333,9 @@ class MobileConnectionRepositoryImpl(
.stateIn(scope, SharingStarted.WhileSubscribed(), initial)
}
+ /** Typical mobile connections aren't available during airplane mode. */
+ override val isAllowedDuringAirplaneMode = MutableStateFlow(false).asStateFlow()
+
class Factory
@Inject
constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
index d42e30c9b1b9..1a138272d67c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
@@ -111,6 +111,9 @@ interface MobileIconInteractor {
/** See [MobileIconsInteractor.isForceHidden]. */
val isForceHidden: Flow<Boolean>
+ /** See [MobileConnectionRepository.isAllowedDuringAirplaneMode]. */
+ val isAllowedDuringAirplaneMode: StateFlow<Boolean>
+
/** True when in carrier network change mode */
val carrierNetworkChangeActive: StateFlow<Boolean>
}
@@ -267,4 +270,6 @@ class MobileIconInteractorImpl(
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
override val isInService = connectionRepository.isInService
+
+ override val isAllowedDuringAirplaneMode = connectionRepository.isAllowedDuringAirplaneMode
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
index 35f4f9aa4622..fe2481595ff4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
@@ -102,9 +102,16 @@ constructor(
} else {
combine(
airplaneModeInteractor.isAirplaneMode,
+ iconInteractor.isAllowedDuringAirplaneMode,
iconInteractor.isForceHidden,
- ) { isAirplaneMode, isForceHidden ->
- !isAirplaneMode && !isForceHidden
+ ) { isAirplaneMode, isAllowedDuringAirplaneMode, isForceHidden ->
+ if (isForceHidden) {
+ false
+ } else if (isAirplaneMode) {
+ isAllowedDuringAirplaneMode
+ } else {
+ true
+ }
}
}
.distinctUntilChanged()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
index b11b4727c3c3..b29d46174bd1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
@@ -49,6 +49,9 @@ interface WifiRepository {
const val COL_NAME_IS_ENABLED = "isEnabled"
/** Column name to use for [isWifiDefault] for table logging. */
const val COL_NAME_IS_DEFAULT = "isDefault"
+
+ const val CARRIER_MERGED_INVALID_SUB_ID_REASON =
+ "Wifi network was carrier merged but had invalid sub ID"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoModeWifiDataSource.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoModeWifiDataSource.kt
index 7d2501ca0e79..ab9b516b837f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoModeWifiDataSource.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoModeWifiDataSource.kt
@@ -24,6 +24,7 @@ import com.android.systemui.demomode.DemoMode.COMMAND_NETWORK
import com.android.systemui.demomode.DemoModeController
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
@@ -56,12 +57,14 @@ constructor(
val activity = getString("activity").toActivity()
val ssid = getString("ssid")
val validated = getString("fully").toBoolean()
+ val hotspotDeviceType = getString("hotspot").toHotspotDeviceType()
return FakeWifiEventModel.Wifi(
level = level,
activity = activity,
ssid = ssid,
validated = validated,
+ hotspotDeviceType,
)
}
@@ -82,6 +85,20 @@ constructor(
else -> WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE
}
+ private fun String?.toHotspotDeviceType(): WifiNetworkModel.HotspotDeviceType {
+ return when (this) {
+ null,
+ "none" -> WifiNetworkModel.HotspotDeviceType.NONE
+ "unknown" -> WifiNetworkModel.HotspotDeviceType.UNKNOWN
+ "phone" -> WifiNetworkModel.HotspotDeviceType.PHONE
+ "tablet" -> WifiNetworkModel.HotspotDeviceType.TABLET
+ "laptop" -> WifiNetworkModel.HotspotDeviceType.LAPTOP
+ "watch" -> WifiNetworkModel.HotspotDeviceType.WATCH
+ "auto" -> WifiNetworkModel.HotspotDeviceType.AUTO
+ else -> WifiNetworkModel.HotspotDeviceType.INVALID
+ }
+ }
+
companion object {
const val DEFAULT_CARRIER_MERGED_SUB_ID = 10
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt
index a57be665f105..99b680056d7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt
@@ -97,6 +97,7 @@ constructor(
isValidated = validated ?: true,
level = level ?: 0,
ssid = ssid ?: DEMO_NET_SSID,
+ hotspotDeviceType = hotspotDeviceType,
// These fields below aren't supported in demo mode, since they aren't needed to satisfy
// the interface.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/model/FakeWifiEventModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/model/FakeWifiEventModel.kt
index f5035cbc0215..b2e843e283f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/model/FakeWifiEventModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/model/FakeWifiEventModel.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model
import android.telephony.Annotation
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
/**
* Model for demo wifi commands, ported from [NetworkControllerImpl]
@@ -29,6 +30,8 @@ sealed interface FakeWifiEventModel {
@Annotation.DataActivityType val activity: Int,
val ssid: String?,
val validated: Boolean?,
+ val hotspotDeviceType: WifiNetworkModel.HotspotDeviceType =
+ WifiNetworkModel.HotspotDeviceType.NONE,
) : FakeWifiEventModel
data class CarrierMerged(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryHelper.kt
new file mode 100644
index 000000000000..f1b98b3972e1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryHelper.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.wifi.data.repository.prod
+
+import android.net.wifi.WifiManager
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import com.android.systemui.statusbar.pipeline.shared.data.model.toWifiDataActivityModel
+import java.util.concurrent.Executor
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * Object to provide shared helper functions between [WifiRepositoryImpl] and
+ * [WifiRepositoryViaTrackerLib].
+ */
+object WifiRepositoryHelper {
+ /** Creates a flow that fetches the [DataActivityModel] from [WifiManager]. */
+ fun createActivityFlow(
+ wifiManager: WifiManager,
+ @Main mainExecutor: Executor,
+ scope: CoroutineScope,
+ tableLogBuffer: TableLogBuffer,
+ inputLogger: (String) -> Unit,
+ ): StateFlow<DataActivityModel> {
+ return conflatedCallbackFlow {
+ val callback =
+ WifiManager.TrafficStateCallback { state ->
+ inputLogger.invoke(prettyPrintActivity(state))
+ trySend(state.toWifiDataActivityModel())
+ }
+ wifiManager.registerTrafficStateCallback(mainExecutor, callback)
+ awaitClose { wifiManager.unregisterTrafficStateCallback(callback) }
+ }
+ .logDiffsForTable(
+ tableLogBuffer,
+ columnPrefix = ACTIVITY_PREFIX,
+ initialValue = ACTIVITY_DEFAULT,
+ )
+ .stateIn(
+ scope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = ACTIVITY_DEFAULT,
+ )
+ }
+
+ // TODO(b/292534484): This print should only be done in [MessagePrinter] part of the log buffer.
+ private fun prettyPrintActivity(activity: Int): String {
+ return when (activity) {
+ WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE -> "NONE"
+ WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN -> "IN"
+ WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT -> "OUT"
+ WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT -> "INOUT"
+ else -> "INVALID"
+ }
+ }
+
+ private const val ACTIVITY_PREFIX = "wifiActivity"
+ val ACTIVITY_DEFAULT = DataActivityModel(hasActivityIn = false, hasActivityOut = false)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
index 995de6d2fc61..afd15765d163 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
@@ -28,7 +28,6 @@ import android.net.NetworkCapabilities.TRANSPORT_WIFI
import android.net.NetworkRequest
import android.net.wifi.WifiInfo
import android.net.wifi.WifiManager
-import android.net.wifi.WifiManager.TrafficStateCallback
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
@@ -40,10 +39,10 @@ import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.logDiffsForTable
import com.android.systemui.statusbar.pipeline.dagger.WifiTableLog
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
-import com.android.systemui.statusbar.pipeline.shared.data.model.toWifiDataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl.Companion.getMainOrUnderlyingWifiInfo
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository.Companion.CARRIER_MERGED_INVALID_SUB_ID_REASON
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository.Companion.COL_NAME_IS_DEFAULT
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository.Companion.COL_NAME_IS_ENABLED
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryDagger
@@ -218,29 +217,15 @@ constructor(
)
override val wifiActivity: StateFlow<DataActivityModel> =
- conflatedCallbackFlow {
- val callback = TrafficStateCallback { state ->
- logger.logActivity(prettyPrintActivity(state))
- trySend(state.toWifiDataActivityModel())
- }
- wifiManager.registerTrafficStateCallback(mainExecutor, callback)
- awaitClose { wifiManager.unregisterTrafficStateCallback(callback) }
- }
- .logDiffsForTable(
- wifiTableLogBuffer,
- columnPrefix = ACTIVITY_PREFIX,
- initialValue = ACTIVITY_DEFAULT,
- )
- .stateIn(
- scope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = ACTIVITY_DEFAULT,
- )
+ WifiRepositoryHelper.createActivityFlow(
+ wifiManager,
+ mainExecutor,
+ scope,
+ wifiTableLogBuffer,
+ logger::logActivity,
+ )
companion object {
- private const val ACTIVITY_PREFIX = "wifiActivity"
-
- val ACTIVITY_DEFAULT = DataActivityModel(hasActivityIn = false, hasActivityOut = false)
// Start out with no known wifi network.
// Note: [WifiStatusTracker] (the old implementation of connectivity logic) does do an
// initial fetch to get a starting wifi network. But, it uses a deprecated API
@@ -277,6 +262,8 @@ constructor(
isValidated = networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED),
level = wifiManager.calculateSignalLevel(wifiInfo.rssi),
wifiInfo.ssid,
+ // This repository doesn't support any hotspot information.
+ WifiNetworkModel.HotspotDeviceType.NONE,
wifiInfo.isPasspointAp,
wifiInfo.isOsuAp,
wifiInfo.passpointProviderFriendlyName
@@ -284,16 +271,6 @@ constructor(
}
}
- private fun prettyPrintActivity(activity: Int): String {
- return when (activity) {
- TrafficStateCallback.DATA_ACTIVITY_NONE -> "NONE"
- TrafficStateCallback.DATA_ACTIVITY_IN -> "IN"
- TrafficStateCallback.DATA_ACTIVITY_OUT -> "OUT"
- TrafficStateCallback.DATA_ACTIVITY_INOUT -> "INOUT"
- else -> "INVALID"
- }
- }
-
private val WIFI_NETWORK_CALLBACK_REQUEST: NetworkRequest =
NetworkRequest.Builder()
.clearCapabilities()
@@ -301,9 +278,6 @@ constructor(
.addTransportType(TRANSPORT_WIFI)
.addTransportType(TRANSPORT_CELLULAR)
.build()
-
- private const val CARRIER_MERGED_INVALID_SUB_ID_REASON =
- "Wifi network was carrier merged but had invalid sub ID"
}
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLib.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLib.kt
index 127136789ba6..175563bb0764 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLib.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLib.kt
@@ -17,12 +17,15 @@
package com.android.systemui.statusbar.pipeline.wifi.data.repository.prod
import android.net.wifi.WifiManager
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.table.TableLogBuffer
@@ -31,20 +34,25 @@ import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
import com.android.systemui.statusbar.pipeline.dagger.WifiTrackerLibInputLog
import com.android.systemui.statusbar.pipeline.dagger.WifiTrackerLibTableLog
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository.Companion.CARRIER_MERGED_INVALID_SUB_ID_REASON
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository.Companion.COL_NAME_IS_DEFAULT
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository.Companion.COL_NAME_IS_ENABLED
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryViaTrackerLibDagger
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.WIFI_STATE_DEFAULT
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel.Inactive.toHotspotDeviceType
+import com.android.wifitrackerlib.HotspotNetworkEntry
import com.android.wifitrackerlib.MergedCarrierEntry
import com.android.wifitrackerlib.WifiEntry
+import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MAX
+import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MIN
+import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_UNREACHABLE
import com.android.wifitrackerlib.WifiPickerTracker
import java.util.concurrent.Executor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.callbackFlow
@@ -62,6 +70,7 @@ import kotlinx.coroutines.flow.stateIn
class WifiRepositoryViaTrackerLib
@Inject
constructor(
+ featureFlags: FeatureFlags,
@Application private val scope: CoroutineScope,
@Main private val mainExecutor: Executor,
private val wifiPickerTrackerFactory: WifiPickerTrackerFactory,
@@ -75,6 +84,8 @@ constructor(
mainExecutor.execute { it.currentState = Lifecycle.State.CREATED }
}
+ private val isInstantTetherEnabled = featureFlags.isEnabled(Flags.INSTANT_TETHER)
+
private var wifiPickerTracker: WifiPickerTracker? = null
private val wifiPickerTrackerInfo: StateFlow<WifiPickerTrackerInfo> = run {
@@ -128,19 +139,21 @@ constructor(
}
}
- // TODO(b/292591403): [WifiPickerTrackerFactory] currently scans to see all
- // available wifi networks every 10s. Because SysUI only needs to display the
- // **connected** network, we don't need scans to be running. We should disable these
- // scans (ideal) or at least run them very infrequently.
- wifiPickerTracker = wifiPickerTrackerFactory.create(lifecycle, callback)
+ wifiPickerTracker =
+ wifiPickerTrackerFactory.create(lifecycle, callback).apply {
+ // By default, [WifiPickerTracker] will scan to see all available wifi
+ // networks in the area. Because SysUI only needs to display the
+ // **connected** network, we don't need scans to be running (and in fact,
+ // running scans is costly and should be avoided whenever possible).
+ this?.disableScanning()
+ }
// The lifecycle must be STARTED in order for the callback to receive events.
mainExecutor.execute { lifecycle.currentState = Lifecycle.State.STARTED }
awaitClose {
mainExecutor.execute { lifecycle.currentState = Lifecycle.State.CREATED }
}
}
- // TODO(b/292534484): Update to Eagerly once scans are disabled. (Here and other flows)
- .stateIn(scope, SharingStarted.WhileSubscribed(), current)
+ .stateIn(scope, SharingStarted.Eagerly, current)
}
override val isWifiEnabled: StateFlow<Boolean> =
@@ -153,7 +166,7 @@ constructor(
columnName = COL_NAME_IS_ENABLED,
initialValue = false,
)
- .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+ .stateIn(scope, SharingStarted.Eagerly, false)
override val wifiNetwork: StateFlow<WifiNetworkModel> =
wifiPickerTrackerInfo
@@ -164,7 +177,7 @@ constructor(
columnPrefix = "",
initialValue = WIFI_NETWORK_DEFAULT,
)
- .stateIn(scope, SharingStarted.WhileSubscribed(), WIFI_NETWORK_DEFAULT)
+ .stateIn(scope, SharingStarted.Eagerly, WIFI_NETWORK_DEFAULT)
/** Converts WifiTrackerLib's [WifiEntry] into our internal model. */
private fun WifiEntry.toWifiNetworkModel(): WifiNetworkModel {
@@ -172,30 +185,58 @@ constructor(
return WIFI_NETWORK_DEFAULT
}
return if (this is MergedCarrierEntry) {
+ this.convertCarrierMergedToModel()
+ } else {
+ this.convertNormalToModel()
+ }
+ }
+
+ private fun MergedCarrierEntry.convertCarrierMergedToModel(): WifiNetworkModel {
+ return if (this.subscriptionId == INVALID_SUBSCRIPTION_ID) {
+ WifiNetworkModel.Invalid(CARRIER_MERGED_INVALID_SUB_ID_REASON)
+ } else {
WifiNetworkModel.CarrierMerged(
networkId = NETWORK_ID,
- // TODO(b/292534484): Fetch the real subscription ID from [MergedCarrierEntry].
- subscriptionId = TEMP_SUB_ID,
+ subscriptionId = this.subscriptionId,
level = this.level,
// WifiManager APIs to calculate the signal level start from 0, so
// maxSignalLevel + 1 represents the total level buckets count.
numberOfLevels = wifiManager.maxSignalLevel + 1,
)
- } else {
- WifiNetworkModel.Active(
- networkId = NETWORK_ID,
- isValidated = this.hasInternetAccess(),
- level = this.level,
- ssid = this.ssid,
- // TODO(b/292534484): Fetch the real values from [WifiEntry] (#getTitle might be
- // appropriate).
- isPasspointAccessPoint = false,
- isOnlineSignUpForPasspointAccessPoint = false,
- passpointProviderFriendlyName = null,
- )
}
}
+ private fun WifiEntry.convertNormalToModel(): WifiNetworkModel {
+ if (this.level == WIFI_LEVEL_UNREACHABLE || this.level !in WIFI_LEVEL_MIN..WIFI_LEVEL_MAX) {
+ // If our level means the network is unreachable or the level is otherwise invalid, we
+ // don't have an active network.
+ return WifiNetworkModel.Inactive
+ }
+
+ val hotspotDeviceType =
+ if (isInstantTetherEnabled && this is HotspotNetworkEntry) {
+ this.deviceType.toHotspotDeviceType()
+ } else {
+ WifiNetworkModel.HotspotDeviceType.NONE
+ }
+
+ return WifiNetworkModel.Active(
+ networkId = NETWORK_ID,
+ isValidated = this.hasInternetAccess(),
+ level = this.level,
+ ssid = this.title,
+ hotspotDeviceType = hotspotDeviceType,
+ // With WifiTrackerLib, [WifiEntry.title] will appropriately fetch the SSID for
+ // typical wifi networks *and* passpoint/OSU APs. So, the AP-specific values can
+ // always be false/null in this repository.
+ // TODO(b/292534484): Remove these fields from the wifi network model once this
+ // repository is fully enabled.
+ isPasspointAccessPoint = false,
+ isOnlineSignUpForPasspointAccessPoint = false,
+ passpointProviderFriendlyName = null,
+ )
+ }
+
override val isWifiDefault: StateFlow<Boolean> =
wifiPickerTrackerInfo
.map { it.isDefault }
@@ -206,12 +247,16 @@ constructor(
columnName = COL_NAME_IS_DEFAULT,
initialValue = false,
)
- .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+ .stateIn(scope, SharingStarted.Eagerly, false)
- // TODO(b/292534484): Re-use WifiRepositoryImpl code to implement wifi activity since
- // WifiTrackerLib doesn't expose activity details.
override val wifiActivity: StateFlow<DataActivityModel> =
- MutableStateFlow(DataActivityModel(false, false))
+ WifiRepositoryHelper.createActivityFlow(
+ wifiManager,
+ mainExecutor,
+ scope,
+ wifiTrackerLibTableLogBuffer,
+ this::logActivity,
+ )
private fun logOnWifiEntriesChanged(connectedEntry: WifiEntry?) {
inputLogger.log(
@@ -231,6 +276,10 @@ constructor(
)
}
+ private fun logActivity(activity: String) {
+ inputLogger.log(TAG, LogLevel.DEBUG, { str1 = activity }, { "onActivityChanged: $str1" })
+ }
+
/**
* Data class storing all the information fetched from [WifiPickerTracker].
*
@@ -249,6 +298,7 @@ constructor(
class Factory
@Inject
constructor(
+ private val featureFlags: FeatureFlags,
@Application private val scope: CoroutineScope,
@Main private val mainExecutor: Executor,
private val wifiPickerTrackerFactory: WifiPickerTrackerFactory,
@@ -257,6 +307,7 @@ constructor(
) {
fun create(wifiManager: WifiManager): WifiRepositoryViaTrackerLib {
return WifiRepositoryViaTrackerLib(
+ featureFlags,
scope,
mainExecutor,
wifiPickerTrackerFactory,
@@ -283,13 +334,5 @@ constructor(
* to [WifiRepositoryViaTrackerLib].
*/
private const val NETWORK_ID = -1
-
- /**
- * A temporary subscription ID until WifiTrackerLib exposes a method to fetch the
- * subscription ID.
- *
- * Use -2 because [SubscriptionManager.INVALID_SUBSCRIPTION_ID] is -1.
- */
- private const val TEMP_SUB_ID = -2
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModel.kt
index 4b33c88cea30..7078a2e1728c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModel.kt
@@ -17,11 +17,13 @@
package com.android.systemui.statusbar.pipeline.wifi.shared.model
import android.net.wifi.WifiManager.UNKNOWN_SSID
+import android.net.wifi.sharedconnectivity.app.NetworkProviderInfo
import android.telephony.SubscriptionManager
import androidx.annotation.VisibleForTesting
import com.android.systemui.log.table.Diffable
import com.android.systemui.log.table.TableRowLogger
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.wifitrackerlib.HotspotNetworkEntry.DeviceType
/** Provides information about the current wifi network. */
sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
@@ -52,6 +54,7 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
row.logChange(COL_LEVEL, LEVEL_DEFAULT)
row.logChange(COL_NUM_LEVELS, NUM_LEVELS_DEFAULT)
row.logChange(COL_SSID, null)
+ row.logChange(COL_HOTSPOT, null)
row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
row.logChange(COL_ONLINE_SIGN_UP, false)
row.logChange(COL_PASSPOINT_NAME, null)
@@ -83,6 +86,7 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
row.logChange(COL_LEVEL, LEVEL_DEFAULT)
row.logChange(COL_NUM_LEVELS, NUM_LEVELS_DEFAULT)
row.logChange(COL_SSID, null)
+ row.logChange(COL_HOTSPOT, null)
row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
row.logChange(COL_ONLINE_SIGN_UP, false)
row.logChange(COL_PASSPOINT_NAME, null)
@@ -110,6 +114,7 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
row.logChange(COL_LEVEL, LEVEL_DEFAULT)
row.logChange(COL_NUM_LEVELS, NUM_LEVELS_DEFAULT)
row.logChange(COL_SSID, null)
+ row.logChange(COL_HOTSPOT, null)
row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
row.logChange(COL_ONLINE_SIGN_UP, false)
row.logChange(COL_PASSPOINT_NAME, null)
@@ -184,6 +189,7 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
row.logChange(COL_LEVEL, level)
row.logChange(COL_NUM_LEVELS, numberOfLevels)
row.logChange(COL_SSID, null)
+ row.logChange(COL_HOTSPOT, null)
row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
row.logChange(COL_ONLINE_SIGN_UP, false)
row.logChange(COL_PASSPOINT_NAME, null)
@@ -209,6 +215,12 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
/** See [android.net.wifi.WifiInfo.ssid]. */
val ssid: String? = null,
+ /**
+ * The type of device providing a hotspot connection, or [HotspotDeviceType.NONE] if this
+ * isn't a hotspot connection.
+ */
+ val hotspotDeviceType: HotspotDeviceType = WifiNetworkModel.HotspotDeviceType.NONE,
+
/** See [android.net.wifi.WifiInfo.isPasspointAp]. */
val isPasspointAccessPoint: Boolean = false,
@@ -247,6 +259,9 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
if (prevVal.ssid != ssid) {
row.logChange(COL_SSID, ssid)
}
+ if (prevVal.hotspotDeviceType != hotspotDeviceType) {
+ row.logChange(COL_HOTSPOT, hotspotDeviceType.name)
+ }
// TODO(b/238425913): The passpoint-related values are frequently never used, so it
// would be great to not log them when they're not used.
@@ -272,6 +287,7 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
row.logChange(COL_LEVEL, level)
row.logChange(COL_NUM_LEVELS, null)
row.logChange(COL_SSID, ssid)
+ row.logChange(COL_HOTSPOT, hotspotDeviceType.name)
row.logChange(COL_PASSPOINT_ACCESS_POINT, isPasspointAccessPoint)
row.logChange(COL_ONLINE_SIGN_UP, isOnlineSignUpForPasspointAccessPoint)
row.logChange(COL_PASSPOINT_NAME, passpointProviderFriendlyName)
@@ -298,13 +314,51 @@ sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
}
companion object {
+ // TODO(b/292534484): Use [com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MAX] instead
+ // once the migration to WifiTrackerLib is complete.
@VisibleForTesting internal const val MAX_VALID_LEVEL = 4
}
}
companion object {
+ // TODO(b/292534484): Use [com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MIN] instead
+ // once the migration to WifiTrackerLib is complete.
@VisibleForTesting internal const val MIN_VALID_LEVEL = 0
}
+
+ /**
+ * Enum for the type of device providing the hotspot connection, or [NONE] if this connection
+ * isn't a hotspot.
+ */
+ enum class HotspotDeviceType {
+ /* This wifi connection isn't a hotspot. */
+ NONE,
+ /** The device type for this hotspot is unknown. */
+ UNKNOWN,
+ PHONE,
+ TABLET,
+ LAPTOP,
+ WATCH,
+ AUTO,
+ /** The device type sent for this hotspot is invalid to SysUI. */
+ INVALID,
+ }
+
+ /**
+ * Converts a device type from [com.android.wifitrackerlib.HotspotNetworkEntry.deviceType] to
+ * our internal representation.
+ */
+ fun @receiver:DeviceType Int.toHotspotDeviceType(): HotspotDeviceType {
+ return when (this) {
+ NetworkProviderInfo.DEVICE_TYPE_UNKNOWN -> HotspotDeviceType.UNKNOWN
+ NetworkProviderInfo.DEVICE_TYPE_PHONE -> HotspotDeviceType.PHONE
+ NetworkProviderInfo.DEVICE_TYPE_TABLET -> HotspotDeviceType.TABLET
+ NetworkProviderInfo.DEVICE_TYPE_LAPTOP -> HotspotDeviceType.LAPTOP
+ NetworkProviderInfo.DEVICE_TYPE_WATCH -> HotspotDeviceType.WATCH
+ NetworkProviderInfo.DEVICE_TYPE_AUTO -> HotspotDeviceType.AUTO
+ else -> HotspotDeviceType.INVALID
+ }
+ }
}
const val TYPE_CARRIER_MERGED = "CarrierMerged"
@@ -319,6 +373,7 @@ const val COL_VALIDATED = "isValidated"
const val COL_LEVEL = "level"
const val COL_NUM_LEVELS = "maxLevel"
const val COL_SSID = "ssid"
+const val COL_HOTSPOT = "hotspot"
const val COL_PASSPOINT_ACCESS_POINT = "isPasspointAccessPoint"
const val COL_ONLINE_SIGN_UP = "isOnlineSignUpForPasspointAccessPoint"
const val COL_PASSPOINT_NAME = "passpointProviderFriendlyName"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index 7df083afcd19..37eda6490ec2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -162,6 +162,9 @@ public interface BatteryController extends DemoMode,
default void onIsBatteryDefenderChanged(boolean isBatteryDefender) {
}
+ default void onIsIncompatibleChargingChanged(boolean isIncompatibleCharging) {
+ }
+
@Override
default void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
pw.println(this);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index d5d8f4d7598e..4b515115dd77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -29,6 +29,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.hardware.usb.UsbManager;
import android.os.BatteryManager;
import android.os.Bundle;
import android.os.Handler;
@@ -42,6 +43,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.settingslib.Utils;
import com.android.settingslib.fuelgauge.BatterySaverUtils;
import com.android.settingslib.fuelgauge.Estimate;
import com.android.settingslib.utils.PowerUtil;
@@ -97,6 +99,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
private boolean mAodPowerSave;
private boolean mWirelessCharging;
private boolean mIsBatteryDefender = false;
+ private boolean mIsIncompatibleCharging = false;
private boolean mTestMode = false;
@VisibleForTesting
boolean mHasReceivedBattery = false;
@@ -136,6 +139,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
filter.addAction(ACTION_LEVEL_TEST);
+ filter.addAction(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED);
mBroadcastDispatcher.registerReceiver(this, filter);
}
@@ -169,6 +173,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
ipw.print("mCharging="); ipw.println(mCharging);
ipw.print("mCharged="); ipw.println(mCharged);
ipw.print("mIsBatteryDefender="); ipw.println(mIsBatteryDefender);
+ ipw.print("mIsIncompatibleCharging="); ipw.println(mIsIncompatibleCharging);
ipw.print("mPowerSave="); ipw.println(mPowerSave);
ipw.print("mStateUnknown="); ipw.println(mStateUnknown);
ipw.println("Callbacks:------------------");
@@ -214,6 +219,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
cb.onBatteryUnknownStateChanged(mStateUnknown);
cb.onWirelessChargingChanged(mWirelessCharging);
cb.onIsBatteryDefenderChanged(mIsBatteryDefender);
+ cb.onIsIncompatibleChargingChanged(mIsIncompatibleCharging);
}
@Override
@@ -229,7 +235,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
if (mTestMode && !intent.getBooleanExtra("testmode", false)) return;
mHasReceivedBattery = true;
- mLevel = (int)(100f
+ mLevel = (int) (100f
* intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
/ intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));
mPluggedChargingSource = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
@@ -262,6 +268,12 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
fireBatteryLevelChanged();
} else if (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)) {
updatePowerSave();
+ } else if (action.equals(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED)) {
+ boolean isIncompatibleCharging = Utils.containsIncompatibleChargers(mContext, TAG);
+ if (isIncompatibleCharging != mIsIncompatibleCharging) {
+ mIsIncompatibleCharging = isIncompatibleCharging;
+ fireIsIncompatibleChargingChanged();
+ }
} else if (action.equals(ACTION_LEVEL_TEST)) {
mTestMode = true;
mMainHandler.post(new Runnable() {
@@ -270,6 +282,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
int mSavedLevel = mLevel;
boolean mSavedPluggedIn = mPluggedIn;
Intent mTestIntent = new Intent(Intent.ACTION_BATTERY_CHANGED);
+
@Override
public void run() {
if (mCurrentLevel < 0) {
@@ -333,6 +346,13 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
return mIsBatteryDefender;
}
+ /**
+ * Returns whether the charging adapter is incompatible.
+ */
+ public boolean isIncompatibleCharging() {
+ return mIsIncompatibleCharging;
+ }
+
@Override
public void getEstimatedTimeRemainingString(EstimateFetchCompletion completion) {
// Need to fetch or refresh the estimate, but it may involve binder calls so offload the
@@ -453,6 +473,15 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
}
}
+ private void fireIsIncompatibleChargingChanged() {
+ synchronized (mChangeCallbacks) {
+ final int n = mChangeCallbacks.size();
+ for (int i = 0; i < n; i++) {
+ mChangeCallbacks.get(i).onIsIncompatibleChargingChanged(mIsIncompatibleCharging);
+ }
+ }
+ }
+
@Override
public void dispatchDemoCommand(String command, Bundle args) {
if (!mDemoModeController.isInDemoMode()) {
@@ -464,6 +493,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
String powerSave = args.getString("powersave");
String present = args.getString("present");
String defender = args.getString("defender");
+ String incompatible = args.getString("incompatible");
if (level != null) {
mLevel = Math.min(Math.max(Integer.parseInt(level), 0), 100);
}
@@ -482,6 +512,10 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
mIsBatteryDefender = defender.equals("true");
fireIsBatteryDefenderChanged();
}
+ if (incompatible != null) {
+ mIsIncompatibleCharging = incompatible.equals("true");
+ fireIsIncompatibleChargingChanged();
+ }
fireBatteryLevelChanged();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index f8c36dcc90a1..518a9b3f61ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -55,7 +55,6 @@ import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.DeviceConfigProxy;
-import com.android.systemui.util.Utils;
import com.android.systemui.util.settings.SecureSettings;
import java.util.ArrayList;
@@ -362,7 +361,8 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
private static final int MSG_ADD_CALLBACK = 3;
private static final int MSG_REMOVE_CALLBACK = 4;
- private ArrayList<LocationChangeCallback> mSettingsChangeCallbacks = new ArrayList<>();
+ private final ArrayList<LocationChangeCallback> mSettingsChangeCallbacks =
+ new ArrayList<>();
H(Looper looper) {
super(looper);
@@ -388,14 +388,23 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
}
private void locationActiveChanged() {
- Utils.safeForeach(mSettingsChangeCallbacks,
- cb -> cb.onLocationActiveChanged(mAreActiveLocationRequests));
+ synchronized (mSettingsChangeCallbacks) {
+ final int n = mSettingsChangeCallbacks.size();
+ for (int i = 0; i < n; i++) {
+ mSettingsChangeCallbacks.get(i)
+ .onLocationActiveChanged(mAreActiveLocationRequests);
+ }
+ }
}
private void locationSettingsChanged() {
boolean isEnabled = isLocationEnabled();
- Utils.safeForeach(mSettingsChangeCallbacks,
- cb -> cb.onLocationSettingsChanged(isEnabled));
+ synchronized (mSettingsChangeCallbacks) {
+ final int n = mSettingsChangeCallbacks.size();
+ for (int i = 0; i < n; i++) {
+ mSettingsChangeCallbacks.get(i).onLocationSettingsChanged(isEnabled);
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateView.kt
index ae9d9ee445f2..cd1dcd585ed9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateView.kt
@@ -64,7 +64,7 @@ class VariableDateView(context: Context, attrs: AttributeSet) : TextView(context
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val availableWidth = MeasureSpec.getSize(widthMeasureSpec) - paddingStart - paddingEnd
if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED && !freezeSwitching) {
- onMeasureListener?.onMeasureAction(availableWidth)
+ onMeasureListener?.onMeasureAction(availableWidth, widthMeasureSpec)
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}
@@ -74,6 +74,6 @@ class VariableDateView(context: Context, attrs: AttributeSet) : TextView(context
}
interface OnMeasureListener {
- fun onMeasureAction(availableWidth: Int)
+ fun onMeasureAction(availableWidth: Int, widthMeasureSpec: Int)
}
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateViewController.kt
index f040d0a0efcf..4a31b8687069 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateViewController.kt
@@ -28,9 +28,11 @@ import android.os.HandlerExecutor
import android.os.UserHandle
import android.text.TextUtils
import android.util.Log
+import android.view.View.MeasureSpec
import androidx.annotation.VisibleForTesting
import com.android.systemui.Dependency
import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.shade.ShadeExpansionStateManager
import com.android.systemui.util.ViewController
import com.android.systemui.util.time.SystemClock
import java.text.FieldPosition
@@ -80,6 +82,7 @@ private const val TAG = "VariableDateViewController"
class VariableDateViewController(
private val systemClock: SystemClock,
private val broadcastDispatcher: BroadcastDispatcher,
+ private val shadeExpansionStateManager: ShadeExpansionStateManager,
private val timeTickHandler: Handler,
view: VariableDateView
) : ViewController<VariableDateView>(view) {
@@ -94,6 +97,7 @@ class VariableDateViewController(
post(::updateClock)
}
}
+ private var isQsExpanded = false
private var lastWidth = Integer.MAX_VALUE
private var lastText = ""
private var currentTime = Date()
@@ -131,7 +135,11 @@ class VariableDateViewController(
}
private val onMeasureListener = object : VariableDateView.OnMeasureListener {
- override fun onMeasureAction(availableWidth: Int) {
+ override fun onMeasureAction(availableWidth: Int, widthMeasureSpec: Int) {
+ if (!isQsExpanded && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) {
+ // ignore measured width from AT_MOST passes when in QQS (b/289489856)
+ return
+ }
if (availableWidth != lastWidth) {
// maybeChangeFormat will post if the pattern needs to change.
maybeChangeFormat(availableWidth)
@@ -140,6 +148,15 @@ class VariableDateViewController(
}
}
+ private fun onQsExpansionFractionChanged(qsExpansionFraction: Float) {
+ val newIsQsExpanded = qsExpansionFraction > 0.5
+ if (newIsQsExpanded != isQsExpanded) {
+ isQsExpanded = newIsQsExpanded
+ // manually trigger a measure pass midway through the transition from QS to QQS
+ post { mView.measure(0, 0) }
+ }
+ }
+
override fun onViewAttached() {
val filter = IntentFilter().apply {
addAction(Intent.ACTION_TIME_TICK)
@@ -151,6 +168,7 @@ class VariableDateViewController(
broadcastDispatcher.registerReceiver(intentReceiver, filter,
HandlerExecutor(timeTickHandler), UserHandle.SYSTEM)
+ shadeExpansionStateManager.addQsExpansionFractionListener(::onQsExpansionFractionChanged)
post(::updateClock)
mView.onAttach(onMeasureListener)
}
@@ -158,6 +176,7 @@ class VariableDateViewController(
override fun onViewDetached() {
dateFormat = null
mView.onAttach(null)
+ shadeExpansionStateManager.removeQsExpansionFractionListener(::onQsExpansionFractionChanged)
broadcastDispatcher.unregisterReceiver(intentReceiver)
}
@@ -211,12 +230,14 @@ class VariableDateViewController(
class Factory @Inject constructor(
private val systemClock: SystemClock,
private val broadcastDispatcher: BroadcastDispatcher,
+ private val shadeExpansionStateManager: ShadeExpansionStateManager,
@Named(Dependency.TIME_TICK_HANDLER_NAME) private val handler: Handler
) {
fun create(view: VariableDateView): VariableDateViewController {
return VariableDateViewController(
systemClock,
broadcastDispatcher,
+ shadeExpansionStateManager,
handler,
view
)
diff --git a/packages/SystemUI/src/com/android/systemui/util/IListenerSet.kt b/packages/SystemUI/src/com/android/systemui/util/IListenerSet.kt
new file mode 100644
index 000000000000..b0230b8eb0dd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/IListenerSet.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util
+
+/**
+ * A collection of listeners, observers, callbacks, etc.
+ *
+ * This container is optimized for infrequent mutation and frequent iteration, with thread safety
+ * and reentrant-safety guarantees as well. Specifically, to ensure that
+ * [ConcurrentModificationException] is never thrown, this iterator will not reflect changes made to
+ * the set after the iterator is constructed.
+ */
+interface IListenerSet<E : Any> : Set<E> {
+ /**
+ * A thread-safe, reentrant-safe method to add a listener. Does nothing if the listener is
+ * already in the set.
+ */
+ fun addIfAbsent(element: E): Boolean
+
+ /** A thread-safe, reentrant-safe method to remove a listener. */
+ fun remove(element: E): Boolean
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/ListenerSet.kt b/packages/SystemUI/src/com/android/systemui/util/ListenerSet.kt
index a47e61441c4c..f8e0b3dfe6d5 100644
--- a/packages/SystemUI/src/com/android/systemui/util/ListenerSet.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/ListenerSet.kt
@@ -29,20 +29,12 @@ import java.util.concurrent.CopyOnWriteArrayList
class ListenerSet<E : Any>
/** Private constructor takes the internal list so that we can use auto-delegation */
private constructor(private val listeners: CopyOnWriteArrayList<E>) :
- Collection<E> by listeners, Set<E> {
+ Collection<E> by listeners, IListenerSet<E> {
/** Create a new instance */
constructor() : this(CopyOnWriteArrayList())
- /**
- * A thread-safe, reentrant-safe method to add a listener. Does nothing if the listener is
- * already in the set.
- */
- fun addIfAbsent(element: E): Boolean = listeners.addIfAbsent(element)
+ override fun addIfAbsent(element: E): Boolean = listeners.addIfAbsent(element)
- /** A thread-safe, reentrant-safe method to remove a listener. */
- fun remove(element: E): Boolean = listeners.remove(element)
+ override fun remove(element: E): Boolean = listeners.remove(element)
}
-
-/** Extension to match Collection which is implemented to only be (easily) accessible in kotlin */
-fun <T : Any> ListenerSet<T>.isNotEmpty(): Boolean = !isEmpty()
diff --git a/packages/SystemUI/src/com/android/systemui/util/NamedListenerSet.kt b/packages/SystemUI/src/com/android/systemui/util/NamedListenerSet.kt
new file mode 100644
index 000000000000..c90b57ed449f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/NamedListenerSet.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util
+
+import java.util.concurrent.CopyOnWriteArrayList
+import java.util.function.Consumer
+
+/**
+ * A collection of listeners, observers, callbacks, etc.
+ *
+ * This container is optimized for infrequent mutation and frequent iteration, with thread safety
+ * and reentrant-safety guarantees as well. Specifically, to ensure that
+ * [ConcurrentModificationException] is never thrown, this iterator will not reflect changes made to
+ * the set after the iterator is constructed.
+ *
+ * This class provides all the abilities of [ListenerSet], except that each listener has a name
+ * calculated at runtime which can be used for time-efficient tracing of listener invocations.
+ */
+class NamedListenerSet<E : Any>(
+ private val getName: (E) -> String = { it.javaClass.name },
+) : IListenerSet<E> {
+ private val listeners = CopyOnWriteArrayList<NamedListener>()
+
+ override val size: Int
+ get() = listeners.size
+
+ override fun isEmpty() = listeners.isEmpty()
+
+ override fun iterator(): Iterator<E> = iterator {
+ listeners.iterator().forEach { yield(it.listener) }
+ }
+
+ override fun containsAll(elements: Collection<E>) =
+ listeners.count { it.listener in elements } == elements.size
+
+ override fun contains(element: E) = listeners.firstOrNull { it.listener == element } != null
+
+ override fun addIfAbsent(element: E): Boolean = listeners.addIfAbsent(NamedListener(element))
+
+ override fun remove(element: E): Boolean = listeners.removeIf { it.listener == element }
+
+ /** A wrapper for the listener with an associated name. */
+ inner class NamedListener(val listener: E) {
+ val name: String = getName(listener)
+
+ override fun hashCode(): Int {
+ return listener.hashCode()
+ }
+
+ override fun equals(other: Any?): Boolean =
+ when {
+ other === null -> false
+ other === this -> true
+ other !is NamedListenerSet<*>.NamedListener -> false
+ listener == other.listener -> true
+ else -> false
+ }
+ }
+
+ /** Iterate the listeners in the set, providing the name for each one as well. */
+ inline fun forEachNamed(block: (String, E) -> Unit) =
+ namedIterator().forEach { element -> block(element.name, element.listener) }
+
+ /**
+ * Iterate the listeners in the set, wrapping each call to the block with [traceSection] using
+ * the listener name.
+ */
+ inline fun forEachTraced(block: (E) -> Unit) = forEachNamed { name, listener ->
+ traceSection(name) { block(listener) }
+ }
+
+ /**
+ * Iterate the listeners in the set, wrapping each call to the block with [traceSection] using
+ * the listener name.
+ */
+ fun forEachTraced(consumer: Consumer<E>) = forEachNamed { name, listener ->
+ traceSection(name) { consumer.accept(listener) }
+ }
+
+ /** Iterate over the [NamedListener]s currently in the set. */
+ fun namedIterator(): Iterator<NamedListener> = listeners.iterator()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index c2727fc32465..e0daa0706b86 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -37,6 +37,10 @@ public class Utils {
/**
* Allows lambda iteration over a list. It is done in reverse order so it is safe
* to add or remove items during the iteration. Skips over null items.
+ *
+ * @deprecated According to b/286841705, this is *not* safe: If an item is removed from the
+ * list, then list.get(i) could throw an IndexOutOfBoundsException. This method should not be
+ * used; try using `synchronized` or making a copy of the list instead.
*/
public static <T> void safeForeach(List<T> list, Consumer<T> c) {
for (int i = list.size() - 1; i >= 0; i--) {
diff --git a/packages/SystemUI/tests/src/android/animation/AnimatorTestRuleIsolationTest.kt b/packages/SystemUI/tests/src/android/animation/AnimatorTestRuleIsolationTest.kt
index 7e105cf19e2b..0fe2283c8543 100644
--- a/packages/SystemUI/tests/src/android/animation/AnimatorTestRuleIsolationTest.kt
+++ b/packages/SystemUI/tests/src/android/animation/AnimatorTestRuleIsolationTest.kt
@@ -31,7 +31,7 @@ import org.junit.runner.RunWith
*/
@RunWith(AndroidTestingRunner::class)
@SmallTest
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
class AnimatorTestRuleIsolationTest : SysuiTestCase() {
@get:Rule val animatorTestRule = AnimatorTestRule()
diff --git a/packages/SystemUI/tests/src/android/animation/AnimatorTestRulePrecisionTest.kt b/packages/SystemUI/tests/src/android/animation/AnimatorTestRulePrecisionTest.kt
index 6c4036852802..cc7f7e4067d9 100644
--- a/packages/SystemUI/tests/src/android/animation/AnimatorTestRulePrecisionTest.kt
+++ b/packages/SystemUI/tests/src/android/animation/AnimatorTestRulePrecisionTest.kt
@@ -28,7 +28,7 @@ import org.junit.runner.RunWith
@RunWith(AndroidTestingRunner::class)
@SmallTest
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
class AnimatorTestRulePrecisionTest : SysuiTestCase() {
@get:Rule val animatorTestRule = AnimatorTestRule()
diff --git a/packages/SystemUI/tests/src/androidx/core/animation/AnimatorTestRuleIsolationTest.kt b/packages/SystemUI/tests/src/androidx/core/animation/AnimatorTestRuleIsolationTest.kt
index d034093a71b3..2d84fbafcf6c 100644
--- a/packages/SystemUI/tests/src/androidx/core/animation/AnimatorTestRuleIsolationTest.kt
+++ b/packages/SystemUI/tests/src/androidx/core/animation/AnimatorTestRuleIsolationTest.kt
@@ -31,7 +31,7 @@ import org.junit.runner.RunWith
*/
@RunWith(AndroidTestingRunner::class)
@SmallTest
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
class AnimatorTestRuleIsolationTest : SysuiTestCase() {
@get:Rule val animatorTestRule = AnimatorTestRule()
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
index e7d420bcb32b..9016220b40cf 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
@@ -419,7 +419,15 @@ public class CarrierTextManagerTest extends SysuiTestCase {
assertFalse(mWifiRepository.isWifiConnectedWithValidSsid());
mWifiRepository.setWifiNetwork(
- new WifiNetworkModel.Active(0, false, 0, "", false, false, null));
+ new WifiNetworkModel.Active(
+ /* networkId= */ 0,
+ /* isValidated= */ false,
+ /* level= */ 0,
+ /* ssid= */ "",
+ /* hotspotDeviceType= */ WifiNetworkModel.HotspotDeviceType.NONE,
+ /* isPasspointAccessPoint= */ false,
+ /* isOnlineSignUpForPasspointAccessPoint= */ false,
+ /* passpointProviderFriendlyName= */ null));
assertTrue(mWifiRepository.isWifiConnectedWithValidSsid());
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
index ac04bc4356ac..98d4d22d59b4 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
@@ -23,6 +23,7 @@ import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLE
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -157,6 +158,12 @@ public class KeyguardClockSwitchControllerBaseTest extends SysuiTestCase {
when(mSmartspaceController.buildAndConnectDateView(any())).thenReturn(mFakeDateView);
when(mSmartspaceController.buildAndConnectWeatherView(any())).thenReturn(mFakeWeatherView);
when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
+ doAnswer(invocation -> {
+ removeView(mFakeDateView);
+ removeView(mFakeWeatherView);
+ removeView(mFakeSmartspaceView);
+ return null;
+ }).when(mSmartspaceController).removeViewsFromParent(any());
mExecutor = new FakeExecutor(new FakeSystemClock());
mFakeFeatureFlags = new FakeFeatureFlags();
mFakeFeatureFlags.set(FACE_AUTH_REFACTOR, false);
@@ -201,6 +208,13 @@ public class KeyguardClockSwitchControllerBaseTest extends SysuiTestCase {
when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(mStatusArea);
}
+ private void removeView(View v) {
+ ViewGroup group = ((ViewGroup) v.getParent());
+ if (group != null) {
+ group.removeView(v);
+ }
+ }
+
protected void init() {
mController.init();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index efb981e5cebb..9ba21da59361 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -27,6 +27,7 @@ import android.testing.TestableResources
import android.view.Gravity
import android.view.LayoutInflater
import android.view.MotionEvent
+import android.view.View
import android.view.WindowInsetsController
import android.widget.FrameLayout
import androidx.test.filters.SmallTest
@@ -50,6 +51,7 @@ import com.android.systemui.plugins.ActivityStarter.OnDismissAction
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -66,6 +68,8 @@ import com.google.common.truth.Truth
import java.util.Optional
import junit.framework.Assert
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -80,6 +84,7 @@ import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
@@ -139,6 +144,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
private lateinit var testableResources: TestableResources
private lateinit var sceneTestUtils: SceneTestUtils
private lateinit var sceneInteractor: SceneInteractor
+ private lateinit var sceneTransitionStateFlow: MutableStateFlow<ObservableTransitionState>
private lateinit var underTest: KeyguardSecurityContainerController
@@ -198,6 +204,9 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
whenever(userInteractor.getSelectedUserId()).thenReturn(TARGET_USER_ID)
sceneTestUtils = SceneTestUtils(this)
sceneInteractor = sceneTestUtils.sceneInteractor()
+ sceneTransitionStateFlow =
+ MutableStateFlow(ObservableTransitionState.Idle(SceneKey.Lockscreen))
+ sceneInteractor.setTransitionState(sceneTransitionStateFlow)
underTest =
KeyguardSecurityContainerController(
@@ -484,6 +493,30 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
}
@Test
+ fun showNextSecurityScreenOrFinish_SimPinToAnotherSimPin_None() {
+ // GIVEN the current security method is SimPin
+ whenever(keyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(false)
+ whenever(keyguardUpdateMonitor.getUserUnlockedWithBiometric(TARGET_USER_ID))
+ .thenReturn(false)
+ underTest.showSecurityScreen(SecurityMode.SimPin)
+
+ // WHEN a request is made from the SimPin screens to show the next security method
+ whenever(keyguardSecurityModel.getSecurityMode(TARGET_USER_ID))
+ .thenReturn(SecurityMode.SimPin)
+ whenever(lockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(true)
+
+ underTest.showNextSecurityScreenOrFinish(
+ /* authenticated= */ true,
+ TARGET_USER_ID,
+ /* bypassSecondaryLockScreen= */ true,
+ SecurityMode.SimPin
+ )
+
+ // THEN the next security method of None will dismiss keyguard.
+ verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
+ }
+
+ @Test
fun onSwipeUp_whenFaceDetectionIsNotRunning_initiatesFaceAuth() {
val registeredSwipeListener = registeredSwipeListener
whenever(keyguardUpdateMonitor.isFaceDetectionRunning).thenReturn(false)
@@ -733,20 +766,39 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
// is
// not enough to trigger a dismissal of the keyguard.
underTest.onViewAttached()
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer, null), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer, null), "reason")
+ sceneTransitionStateFlow.value =
+ ObservableTransitionState.Transition(
+ SceneKey.Lockscreen,
+ SceneKey.Bouncer,
+ flowOf(.5f)
+ )
+ runCurrent()
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer, null), "reason")
+ sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Bouncer)
runCurrent()
verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
// While listening, going from the bouncer scene to the gone scene, does dismiss the
// keyguard.
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone, null), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Gone, null), "reason")
+ sceneTransitionStateFlow.value =
+ ObservableTransitionState.Transition(SceneKey.Bouncer, SceneKey.Gone, flowOf(.5f))
+ runCurrent()
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason")
+ sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Gone)
runCurrent()
verify(viewMediatorCallback).keyguardDone(anyBoolean(), anyInt())
// While listening, moving back to the bouncer scene does not dismiss the keyguard
// again.
clearInvocations(viewMediatorCallback)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer, null), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer, null), "reason")
+ sceneTransitionStateFlow.value =
+ ObservableTransitionState.Transition(SceneKey.Gone, SceneKey.Bouncer, flowOf(.5f))
+ runCurrent()
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer, null), "reason")
+ sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Bouncer)
runCurrent()
verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
@@ -754,12 +806,22 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
// scene
// does not dismiss the keyguard while we're not listening.
underTest.onViewDetached()
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone, null), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Gone, null), "reason")
+ sceneTransitionStateFlow.value =
+ ObservableTransitionState.Transition(SceneKey.Bouncer, SceneKey.Gone, flowOf(.5f))
+ runCurrent()
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason")
+ sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Gone)
runCurrent()
verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
// While not listening, moving back to the bouncer does not dismiss the keyguard.
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer, null), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer, null), "reason")
+ sceneTransitionStateFlow.value =
+ ObservableTransitionState.Transition(SceneKey.Gone, SceneKey.Bouncer, flowOf(.5f))
+ runCurrent()
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer, null), "reason")
+ sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Bouncer)
runCurrent()
verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
@@ -767,11 +829,26 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
// gone
// scene now does dismiss the keyguard again.
underTest.onViewAttached()
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone, null), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Gone, null), "reason")
+ sceneTransitionStateFlow.value =
+ ObservableTransitionState.Transition(SceneKey.Bouncer, SceneKey.Gone, flowOf(.5f))
+ runCurrent()
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason")
+ sceneTransitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Gone)
runCurrent()
verify(viewMediatorCallback).keyguardDone(anyBoolean(), anyInt())
}
+ @Test
+ fun testResetUserSwitcher() {
+ val userSwitcher = mock(View::class.java)
+ whenever(view.findViewById<View>(R.id.keyguard_bouncer_user_switcher))
+ .thenReturn(userSwitcher)
+
+ underTest.prepareToShow()
+ verify(userSwitcher).setAlpha(0f)
+ }
+
private val registeredSwipeListener: KeyguardSecurityContainer.SwipeListener
get() {
underTest.onViewAttached()
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index 20d9ef1e86b1..7d23c800321a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -119,8 +120,8 @@ public class KeyguardStatusViewControllerTest extends KeyguardStatusViewControll
@Test
public void correctlyDump() {
mController.onInit();
- verify(mDumpManager).registerDumpable(mController);
+ verify(mDumpManager).registerDumpable(eq(mController.getInstanceName()), eq(mController));
mController.onDestroy();
- verify(mDumpManager, times(1)).unregisterDumpable(KeyguardStatusViewController.TAG);
+ verify(mDumpManager, times(1)).unregisterDumpable(eq(mController.getInstanceName()));
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 5abab6239b1e..6f3322ab1b85 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -40,6 +40,7 @@ import static com.android.keyguard.KeyguardUpdateMonitor.DEFAULT_CANCEL_SIGNAL_T
import static com.android.keyguard.KeyguardUpdateMonitor.HAL_POWER_PRESS_TIMEOUT;
import static com.android.keyguard.KeyguardUpdateMonitor.getCurrentUser;
import static com.android.systemui.flags.Flags.FP_LISTEN_OCCLUDING_APPS;
+import static com.android.systemui.flags.Flags.STOP_FACE_AUTH_ON_DISPLAY_OFF;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_CLOSED;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN;
@@ -89,6 +90,7 @@ import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
+import android.hardware.display.DisplayManagerGlobal;
import android.hardware.face.FaceAuthenticateOptions;
import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorProperties;
@@ -121,6 +123,9 @@ import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.text.TextUtils;
+import android.view.Display;
+import android.view.DisplayAdjustments;
+import android.view.DisplayInfo;
import androidx.annotation.NonNull;
@@ -143,6 +148,7 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -304,10 +310,12 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mFingerprintAuthenticatorsRegisteredCallback;
private IFaceAuthenticatorsRegisteredCallback mFaceAuthenticatorsRegisteredCallback;
private final InstanceId mKeyguardInstanceId = InstanceId.fakeInstanceId(999);
+ private FakeDisplayTracker mDisplayTracker;
@Before
public void setup() throws RemoteException {
MockitoAnnotations.initMocks(this);
+ mDisplayTracker = new FakeDisplayTracker(mContext);
when(mSessionTracker.getSessionId(SESSION_KEYGUARD)).thenReturn(mKeyguardInstanceId);
when(mUserManager.isUserUnlocked(anyInt())).thenReturn(true);
@@ -348,6 +356,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
allowTestableLooperAsMainThread();
mFeatureFlags = new FakeFeatureFlags();
mFeatureFlags.set(FP_LISTEN_OCCLUDING_APPS, false);
+ mFeatureFlags.set(STOP_FACE_AUTH_ON_DISPLAY_OFF, false);
when(mSecureSettings.getUriFor(anyString())).thenReturn(mURI);
@@ -358,6 +367,11 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
anyInt());
mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext);
+ setupBiometrics(mKeyguardUpdateMonitor);
+ }
+
+ private void setupBiometrics(KeyguardUpdateMonitor keyguardUpdateMonitor)
+ throws RemoteException {
captureAuthenticatorsRegisteredCallbacks();
setupFaceAuth(/* isClass3 */ false);
setupFingerprintAuth(/* isClass3 */ true);
@@ -367,9 +381,9 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mBiometricEnabledOnKeyguardCallback = mBiometricEnabledCallbackArgCaptor.getValue();
biometricsEnabledForCurrentUser();
- mHandler = spy(mKeyguardUpdateMonitor.getHandler());
+ mHandler = spy(keyguardUpdateMonitor.getHandler());
try {
- FieldSetter.setField(mKeyguardUpdateMonitor,
+ FieldSetter.setField(keyguardUpdateMonitor,
KeyguardUpdateMonitor.class.getDeclaredField("mHandler"), mHandler);
} catch (NoSuchFieldException e) {
@@ -3029,6 +3043,79 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
verify(callback).onBiometricEnrollmentStateChanged(BiometricSourceType.FACE);
}
+ @Test
+ public void stopFaceAuthOnDisplayOffFlagNotEnabled_doNotRegisterForDisplayCallback() {
+ assertThat(mDisplayTracker.getDisplayCallbacks().size()).isEqualTo(0);
+ }
+
+ @Test
+ public void onDisplayOn_nothingHappens() throws RemoteException {
+ // GIVEN
+ keyguardIsVisible();
+ enableStopFaceAuthOnDisplayOff();
+
+ // WHEN the default display state changes to ON
+ triggerDefaultDisplayStateChangeToOn();
+
+ // THEN face auth is NOT started since we rely on STARTED_WAKING_UP to start face auth,
+ // NOT the display on event
+ verifyFaceAuthenticateNeverCalled();
+ verifyFaceDetectNeverCalled();
+ }
+
+ @Test
+ public void onDisplayOff_stopFaceAuth() throws RemoteException {
+ enableStopFaceAuthOnDisplayOff();
+
+ // GIVEN device is listening for face
+ mKeyguardUpdateMonitor.setKeyguardShowing(true, false);
+ mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
+ mTestableLooper.processAllMessages();
+ verifyFaceAuthenticateCall();
+
+ final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal);
+ mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel;
+ KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
+ mKeyguardUpdateMonitor.registerCallback(callback);
+
+ // WHEN the default display state changes to OFF
+ triggerDefaultDisplayStateChangeToOff();
+
+ // THEN face listening is stopped.
+ verify(faceCancel).cancel();
+ verify(callback).onBiometricRunningStateChanged(
+ eq(false), eq(BiometricSourceType.FACE)); // beverlyt
+
+ }
+
+ private void triggerDefaultDisplayStateChangeToOn() {
+ triggerDefaultDisplayStateChangeTo(true);
+ }
+
+ private void triggerDefaultDisplayStateChangeToOff() {
+ triggerDefaultDisplayStateChangeTo(false);
+ }
+
+ /**
+ * @param on true for Display.STATE_ON, else Display.STATE_OFF
+ */
+ private void triggerDefaultDisplayStateChangeTo(boolean on) {
+ DisplayManagerGlobal displayManagerGlobal = mock(DisplayManagerGlobal.class);
+ DisplayInfo displayInfoWithDisplayState = new DisplayInfo();
+ displayInfoWithDisplayState.state = on ? Display.STATE_ON : Display.STATE_OFF;
+ when(displayManagerGlobal.getDisplayInfo(mDisplayTracker.getDefaultDisplayId()))
+ .thenReturn(displayInfoWithDisplayState);
+ mDisplayTracker.setAllDisplays(new Display[]{
+ new Display(
+ displayManagerGlobal,
+ mDisplayTracker.getDefaultDisplayId(),
+ displayInfoWithDisplayState,
+ DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS
+ )
+ });
+ mDisplayTracker.triggerOnDisplayChanged(mDisplayTracker.getDefaultDisplayId());
+ }
+
private void verifyFingerprintAuthenticateNeverCalled() {
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), any());
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
@@ -3297,6 +3384,18 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
}
+ private void enableStopFaceAuthOnDisplayOff() throws RemoteException {
+ cleanupKeyguardUpdateMonitor();
+ clearInvocations(mFaceManager);
+ clearInvocations(mFingerprintManager);
+ clearInvocations(mBiometricManager);
+ clearInvocations(mStatusBarStateController);
+ mFeatureFlags.set(STOP_FACE_AUTH_ON_DISPLAY_OFF, true);
+ mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext);
+ setupBiometrics(mKeyguardUpdateMonitor);
+ assertThat(mDisplayTracker.getDisplayCallbacks().size()).isEqualTo(1);
+ }
+
private Intent putPhoneInfo(Intent intent, Bundle data, Boolean simInited) {
int subscription = simInited
? 1/* mock subid=1 */ : SubscriptionManager.PLACEHOLDER_SUBSCRIPTION_ID_BASE;
@@ -3374,7 +3473,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mPackageManager, mFaceManager, mFingerprintManager, mBiometricManager,
mFaceWakeUpTriggersConfig, mDevicePostureController,
Optional.of(mInteractiveToAuthProvider), mFeatureFlags,
- mTaskStackChangeListeners, mActivityTaskManager);
+ mTaskStackChangeListeners, mActivityTaskManager, mDisplayTracker);
setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
index ed6a891a6094..45021ba1b300 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
@@ -20,7 +20,9 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRIN
import static com.android.keyguard.LockIconView.ICON_LOCK;
import static com.android.keyguard.LockIconView.ICON_UNLOCK;
+import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
@@ -33,11 +35,13 @@ import android.hardware.biometrics.BiometricSourceType;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.Pair;
+import android.view.HapticFeedbackConstants;
import android.view.View;
import androidx.test.filters.SmallTest;
import com.android.settingslib.udfps.UdfpsOverlayParams;
+import com.android.systemui.biometrics.UdfpsController;
import com.android.systemui.doze.util.BurnInHelperKt;
import org.junit.Test;
@@ -339,4 +343,59 @@ public class LockIconViewControllerTest extends LockIconViewControllerBaseTest {
// THEN the lock icon is shown
verify(mLockIconView).setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
}
+
+ @Test
+ public void playHaptic_onTouchExploration_NoOneWayHaptics_usesVibrate() {
+ mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, false);
+
+ // WHEN request to vibrate on touch exploration
+ mUnderTest.vibrateOnTouchExploration();
+
+ // THEN vibrates
+ verify(mVibrator).vibrate(
+ anyInt(),
+ any(),
+ eq(UdfpsController.EFFECT_CLICK),
+ eq("lock-icon-down"),
+ any());
+ }
+
+ @Test
+ public void playHaptic_onTouchExploration_withOneWayHaptics_performHapticFeedback() {
+ mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true);
+
+ // WHEN request to vibrate on touch exploration
+ mUnderTest.vibrateOnTouchExploration();
+
+ // THEN performHapticFeedback is used
+ verify(mVibrator).performHapticFeedback(any(), eq(HapticFeedbackConstants.CONTEXT_CLICK));
+ }
+
+ @Test
+ public void playHaptic_onLongPress_NoOneWayHaptics_usesVibrate() {
+ mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, false);
+
+ // WHEN request to vibrate on long press
+ mUnderTest.vibrateOnLongPress();
+
+ // THEN uses vibrate
+ verify(mVibrator).vibrate(
+ anyInt(),
+ any(),
+ eq(UdfpsController.EFFECT_CLICK),
+ eq("lock-screen-lock-icon-longpress"),
+ any());
+ }
+
+ @Test
+ public void playHaptic_onLongPress_withOneWayHaptics_performHapticFeedback() {
+ mFeatureFlags.set(ONE_WAY_HAPTICS_API_MIGRATION, true);
+
+ // WHEN request to vibrate on long press
+ mUnderTest.vibrateOnLongPress();
+
+ // THEN uses perform haptic feedback
+ verify(mVibrator).performHapticFeedback(any(), eq(UdfpsController.LONG_PRESS));
+
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java
index 44a2b682bf37..ba27fcd49fac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java
@@ -25,12 +25,12 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
-import androidx.core.animation.AnimatorTestRule;
import androidx.core.animation.ObjectAnimator;
import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.animation.AnimatorTestRule;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.statusbar.NotificationMediaManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/AnimatorTestRuleOrderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/AnimatorTestRuleOrderTest.kt
new file mode 100644
index 000000000000..a7e7dd074a33
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/AnimatorTestRuleOrderTest.kt
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.animation
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import androidx.core.animation.doOnEnd
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.doOnEnd
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+@RunWithLooper
+class AnimatorTestRuleOrderTest : SysuiTestCase() {
+
+ @get:Rule val animatorTestRule = AnimatorTestRule()
+
+ var value1: Float = -1f
+ var value2: Float = -1f
+
+ private inline fun animateThisX(
+ propertyName: String,
+ duration: Long,
+ startDelay: Long = 0,
+ crossinline onEndAction: () -> Unit,
+ ) {
+ androidx.core.animation.ObjectAnimator.ofFloat(this, propertyName, 0f, 1f).also {
+ it.interpolator = null
+ it.duration = duration
+ it.startDelay = startDelay
+ it.doOnEnd { onEndAction() }
+ it.start()
+ }
+ }
+
+ private inline fun animateThisP(
+ propertyName: String,
+ duration: Long,
+ startDelay: Long = 0,
+ crossinline onEndAction: () -> Unit,
+ ) {
+ android.animation.ObjectAnimator.ofFloat(this, propertyName, 0f, 1f).also {
+ it.interpolator = null
+ it.duration = duration
+ it.startDelay = startDelay
+ it.doOnEnd { onEndAction() }
+ it.start()
+ }
+ }
+
+ @Test
+ fun testTwoAnimators() {
+ var ended1 = false
+ var ended2 = false
+ animateThisP("value1", duration = 100) { ended1 = true }
+ animateThisX("value2", duration = 200) { ended2 = true }
+ assertThat(value1).isEqualTo(0f)
+ assertThat(value2).isEqualTo(0f)
+ assertThat(ended1).isFalse()
+ assertThat(ended2).isFalse()
+
+ animatorTestRule.advanceTimeBy(99)
+ assertThat(value1).isEqualTo(0.99f)
+ assertThat(value2).isEqualTo(0.495f)
+ assertThat(ended1).isFalse()
+ assertThat(ended2).isFalse()
+
+ animatorTestRule.advanceTimeBy(1)
+ assertThat(value1).isEqualTo(1f)
+ assertThat(value2).isEqualTo(0.5f)
+ assertThat(ended1).isTrue()
+ assertThat(ended2).isFalse()
+
+ animatorTestRule.advanceTimeBy(99)
+ assertThat(value1).isEqualTo(1f)
+ assertThat(value2).isEqualTo(0.995f)
+ assertThat(ended1).isTrue()
+ assertThat(ended2).isFalse()
+
+ animatorTestRule.advanceTimeBy(1)
+ assertThat(value1).isEqualTo(1f)
+ assertThat(value2).isEqualTo(1f)
+ assertThat(ended1).isTrue()
+ assertThat(ended2).isTrue()
+ }
+
+ @Test
+ fun testChainedAnimatorsPlatformThenX() {
+ var ended1 = false
+ var ended2 = false
+ animateThisP("value1", duration = 100) {
+ ended1 = true
+ animateThisX("value2", duration = 100) { ended2 = true }
+ }
+
+ assertThat(value1).isEqualTo(0f)
+ assertThat(value2).isEqualTo(-1f)
+ assertThat(ended1).isFalse()
+ assertThat(ended2).isFalse()
+
+ animatorTestRule.advanceTimeBy(50)
+ assertThat(value1).isEqualTo(0.5f)
+ assertThat(value2).isEqualTo(-1f)
+ assertThat(ended1).isFalse()
+ assertThat(ended2).isFalse()
+
+ animatorTestRule.advanceTimeBy(50)
+ assertThat(value1).isEqualTo(1f)
+ assertThat(value2).isEqualTo(0f)
+ assertThat(ended1).isTrue()
+ assertThat(ended2).isFalse()
+
+ animatorTestRule.advanceTimeBy(50)
+ assertThat(value1).isEqualTo(1f)
+ assertThat(value2).isEqualTo(0.5f)
+ assertThat(ended1).isTrue()
+ assertThat(ended2).isFalse()
+
+ animatorTestRule.advanceTimeBy(50)
+ assertThat(value1).isEqualTo(1f)
+ assertThat(value2).isEqualTo(1f)
+ assertThat(ended1).isTrue()
+ assertThat(ended2).isTrue()
+ }
+
+ @Test
+ fun testChainedAnimatorsXThenPlatform() {
+ var ended1 = false
+ var ended2 = false
+ animateThisX("value1", duration = 100) {
+ ended1 = true
+ animateThisP("value2", duration = 100) { ended2 = true }
+ }
+
+ assertThat(value1).isEqualTo(0f)
+ assertThat(value2).isEqualTo(-1f)
+ assertThat(ended1).isFalse()
+ assertThat(ended2).isFalse()
+
+ animatorTestRule.advanceTimeBy(50)
+ assertThat(value1).isEqualTo(0.5f)
+ assertThat(value2).isEqualTo(-1f)
+ assertThat(ended1).isFalse()
+ assertThat(ended2).isFalse()
+
+ animatorTestRule.advanceTimeBy(50)
+ assertThat(value1).isEqualTo(1f)
+ assertThat(value2).isEqualTo(0f)
+ assertThat(ended1).isTrue()
+ assertThat(ended2).isFalse()
+
+ animatorTestRule.advanceTimeBy(50)
+ assertThat(value1).isEqualTo(1f)
+ assertThat(value2).isEqualTo(0.5f)
+ assertThat(ended1).isTrue()
+ assertThat(ended2).isFalse()
+
+ animatorTestRule.advanceTimeBy(50)
+ assertThat(value1).isEqualTo(1f)
+ assertThat(value2).isEqualTo(1f)
+ assertThat(ended1).isTrue()
+ assertThat(ended2).isTrue()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt
index 005697044c0f..d3a2a73959dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt
@@ -18,23 +18,30 @@
package com.android.systemui.authentication.data.repository
+import android.app.admin.DevicePolicyManager
+import android.content.Intent
import android.content.pm.UserInfo
import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
import com.android.keyguard.KeyguardSecurityModel
import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.model.AuthenticationMethodModel
+import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
+import java.util.function.Function
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
+import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.MockitoAnnotations
@@ -43,6 +50,7 @@ import org.mockito.MockitoAnnotations
class AuthenticationRepositoryTest : SysuiTestCase() {
@Mock private lateinit var lockPatternUtils: LockPatternUtils
+ @Mock private lateinit var getSecurityMode: Function<Int, KeyguardSecurityModel.SecurityMode>
private val testUtils = SceneTestUtils(this)
private val testScope = testUtils.testScope
@@ -50,24 +58,49 @@ class AuthenticationRepositoryTest : SysuiTestCase() {
private lateinit var underTest: AuthenticationRepository
+ private var currentSecurityMode: KeyguardSecurityModel.SecurityMode =
+ KeyguardSecurityModel.SecurityMode.PIN
+
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
userRepository.setUserInfos(USER_INFOS)
runBlocking { userRepository.setSelectedUserInfo(USER_INFOS[0]) }
+ whenever(getSecurityMode.apply(anyInt())).thenAnswer { currentSecurityMode }
underTest =
AuthenticationRepositoryImpl(
applicationScope = testScope.backgroundScope,
- getSecurityMode = { KeyguardSecurityModel.SecurityMode.PIN },
+ getSecurityMode = getSecurityMode,
backgroundDispatcher = testUtils.testDispatcher,
userRepository = userRepository,
keyguardRepository = testUtils.keyguardRepository,
lockPatternUtils = lockPatternUtils,
+ broadcastDispatcher = fakeBroadcastDispatcher,
)
}
@Test
+ fun authenticationMethod() =
+ testScope.runTest {
+ val authMethod by collectLastValue(underTest.authenticationMethod)
+ runCurrent()
+ dispatchBroadcast()
+ assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Pin)
+ assertThat(underTest.getAuthenticationMethod()).isEqualTo(AuthenticationMethodModel.Pin)
+
+ setSecurityModeAndDispatchBroadcast(KeyguardSecurityModel.SecurityMode.Pattern)
+ assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Pattern)
+ assertThat(underTest.getAuthenticationMethod())
+ .isEqualTo(AuthenticationMethodModel.Pattern)
+
+ setSecurityModeAndDispatchBroadcast(KeyguardSecurityModel.SecurityMode.None)
+ assertThat(authMethod).isEqualTo(AuthenticationMethodModel.None)
+ assertThat(underTest.getAuthenticationMethod())
+ .isEqualTo(AuthenticationMethodModel.None)
+ }
+
+ @Test
fun isAutoConfirmEnabled() =
testScope.runTest {
whenever(lockPatternUtils.isAutoPinConfirmEnabled(USER_INFOS[0].id)).thenReturn(true)
@@ -95,6 +128,20 @@ class AuthenticationRepositoryTest : SysuiTestCase() {
assertThat(values.last()).isTrue()
}
+ private fun setSecurityModeAndDispatchBroadcast(
+ securityMode: KeyguardSecurityModel.SecurityMode,
+ ) {
+ currentSecurityMode = securityMode
+ dispatchBroadcast()
+ }
+
+ private fun dispatchBroadcast() {
+ fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+ context,
+ Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED)
+ )
+ }
+
companion object {
private val USER_INFOS =
listOf(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
index a86937fcad3c..d848cd46e509 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
@@ -19,9 +19,11 @@ package com.android.systemui.authentication.domain.interactor
import android.app.admin.DevicePolicyManager
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.model.AuthenticationMethodModel as DataLayerAuthenticationMethodModel
import com.android.systemui.authentication.data.repository.AuthenticationRepository
import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
-import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.authentication.domain.model.AuthenticationMethodModel as DomainLayerAuthenticationMethodModel
+import com.android.systemui.authentication.shared.model.AuthenticationPatternCoordinate
import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
@@ -50,42 +52,61 @@ class AuthenticationInteractorTest : SysuiTestCase() {
)
@Test
- fun getAuthenticationMethod() =
+ fun authenticationMethod() =
testScope.runTest {
- assertThat(underTest.getAuthenticationMethod()).isEqualTo(AuthenticationMethodModel.Pin)
+ val authMethod by collectLastValue(underTest.authenticationMethod)
+ runCurrent()
+ assertThat(authMethod).isEqualTo(DomainLayerAuthenticationMethodModel.Pin)
+ assertThat(underTest.getAuthenticationMethod())
+ .isEqualTo(DomainLayerAuthenticationMethodModel.Pin)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password
+ DataLayerAuthenticationMethodModel.Password
)
+ assertThat(authMethod).isEqualTo(DomainLayerAuthenticationMethodModel.Password)
assertThat(underTest.getAuthenticationMethod())
- .isEqualTo(AuthenticationMethodModel.Password)
+ .isEqualTo(DomainLayerAuthenticationMethodModel.Password)
}
@Test
- fun getAuthenticationMethod_noneTreatedAsSwipe_whenLockscreenEnabled() =
+ fun authenticationMethod_noneTreatedAsSwipe_whenLockscreenEnabled() =
testScope.runTest {
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ val authMethod by collectLastValue(underTest.authenticationMethod)
+ runCurrent()
+
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.None
+ )
utils.authenticationRepository.setLockscreenEnabled(true)
+ assertThat(authMethod).isEqualTo(DomainLayerAuthenticationMethodModel.Swipe)
assertThat(underTest.getAuthenticationMethod())
- .isEqualTo(AuthenticationMethodModel.Swipe)
+ .isEqualTo(DomainLayerAuthenticationMethodModel.Swipe)
}
@Test
- fun getAuthenticationMethod_none_whenLockscreenDisabled() =
+ fun authenticationMethod_none_whenLockscreenDisabled() =
testScope.runTest {
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ val authMethod by collectLastValue(underTest.authenticationMethod)
+ runCurrent()
+
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.None
+ )
utils.authenticationRepository.setLockscreenEnabled(false)
+ assertThat(authMethod).isEqualTo(DomainLayerAuthenticationMethodModel.None)
assertThat(underTest.getAuthenticationMethod())
- .isEqualTo(AuthenticationMethodModel.None)
+ .isEqualTo(DomainLayerAuthenticationMethodModel.None)
}
@Test
fun isUnlocked_whenAuthMethodIsNoneAndLockscreenDisabled_isTrue() =
testScope.runTest {
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.None
+ )
utils.authenticationRepository.setLockscreenEnabled(false)
val isUnlocked by collectLastValue(underTest.isUnlocked)
@@ -111,7 +132,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
@Test
fun isUnlocked_whenAuthMethodIsNoneAndLockscreenEnabled_isFalse() =
testScope.runTest {
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.None
+ )
utils.authenticationRepository.setLockscreenEnabled(true)
val isUnlocked by collectLastValue(underTest.isUnlocked)
@@ -124,7 +147,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
utils.authenticationRepository.setUnlocked(false)
runCurrent()
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password
+ DataLayerAuthenticationMethodModel.Password
)
assertThat(underTest.isAuthenticationRequired()).isTrue()
@@ -135,7 +158,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest {
utils.authenticationRepository.setUnlocked(false)
runCurrent()
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.None
+ )
assertThat(underTest.isAuthenticationRequired()).isFalse()
}
@@ -146,7 +171,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
utils.authenticationRepository.setUnlocked(true)
runCurrent()
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password
+ DataLayerAuthenticationMethodModel.Password
)
assertThat(underTest.isAuthenticationRequired()).isFalse()
@@ -157,7 +182,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest {
utils.authenticationRepository.setUnlocked(true)
runCurrent()
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.None
+ )
assertThat(underTest.isAuthenticationRequired()).isFalse()
}
@@ -166,7 +193,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
fun authenticate_withCorrectPin_returnsTrue() =
testScope.runTest {
val isThrottled by collectLastValue(underTest.isThrottled)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.Pin
+ )
assertThat(underTest.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)).isTrue()
assertThat(isThrottled).isFalse()
}
@@ -174,21 +203,27 @@ class AuthenticationInteractorTest : SysuiTestCase() {
@Test
fun authenticate_withIncorrectPin_returnsFalse() =
testScope.runTest {
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.Pin
+ )
assertThat(underTest.authenticate(listOf(9, 8, 7, 6, 5, 4))).isFalse()
}
@Test(expected = IllegalArgumentException::class)
fun authenticate_withEmptyPin_throwsException() =
testScope.runTest {
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.Pin
+ )
underTest.authenticate(listOf())
}
@Test
fun authenticate_withCorrectMaxLengthPin_returnsTrue() =
testScope.runTest {
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.Pin
+ )
val pin = List(16) { 9 }
utils.authenticationRepository.overrideCredential(pin)
assertThat(underTest.authenticate(pin)).isTrue()
@@ -203,7 +238,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
// If the policy changes, there is work to do in SysUI.
assertThat(DevicePolicyManager.MAX_PASSWORD_LENGTH).isLessThan(17)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.Pin
+ )
assertThat(underTest.authenticate(List(17) { 9 })).isFalse()
}
@@ -212,7 +249,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest {
val isThrottled by collectLastValue(underTest.isThrottled)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password
+ DataLayerAuthenticationMethodModel.Password
)
assertThat(underTest.authenticate("password".toList())).isTrue()
@@ -223,7 +260,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
fun authenticate_withIncorrectPassword_returnsFalse() =
testScope.runTest {
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password
+ DataLayerAuthenticationMethodModel.Password
)
assertThat(underTest.authenticate("alohomora".toList())).isFalse()
@@ -233,7 +270,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
fun authenticate_withCorrectPattern_returnsTrue() =
testScope.runTest {
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pattern
+ DataLayerAuthenticationMethodModel.Pattern
)
assertThat(underTest.authenticate(FakeAuthenticationRepository.PATTERN)).isTrue()
@@ -243,21 +280,21 @@ class AuthenticationInteractorTest : SysuiTestCase() {
fun authenticate_withIncorrectPattern_returnsFalse() =
testScope.runTest {
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pattern
+ DataLayerAuthenticationMethodModel.Pattern
)
assertThat(
underTest.authenticate(
listOf(
- AuthenticationMethodModel.Pattern.PatternCoordinate(
+ AuthenticationPatternCoordinate(
x = 2,
y = 0,
),
- AuthenticationMethodModel.Pattern.PatternCoordinate(
+ AuthenticationPatternCoordinate(
x = 2,
y = 1,
),
- AuthenticationMethodModel.Pattern.PatternCoordinate(
+ AuthenticationPatternCoordinate(
x = 2,
y = 2,
),
@@ -271,7 +308,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
fun tryAutoConfirm_withAutoConfirmPinAndShorterPin_returnsNullAndHasNoEffect() =
testScope.runTest {
val isThrottled by collectLastValue(underTest.isThrottled)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.Pin
+ )
utils.authenticationRepository.setAutoConfirmEnabled(true)
assertThat(
underTest.authenticate(
@@ -289,7 +328,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
fun tryAutoConfirm_withAutoConfirmWrongPinCorrectLength_returnsFalseAndDoesNotUnlockDevice() =
testScope.runTest {
val isUnlocked by collectLastValue(underTest.isUnlocked)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.Pin
+ )
utils.authenticationRepository.setAutoConfirmEnabled(true)
assertThat(
underTest.authenticate(
@@ -305,7 +346,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
fun tryAutoConfirm_withAutoConfirmLongerPin_returnsFalseAndDoesNotUnlockDevice() =
testScope.runTest {
val isUnlocked by collectLastValue(underTest.isUnlocked)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.Pin
+ )
utils.authenticationRepository.setAutoConfirmEnabled(true)
assertThat(
underTest.authenticate(
@@ -321,7 +364,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
fun tryAutoConfirm_withAutoConfirmCorrectPin_returnsTrueAndUnlocksDevice() =
testScope.runTest {
val isUnlocked by collectLastValue(underTest.isUnlocked)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.Pin
+ )
utils.authenticationRepository.setAutoConfirmEnabled(true)
assertThat(
underTest.authenticate(
@@ -337,7 +382,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
fun tryAutoConfirm_withoutAutoConfirmButCorrectPin_returnsNullAndHasNoEffects() =
testScope.runTest {
val isUnlocked by collectLastValue(underTest.isUnlocked)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.Pin
+ )
utils.authenticationRepository.setAutoConfirmEnabled(false)
assertThat(
underTest.authenticate(
@@ -354,7 +401,7 @@ class AuthenticationInteractorTest : SysuiTestCase() {
testScope.runTest {
val isUnlocked by collectLastValue(underTest.isUnlocked)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password
+ DataLayerAuthenticationMethodModel.Password
)
assertThat(underTest.authenticate("password".toList(), tryAutoConfirm = true)).isNull()
@@ -367,7 +414,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
val isUnlocked by collectLastValue(underTest.isUnlocked)
val throttling by collectLastValue(underTest.throttling)
val isThrottled by collectLastValue(underTest.isThrottled)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.Pin
+ )
underTest.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)
assertThat(isUnlocked).isTrue()
assertThat(isThrottled).isFalse()
@@ -456,7 +505,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
fun hintedPinLength_withoutAutoConfirm_isNull() =
testScope.runTest {
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.Pin
+ )
utils.authenticationRepository.setAutoConfirmEnabled(false)
assertThat(hintedPinLength).isNull()
@@ -466,7 +517,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
fun hintedPinLength_withAutoConfirmPinTooShort_isNull() =
testScope.runTest {
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.Pin
+ )
utils.authenticationRepository.overrideCredential(
buildList {
repeat(utils.authenticationRepository.hintedPinLength - 1) { add(it + 1) }
@@ -481,7 +534,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
fun hintedPinLength_withAutoConfirmPinAtRightLength_isSameLength() =
testScope.runTest {
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.Pin
+ )
utils.authenticationRepository.setAutoConfirmEnabled(true)
utils.authenticationRepository.overrideCredential(
buildList { repeat(utils.authenticationRepository.hintedPinLength) { add(it + 1) } }
@@ -494,7 +549,9 @@ class AuthenticationInteractorTest : SysuiTestCase() {
fun hintedPinLength_withAutoConfirmPinTooLong_isNull() =
testScope.runTest {
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.Pin
+ )
utils.authenticationRepository.overrideCredential(
buildList {
repeat(utils.authenticationRepository.hintedPinLength + 1) { add(it + 1) }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java
index 40b572934f74..ec8be8ef3047 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java
@@ -35,6 +35,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.StatusBarLocation;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -63,6 +64,7 @@ public class BatteryMeterViewControllerTest extends SysuiTestCase {
private ContentResolver mContentResolver;
@Mock
private BatteryController mBatteryController;
+ private FakeFeatureFlags mFakeFeatureFlags = new FakeFeatureFlags();
private BatteryMeterViewController mController;
@@ -160,6 +162,7 @@ public class BatteryMeterViewControllerTest extends SysuiTestCase {
mTunerService,
mHandler,
mContentResolver,
+ mFakeFeatureFlags,
mBatteryController
);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt
index c84efac86db5..f0f4ca7f3e66 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt
@@ -131,6 +131,16 @@ class BatteryMeterViewTest : SysuiTestCase() {
}
@Test
+ fun contentDescription_isIncompatibleCharging_notCharging() {
+ mBatteryMeterView.onBatteryLevelChanged(45, true)
+ mBatteryMeterView.onIsIncompatibleChargingChanged(true)
+
+ assertThat(mBatteryMeterView.contentDescription).isEqualTo(
+ context.getString(R.string.accessibility_battery_level, 45)
+ )
+ }
+
+ @Test
fun changesFromEstimateToPercent_textAndContentDescriptionChanges() {
mBatteryMeterView.onBatteryLevelChanged(15, false)
mBatteryMeterView.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE)
@@ -231,14 +241,33 @@ class BatteryMeterViewTest : SysuiTestCase() {
assertThat(drawable.displayShield).isFalse()
}
+ @Test
+ fun isIncompatibleChargingChanged_true_drawableGetsChargingFalse() {
+ mBatteryMeterView.onBatteryLevelChanged(45, true)
+ val drawable = getBatteryDrawable()
+
+ mBatteryMeterView.onIsIncompatibleChargingChanged(true)
+
+ assertThat(drawable.getCharging()).isFalse()
+ }
+
+ @Test
+ fun isIncompatibleChargingChanged_false_drawableGetsChargingTrue() {
+ mBatteryMeterView.onBatteryLevelChanged(45, true)
+ val drawable = getBatteryDrawable()
+
+ mBatteryMeterView.onIsIncompatibleChargingChanged(false)
+
+ assertThat(drawable.getCharging()).isTrue()
+ }
+
private fun getBatteryDrawable(): AccessorizedBatteryDrawable {
return (mBatteryMeterView.getChildAt(0) as ImageView)
.drawable as AccessorizedBatteryDrawable
}
private class Fetcher : BatteryEstimateFetcher {
- override fun fetchBatteryTimeRemainingEstimate(
- completion: EstimateFetchCompletion) {
+ override fun fetchBatteryTimeRemainingEstimate(completion: EstimateFetchCompletion) {
completion.onBatteryRemainingEstimateRetrieved(ESTIMATE)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
index 186df02536ea..38e5728f6e70 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt
@@ -165,6 +165,28 @@ class AlternateBouncerInteractorTest : SysuiTestCase() {
assertFalse(bouncerRepository.alternateBouncerVisible.value)
}
+ @Test
+ fun alternateBouncerUiAvailable_fromMultipleSources() {
+ assertFalse(bouncerRepository.alternateBouncerUIAvailable.value)
+
+ // GIVEN there are two different sources indicating the alternate bouncer is available
+ underTest.setAlternateBouncerUIAvailable(true, "source1")
+ underTest.setAlternateBouncerUIAvailable(true, "source2")
+ assertTrue(bouncerRepository.alternateBouncerUIAvailable.value)
+
+ // WHEN one of the sources no longer says the UI is available
+ underTest.setAlternateBouncerUIAvailable(false, "source1")
+
+ // THEN alternate bouncer UI is still available (from the other source)
+ assertTrue(bouncerRepository.alternateBouncerUIAvailable.value)
+
+ // WHEN all sources say the UI is not available
+ underTest.setAlternateBouncerUIAvailable(false, "source2")
+
+ // THEN alternate boucer UI is not available
+ assertFalse(bouncerRepository.alternateBouncerUIAvailable.value)
+ }
+
private fun givenCanShowAlternateBouncer() {
bouncerRepository.setAlternateBouncerUIAvailable(true)
biometricSettingsRepository.setFingerprintEnrolled(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
index 14fc931522a4..86e0c751085b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
@@ -19,8 +19,9 @@ package com.android.systemui.bouncer.domain.interactor
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.model.AuthenticationMethodModel
import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
-import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.authentication.shared.model.AuthenticationPatternCoordinate
import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
@@ -69,10 +70,11 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun pinAuthMethod() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ runCurrent()
utils.authenticationRepository.setUnlocked(false)
underTest.showOrUnlockDevice()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
@@ -100,10 +102,11 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun pinAuthMethod_tryAutoConfirm_withAutoConfirmPin() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ runCurrent()
utils.authenticationRepository.setAutoConfirmEnabled(true)
utils.authenticationRepository.setUnlocked(false)
underTest.showOrUnlockDevice()
@@ -136,10 +139,11 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun pinAuthMethod_tryAutoConfirm_withoutAutoConfirmPin() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ runCurrent()
utils.authenticationRepository.setUnlocked(false)
underTest.showOrUnlockDevice()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
@@ -165,11 +169,12 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun passwordAuthMethod() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
)
+ runCurrent()
utils.authenticationRepository.setUnlocked(false)
underTest.showOrUnlockDevice()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
@@ -197,11 +202,12 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun patternAuthMethod() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern
)
+ runCurrent()
utils.authenticationRepository.setUnlocked(false)
underTest.showOrUnlockDevice()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
@@ -214,11 +220,7 @@ class BouncerInteractorTest : SysuiTestCase() {
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PATTERN)
// Wrong input.
- assertThat(
- underTest.authenticate(
- listOf(AuthenticationMethodModel.Pattern.PatternCoordinate(1, 2))
- )
- )
+ assertThat(underTest.authenticate(listOf(AuthenticationPatternCoordinate(1, 2))))
.isFalse()
assertThat(message).isEqualTo(MESSAGE_WRONG_PATTERN)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
@@ -234,7 +236,7 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun showOrUnlockDevice_notLocked_switchesToGoneScene() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
runCurrent()
@@ -247,8 +249,9 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun showOrUnlockDevice_authMethodNotSecure_switchesToGoneScene() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.authenticationRepository.setLockscreenEnabled(true)
utils.authenticationRepository.setUnlocked(false)
underTest.showOrUnlockDevice()
@@ -259,11 +262,12 @@ class BouncerInteractorTest : SysuiTestCase() {
@Test
fun showOrUnlockDevice_customMessageShown() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
)
+ runCurrent()
utils.authenticationRepository.setUnlocked(false)
val customMessage = "Hello there!"
@@ -279,7 +283,7 @@ class BouncerInteractorTest : SysuiTestCase() {
val isThrottled by collectLastValue(underTest.isThrottled)
val throttling by collectLastValue(underTest.throttling)
val message by collectLastValue(underTest.message)
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
runCurrent()
underTest.showOrUnlockDevice()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
index 2cc949326fa0..7af8a0425402 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
@@ -18,19 +18,17 @@ package com.android.systemui.bouncer.ui.viewmodel
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.model.AuthenticationMethodModel
import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
-import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(JUnit4::class)
class AuthMethodBouncerViewModelTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
index 0df0a17931f4..2c96bcc9dd33 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
@@ -18,8 +18,9 @@ package com.android.systemui.bouncer.ui.viewmodel
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.model.AuthenticationMethodModel as DataLayerAuthenticationMethodModel
import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
-import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.authentication.domain.model.AuthenticationMethodModel as DomainLayerAuthenticationMethodModel
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
import com.google.common.truth.Truth.assertThat
@@ -55,6 +56,7 @@ class BouncerViewModelTest : SysuiTestCase() {
private val underTest =
utils.bouncerViewModel(
bouncerInteractor = bouncerInteractor,
+ authenticationInteractor = authenticationInteractor,
)
@Test
@@ -86,7 +88,8 @@ class BouncerViewModelTest : SysuiTestCase() {
@Test
fun authMethod_reusesInstances() =
testScope.runTest {
- val seen = mutableMapOf<AuthenticationMethodModel, AuthMethodBouncerViewModel>()
+ val seen =
+ mutableMapOf<DomainLayerAuthenticationMethodModel, AuthMethodBouncerViewModel>()
val authMethodViewModel: AuthMethodBouncerViewModel? by
collectLastValue(underTest.authMethod)
// First pass, populate our "seen" map:
@@ -105,7 +108,7 @@ class BouncerViewModelTest : SysuiTestCase() {
@Test
fun authMethodsToTest_returnsCompleteSampleOfAllAuthMethodTypes() {
assertThat(authMethodsToTest().map { it::class }.toSet())
- .isEqualTo(AuthenticationMethodModel::class.sealedSubclasses.toSet())
+ .isEqualTo(DomainLayerAuthenticationMethodModel::class.sealedSubclasses.toSet())
}
@Test
@@ -113,7 +116,9 @@ class BouncerViewModelTest : SysuiTestCase() {
testScope.runTest {
val message by collectLastValue(underTest.message)
val throttling by collectLastValue(bouncerInteractor.throttling)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.Pin
+ )
assertThat(message?.isUpdateAnimated).isTrue()
repeat(FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING) {
@@ -136,7 +141,9 @@ class BouncerViewModelTest : SysuiTestCase() {
}
)
val throttling by collectLastValue(bouncerInteractor.throttling)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.Pin
+ )
assertThat(isInputEnabled).isTrue()
repeat(FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING) {
@@ -153,7 +160,9 @@ class BouncerViewModelTest : SysuiTestCase() {
fun throttlingDialogMessage() =
testScope.runTest {
val throttlingDialogMessage by collectLastValue(underTest.throttlingDialogMessage)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAuthenticationMethod(
+ DataLayerAuthenticationMethodModel.Pin
+ )
repeat(FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING) {
// Wrong PIN.
@@ -166,13 +175,32 @@ class BouncerViewModelTest : SysuiTestCase() {
assertThat(throttlingDialogMessage).isNull()
}
- private fun authMethodsToTest(): List<AuthenticationMethodModel> {
+ private fun authMethodsToTest(): List<DomainLayerAuthenticationMethodModel> {
return listOf(
- AuthenticationMethodModel.None,
- AuthenticationMethodModel.Swipe,
- AuthenticationMethodModel.Pin,
- AuthenticationMethodModel.Password,
- AuthenticationMethodModel.Pattern,
+ DomainLayerAuthenticationMethodModel.None,
+ DomainLayerAuthenticationMethodModel.Swipe,
+ DomainLayerAuthenticationMethodModel.Pin,
+ DomainLayerAuthenticationMethodModel.Password,
+ DomainLayerAuthenticationMethodModel.Pattern,
+ )
+ }
+
+ private fun FakeAuthenticationRepository.setAuthenticationMethod(
+ model: DomainLayerAuthenticationMethodModel,
+ ) {
+ setAuthenticationMethod(
+ when (model) {
+ is DomainLayerAuthenticationMethodModel.None,
+ is DomainLayerAuthenticationMethodModel.Swipe ->
+ DataLayerAuthenticationMethodModel.None
+ is DomainLayerAuthenticationMethodModel.Pin ->
+ DataLayerAuthenticationMethodModel.Pin
+ is DomainLayerAuthenticationMethodModel.Password ->
+ DataLayerAuthenticationMethodModel.Password
+ is DomainLayerAuthenticationMethodModel.Pattern ->
+ DataLayerAuthenticationMethodModel.Pattern
+ }
)
+ setLockscreenEnabled(model !is DomainLayerAuthenticationMethodModel.None)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
index 7f8d54c43387..4380af80efbd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
@@ -19,7 +19,7 @@ package com.android.systemui.bouncer.ui.viewmodel
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
-import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.authentication.data.model.AuthenticationMethodModel
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.SceneKey
@@ -55,6 +55,7 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
private val bouncerViewModel =
utils.bouncerViewModel(
bouncerInteractor = bouncerInteractor,
+ authenticationInteractor = authenticationInteractor,
)
private val underTest =
PasswordBouncerViewModel(
@@ -72,14 +73,15 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
@Test
fun onShown() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -92,14 +94,15 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
@Test
fun onPasswordInputChanged() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -114,12 +117,13 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAuthenticateKeyPressed_whenCorrect() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPasswordInputChanged("password")
@@ -132,14 +136,15 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAuthenticateKeyPressed_whenWrong() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPasswordInputChanged("wrong")
@@ -154,14 +159,15 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAuthenticateKeyPressed_correctAfterWrong() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPasswordInputChanged("wrong")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
index 57fcbe595fa6..ea2cad2ab517 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
@@ -19,8 +19,8 @@ package com.android.systemui.bouncer.ui.viewmodel
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.model.AuthenticationMethodModel
import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
-import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.SceneKey
@@ -57,6 +57,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
private val bouncerViewModel =
utils.bouncerViewModel(
bouncerInteractor = bouncerInteractor,
+ authenticationInteractor = authenticationInteractor,
)
private val underTest =
PatternBouncerViewModel(
@@ -75,7 +76,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
@Test
fun onShown() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
@@ -83,7 +84,8 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -97,7 +99,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
@Test
fun onDragStart() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
@@ -105,7 +107,8 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -121,14 +124,15 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
@Test
fun onDragEnd_whenCorrect() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onDragStart()
@@ -168,7 +172,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
@Test
fun onDragEnd_whenWrong() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
@@ -176,7 +180,8 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onDragStart()
@@ -200,7 +205,7 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
@Test
fun onDragEnd_correctAfterWrong() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
@@ -208,7 +213,8 @@ class PatternBouncerViewModelTest : SysuiTestCase() {
AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onDragStart()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
index 81c68ed2320f..531f86abdfbc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
@@ -19,8 +19,8 @@ package com.android.systemui.bouncer.ui.viewmodel
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.model.AuthenticationMethodModel
import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
-import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.SceneKey
@@ -57,6 +57,7 @@ class PinBouncerViewModelTest : SysuiTestCase() {
private val bouncerViewModel =
utils.bouncerViewModel(
bouncerInteractor = bouncerInteractor,
+ authenticationInteractor = authenticationInteractor,
)
private val underTest =
PinBouncerViewModel(
@@ -75,11 +76,13 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onShown() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -92,12 +95,14 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onPinButtonClicked() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -112,12 +117,14 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onBackspaceButtonClicked() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -134,11 +141,13 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onPinEdit() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -156,12 +165,14 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onBackspaceButtonLongPressed() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -180,10 +191,12 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAuthenticateButtonClicked_whenCorrect() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
FakeAuthenticationRepository.DEFAULT_PIN.forEach { digit ->
@@ -198,12 +211,14 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAuthenticateButtonClicked_whenWrong() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPinButtonClicked(1)
@@ -222,12 +237,14 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAuthenticateButtonClicked_correctAfterWrong() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPinButtonClicked(1)
@@ -254,11 +271,13 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAutoConfirm_whenCorrect() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
utils.authenticationRepository.setAutoConfirmEnabled(true)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
FakeAuthenticationRepository.DEFAULT_PIN.forEach { digit ->
@@ -271,13 +290,15 @@ class PinBouncerViewModelTest : SysuiTestCase() {
@Test
fun onAutoConfirm_whenWrong() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
utils.authenticationRepository.setAutoConfirmEnabled(true)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
FakeAuthenticationRepository.DEFAULT_PIN.dropLast(1).forEach { digit ->
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt
index 35f0f6c68798..37c70d8f25e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt
@@ -28,12 +28,12 @@ import org.junit.runner.RunWith
@RunWith(AndroidTestingRunner::class)
class FakeFeatureFlagsTest : SysuiTestCase() {
- private val unreleasedFlag = UnreleasedFlag(-1000, "-1000", "test")
- private val releasedFlag = ReleasedFlag(-1001, "-1001", "test")
- private val stringFlag = StringFlag(-1002, "-1002", "test")
- private val resourceBooleanFlag = ResourceBooleanFlag(-1003, "-1003", "test", resourceId = -1)
- private val resourceStringFlag = ResourceStringFlag(-1004, "-1004", "test", resourceId = -1)
- private val sysPropBooleanFlag = SysPropBooleanFlag(-1005, "test", "test")
+ private val unreleasedFlag = UnreleasedFlag("-1000", "test")
+ private val releasedFlag = ReleasedFlag("-1001", "test")
+ private val stringFlag = StringFlag("-1002", "test")
+ private val resourceBooleanFlag = ResourceBooleanFlag("-1003", "test", resourceId = -1)
+ private val resourceStringFlag = ResourceStringFlag("-1004", "test", resourceId = -1)
+ private val sysPropBooleanFlag = SysPropBooleanFlag("test", "test")
/**
* FakeFeatureFlags does not honor any default values. All flags which are accessed must be
@@ -46,43 +46,43 @@ class FakeFeatureFlagsTest : SysuiTestCase() {
assertThat(flags.isEnabled(Flags.TEAMFOOD)).isFalse()
fail("Expected an exception when accessing an unspecified flag.")
} catch (ex: IllegalStateException) {
- assertThat(ex.message).contains("id=1")
+ assertThat(ex.message).contains("UNKNOWN(teamfood)")
}
try {
assertThat(flags.isEnabled(unreleasedFlag)).isFalse()
fail("Expected an exception when accessing an unspecified flag.")
} catch (ex: IllegalStateException) {
- assertThat(ex.message).contains("UNKNOWN(id=-1000)")
+ assertThat(ex.message).contains("UNKNOWN(-1000)")
}
try {
assertThat(flags.isEnabled(releasedFlag)).isFalse()
fail("Expected an exception when accessing an unspecified flag.")
} catch (ex: IllegalStateException) {
- assertThat(ex.message).contains("UNKNOWN(id=-1001)")
+ assertThat(ex.message).contains("UNKNOWN(-1001)")
}
try {
assertThat(flags.isEnabled(resourceBooleanFlag)).isFalse()
fail("Expected an exception when accessing an unspecified flag.")
} catch (ex: IllegalStateException) {
- assertThat(ex.message).contains("UNKNOWN(id=-1003)")
+ assertThat(ex.message).contains("UNKNOWN(-1003)")
}
try {
assertThat(flags.isEnabled(sysPropBooleanFlag)).isFalse()
fail("Expected an exception when accessing an unspecified flag.")
} catch (ex: IllegalStateException) {
- assertThat(ex.message).contains("UNKNOWN(id=-1005)")
+ assertThat(ex.message).contains("UNKNOWN(test)")
}
try {
assertThat(flags.getString(stringFlag)).isEmpty()
fail("Expected an exception when accessing an unspecified flag.")
} catch (ex: IllegalStateException) {
- assertThat(ex.message).contains("UNKNOWN(id=-1002)")
+ assertThat(ex.message).contains("UNKNOWN(-1002)")
}
try {
assertThat(flags.getString(resourceStringFlag)).isEmpty()
fail("Expected an exception when accessing an unspecified flag.")
} catch (ex: IllegalStateException) {
- assertThat(ex.message).contains("UNKNOWN(id=-1004)")
+ assertThat(ex.message).contains("UNKNOWN(-1004)")
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
index 18f7db18b1f4..ff15cb39b640 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
@@ -74,10 +74,10 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
private val serverFlagReader = ServerFlagReaderFake()
private val teamfoodableFlagA = UnreleasedFlag(
- 500, name = "a", namespace = "test", teamfood = true
+ name = "a", namespace = "test", teamfood = true
)
private val teamfoodableFlagB = ReleasedFlag(
- 501, name = "b", namespace = "test", teamfood = true
+ name = "b", namespace = "test", teamfood = true
)
@Before
@@ -119,7 +119,6 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
assertThat(
featureFlagsDebug.isEnabled(
ReleasedFlag(
- 2,
name = "2",
namespace = "test"
)
@@ -128,7 +127,6 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
assertThat(
featureFlagsDebug.isEnabled(
UnreleasedFlag(
- 3,
name = "3",
namespace = "test"
)
@@ -137,7 +135,6 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
assertThat(
featureFlagsDebug.isEnabled(
ReleasedFlag(
- 4,
name = "4",
namespace = "test"
)
@@ -146,7 +143,6 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
assertThat(
featureFlagsDebug.isEnabled(
UnreleasedFlag(
- 5,
name = "5",
namespace = "test"
)
@@ -208,23 +204,22 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
assertThat(
featureFlagsDebug.isEnabled(
ResourceBooleanFlag(
- 1,
"1",
"test",
1001
)
)
).isFalse()
- assertThat(featureFlagsDebug.isEnabled(ResourceBooleanFlag(2, "2", "test", 1002))).isTrue()
- assertThat(featureFlagsDebug.isEnabled(ResourceBooleanFlag(3, "3", "test", 1003))).isTrue()
+ assertThat(featureFlagsDebug.isEnabled(ResourceBooleanFlag("2", "test", 1002))).isTrue()
+ assertThat(featureFlagsDebug.isEnabled(ResourceBooleanFlag("3", "test", 1003))).isTrue()
Assert.assertThrows(NameNotFoundException::class.java) {
- featureFlagsDebug.isEnabled(ResourceBooleanFlag(4, "4", "test", 1004))
+ featureFlagsDebug.isEnabled(ResourceBooleanFlag("4", "test", 1004))
}
// Test that resource is loaded (and validated) even when the setting is set.
// This prevents developers from not noticing when they reference an invalid resource.
Assert.assertThrows(NameNotFoundException::class.java) {
- featureFlagsDebug.isEnabled(ResourceBooleanFlag(5, "5", "test", 1005))
+ featureFlagsDebug.isEnabled(ResourceBooleanFlag("5", "test", 1005))
}
}
@@ -237,30 +232,29 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
return@thenAnswer it.getArgument(1)
}
- assertThat(featureFlagsDebug.isEnabled(SysPropBooleanFlag(1, "a", "test"))).isFalse()
- assertThat(featureFlagsDebug.isEnabled(SysPropBooleanFlag(2, "b", "test"))).isTrue()
- assertThat(featureFlagsDebug.isEnabled(SysPropBooleanFlag(3, "c", "test", true))).isTrue()
+ assertThat(featureFlagsDebug.isEnabled(SysPropBooleanFlag("a", "test"))).isFalse()
+ assertThat(featureFlagsDebug.isEnabled(SysPropBooleanFlag("b", "test"))).isTrue()
+ assertThat(featureFlagsDebug.isEnabled(SysPropBooleanFlag("c", "test", true))).isTrue()
assertThat(
featureFlagsDebug.isEnabled(
SysPropBooleanFlag(
- 4,
"d",
"test",
false
)
)
).isFalse()
- assertThat(featureFlagsDebug.isEnabled(SysPropBooleanFlag(5, "e", "test"))).isFalse()
+ assertThat(featureFlagsDebug.isEnabled(SysPropBooleanFlag("e", "test"))).isFalse()
}
@Test
fun readStringFlag() {
whenever(flagManager.readFlagValue<String>(eq("3"), any())).thenReturn("foo")
whenever(flagManager.readFlagValue<String>(eq("4"), any())).thenReturn("bar")
- assertThat(featureFlagsDebug.getString(StringFlag(1, "1", "test", "biz"))).isEqualTo("biz")
- assertThat(featureFlagsDebug.getString(StringFlag(2, "2", "test", "baz"))).isEqualTo("baz")
- assertThat(featureFlagsDebug.getString(StringFlag(3, "3", "test", "buz"))).isEqualTo("foo")
- assertThat(featureFlagsDebug.getString(StringFlag(4, "4", "test", "buz"))).isEqualTo("bar")
+ assertThat(featureFlagsDebug.getString(StringFlag("1", "test", "biz"))).isEqualTo("biz")
+ assertThat(featureFlagsDebug.getString(StringFlag("2", "test", "baz"))).isEqualTo("baz")
+ assertThat(featureFlagsDebug.getString(StringFlag("3", "test", "buz"))).isEqualTo("foo")
+ assertThat(featureFlagsDebug.getString(StringFlag("4", "test", "buz"))).isEqualTo("bar")
}
@Test
@@ -279,7 +273,6 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
assertThat(
featureFlagsDebug.getString(
ResourceStringFlag(
- 1,
"1",
"test",
1001
@@ -289,7 +282,6 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
assertThat(
featureFlagsDebug.getString(
ResourceStringFlag(
- 2,
"2",
"test",
1002
@@ -299,7 +291,6 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
assertThat(
featureFlagsDebug.getString(
ResourceStringFlag(
- 3,
"3",
"test",
1003
@@ -308,15 +299,15 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
).isEqualTo("override3")
Assert.assertThrows(NullPointerException::class.java) {
- featureFlagsDebug.getString(ResourceStringFlag(4, "4", "test", 1004))
+ featureFlagsDebug.getString(ResourceStringFlag("4", "test", 1004))
}
Assert.assertThrows(NameNotFoundException::class.java) {
- featureFlagsDebug.getString(ResourceStringFlag(5, "5", "test", 1005))
+ featureFlagsDebug.getString(ResourceStringFlag("5", "test", 1005))
}
// Test that resource is loaded (and validated) even when the setting is set.
// This prevents developers from not noticing when they reference an invalid resource.
Assert.assertThrows(NameNotFoundException::class.java) {
- featureFlagsDebug.getString(ResourceStringFlag(6, "6", "test", 1005))
+ featureFlagsDebug.getString(ResourceStringFlag("6", "test", 1005))
}
}
@@ -324,10 +315,10 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
fun readIntFlag() {
whenever(flagManager.readFlagValue<Int>(eq("3"), any())).thenReturn(22)
whenever(flagManager.readFlagValue<Int>(eq("4"), any())).thenReturn(48)
- assertThat(featureFlagsDebug.getInt(IntFlag(1, "1", "test", 12))).isEqualTo(12)
- assertThat(featureFlagsDebug.getInt(IntFlag(2, "2", "test", 93))).isEqualTo(93)
- assertThat(featureFlagsDebug.getInt(IntFlag(3, "3", "test", 8))).isEqualTo(22)
- assertThat(featureFlagsDebug.getInt(IntFlag(4, "4", "test", 234))).isEqualTo(48)
+ assertThat(featureFlagsDebug.getInt(IntFlag("1", "test", 12))).isEqualTo(12)
+ assertThat(featureFlagsDebug.getInt(IntFlag("2", "test", 93))).isEqualTo(93)
+ assertThat(featureFlagsDebug.getInt(IntFlag("3", "test", 8))).isEqualTo(22)
+ assertThat(featureFlagsDebug.getInt(IntFlag("4", "test", 234))).isEqualTo(48)
}
@Test
@@ -339,30 +330,30 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
whenever(resources.getInteger(1005)).thenThrow(NotFoundException("unknown resource"))
whenever(resources.getInteger(1006)).thenThrow(NotFoundException("unknown resource"))
- whenever(flagManager.readFlagValue<Int>(eq(3), any())).thenReturn(20)
- whenever(flagManager.readFlagValue<Int>(eq(4), any())).thenReturn(500)
- whenever(flagManager.readFlagValue<Int>(eq(5), any())).thenReturn(9519)
+ whenever(flagManager.readFlagValue<Int>(eq("3"), any())).thenReturn(20)
+ whenever(flagManager.readFlagValue<Int>(eq("4"), any())).thenReturn(500)
+ whenever(flagManager.readFlagValue<Int>(eq("5"), any())).thenReturn(9519)
- assertThat(featureFlagsDebug.getInt(ResourceIntFlag(1, "1", "test", 1001))).isEqualTo(88)
- assertThat(featureFlagsDebug.getInt(ResourceIntFlag(2, "2", "test", 1002))).isEqualTo(61)
- assertThat(featureFlagsDebug.getInt(ResourceIntFlag(3, "3", "test", 1003))).isEqualTo(20)
+ assertThat(featureFlagsDebug.getInt(ResourceIntFlag("1", "test", 1001))).isEqualTo(88)
+ assertThat(featureFlagsDebug.getInt(ResourceIntFlag("2", "test", 1002))).isEqualTo(61)
+ assertThat(featureFlagsDebug.getInt(ResourceIntFlag("3", "test", 1003))).isEqualTo(20)
Assert.assertThrows(NotFoundException::class.java) {
- featureFlagsDebug.getInt(ResourceIntFlag(4, "4", "test", 1004))
+ featureFlagsDebug.getInt(ResourceIntFlag("4", "test", 1004))
}
// Test that resource is loaded (and validated) even when the setting is set.
// This prevents developers from not noticing when they reference an invalid resource.
Assert.assertThrows(NotFoundException::class.java) {
- featureFlagsDebug.getInt(ResourceIntFlag(5, "5", "test", 1005))
+ featureFlagsDebug.getInt(ResourceIntFlag("5", "test", 1005))
}
}
@Test
fun broadcastReceiver_IgnoresInvalidData() {
- addFlag(UnreleasedFlag(1, "1", "test"))
- addFlag(ResourceBooleanFlag(2, "2", "test", 1002))
- addFlag(StringFlag(3, "3", "test", "flag3"))
- addFlag(ResourceStringFlag(4, "4", "test", 1004))
+ addFlag(UnreleasedFlag("1", "test"))
+ addFlag(ResourceBooleanFlag("2", "test", 1002))
+ addFlag(StringFlag("3", "test", "flag3"))
+ addFlag(ResourceStringFlag("4", "test", 1004))
broadcastReceiver.onReceive(mockContext, null)
broadcastReceiver.onReceive(mockContext, Intent())
@@ -378,7 +369,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
@Test
fun intentWithId_NoValueKeyClears() {
- addFlag(UnreleasedFlag(1, name = "1", namespace = "test"))
+ addFlag(UnreleasedFlag(name = "1", namespace = "test"))
// trying to erase an id not in the map does nothing
broadcastReceiver.onReceive(
@@ -397,10 +388,10 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
@Test
fun setBooleanFlag() {
- addFlag(UnreleasedFlag(1, "1", "test"))
- addFlag(UnreleasedFlag(2, "2", "test"))
- addFlag(ResourceBooleanFlag(3, "3", "test", 1003))
- addFlag(ResourceBooleanFlag(4, "4", "test", 1004))
+ addFlag(UnreleasedFlag("1", "test"))
+ addFlag(UnreleasedFlag("2", "test"))
+ addFlag(ResourceBooleanFlag("3", "test", 1003))
+ addFlag(ResourceBooleanFlag("4", "test", 1004))
setByBroadcast("1", false)
verifyPutData("1", "{\"type\":\"boolean\",\"value\":false}")
@@ -417,8 +408,8 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
@Test
fun setStringFlag() {
- addFlag(StringFlag(1, "1", "1", "test"))
- addFlag(ResourceStringFlag(2, "2", "test", 1002))
+ addFlag(StringFlag("1", "1", "test"))
+ addFlag(ResourceStringFlag("2", "test", 1002))
setByBroadcast("1", "override1")
verifyPutData("1", "{\"type\":\"string\",\"value\":\"override1\"}")
@@ -429,7 +420,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
@Test
fun setFlag_ClearsCache() {
- val flag1 = addFlag(StringFlag(1, "1", "test", "flag1"))
+ val flag1 = addFlag(StringFlag("1", "test", "flag1"))
whenever(flagManager.readFlagValue<String>(eq("1"), any())).thenReturn("original")
// gets the flag & cache it
@@ -451,7 +442,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
@Test
fun serverSide_Overrides_MakesFalse() {
- val flag = ReleasedFlag(100, "100", "test")
+ val flag = ReleasedFlag("100", "test")
serverFlagReader.setFlagValue(flag.namespace, flag.name, false)
@@ -460,7 +451,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
@Test
fun serverSide_Overrides_MakesTrue() {
- val flag = UnreleasedFlag(100, name = "100", namespace = "test")
+ val flag = UnreleasedFlag(name = "100", namespace = "test")
serverFlagReader.setFlagValue(flag.namespace, flag.name, true)
assertThat(featureFlagsDebug.isEnabled(flag)).isTrue()
@@ -494,18 +485,18 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
@Test
fun dumpFormat() {
- val flag1 = ReleasedFlag(1, "1", "test")
- val flag2 = ResourceBooleanFlag(2, "2", "test", 1002)
- val flag3 = UnreleasedFlag(3, "3", "test")
- val flag4 = StringFlag(4, "4", "test", "")
- val flag5 = StringFlag(5, "5", "test", "flag5default")
- val flag6 = ResourceStringFlag(6, "6", "test", 1006)
- val flag7 = ResourceStringFlag(7, "7", "test", 1007)
+ val flag1 = ReleasedFlag("1", "test")
+ val flag2 = ResourceBooleanFlag("2", "test", 1002)
+ val flag3 = UnreleasedFlag("3", "test")
+ val flag4 = StringFlag("4", "test", "")
+ val flag5 = StringFlag("5", "test", "flag5default")
+ val flag6 = ResourceStringFlag("6", "test", 1006)
+ val flag7 = ResourceStringFlag("7", "test", 1007)
whenever(resources.getBoolean(1002)).thenReturn(true)
whenever(resources.getString(1006)).thenReturn("resource1006")
whenever(resources.getString(1007)).thenReturn("resource1007")
- whenever(flagManager.readFlagValue(eq(7), eq(StringFlagSerializer)))
+ whenever(flagManager.readFlagValue(eq("7"), eq(StringFlagSerializer)))
.thenReturn("override7")
// WHEN the flags have been accessed
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt
index 917147b17517..16b459556cb9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt
@@ -44,7 +44,7 @@ class FeatureFlagsReleaseTest : SysuiTestCase() {
private val serverFlagReader = ServerFlagReaderFake()
- private val flagA = ReleasedFlag(501, name = "a", namespace = "test")
+ private val flagA = ReleasedFlag(name = "a", namespace = "test")
@Before
fun setup() {
@@ -62,11 +62,10 @@ class FeatureFlagsReleaseTest : SysuiTestCase() {
@Test
fun testBooleanResourceFlag() {
- val flagId = 213
val flagResourceId = 3
val flagName = "213"
val flagNamespace = "test"
- val flag = ResourceBooleanFlag(flagId, flagName, flagNamespace, flagResourceId)
+ val flag = ResourceBooleanFlag(flagName, flagNamespace, flagResourceId)
whenever(mResources.getBoolean(flagResourceId)).thenReturn(true)
assertThat(featureFlagsRelease.isEnabled(flag)).isTrue()
}
@@ -79,33 +78,32 @@ class FeatureFlagsReleaseTest : SysuiTestCase() {
whenever(mResources.getString(1004)).thenAnswer { throw NameNotFoundException() }
assertThat(featureFlagsRelease.getString(
- ResourceStringFlag(1, "1", "test", 1001))).isEqualTo("")
+ ResourceStringFlag("1", "test", 1001))).isEqualTo("")
assertThat(featureFlagsRelease.getString(
- ResourceStringFlag(2, "2", "test", 1002))).isEqualTo("res2")
+ ResourceStringFlag("2", "test", 1002))).isEqualTo("res2")
assertThrows(NullPointerException::class.java) {
- featureFlagsRelease.getString(ResourceStringFlag(3, "3", "test", 1003))
+ featureFlagsRelease.getString(ResourceStringFlag("3", "test", 1003))
}
assertThrows(NameNotFoundException::class.java) {
- featureFlagsRelease.getString(ResourceStringFlag(4, "4", "test", 1004))
+ featureFlagsRelease.getString(ResourceStringFlag("4", "test", 1004))
}
}
@Test
fun testSysPropBooleanFlag() {
- val flagId = 213
val flagName = "sys_prop_flag"
val flagNamespace = "test"
val flagDefault = true
- val flag = SysPropBooleanFlag(flagId, flagName, flagNamespace, flagDefault)
+ val flag = SysPropBooleanFlag(flagName, flagNamespace, flagDefault)
whenever(mSystemProperties.getBoolean(flagName, flagDefault)).thenReturn(flagDefault)
assertThat(featureFlagsRelease.isEnabled(flag)).isEqualTo(flagDefault)
}
@Test
fun serverSide_OverridesReleased_MakesFalse() {
- val flag = ReleasedFlag(100, "100", "test")
+ val flag = ReleasedFlag("100", "test")
serverFlagReader.setFlagValue(flag.namespace, flag.name, false)
@@ -114,7 +112,7 @@ class FeatureFlagsReleaseTest : SysuiTestCase() {
@Test
fun serverSide_OverridesUnreleased_Ignored() {
- val flag = UnreleasedFlag(100, "100", "test")
+ val flag = UnreleasedFlag("100", "test")
serverFlagReader.setFlagValue(flag.namespace, flag.name, true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt
index 28131b50f04c..b02baa7fd1b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt
@@ -33,10 +33,10 @@ class FlagCommandTest : SysuiTestCase() {
@Mock private lateinit var featureFlags: FeatureFlagsDebug
@Mock private lateinit var pw: PrintWriter
private val flagMap = mutableMapOf<String, Flag<*>>()
- private val flagA = UnreleasedFlag(500, "500", "test")
- private val flagB = ReleasedFlag(501, "501", "test")
- private val stringFlag = StringFlag(502, "502", "test", "abracadabra")
- private val intFlag = IntFlag(503, "503", "test", 12)
+ private val flagA = UnreleasedFlag("500", "test")
+ private val flagB = ReleasedFlag("501", "test")
+ private val stringFlag = StringFlag("502", "test", "abracadabra")
+ private val intFlag = IntFlag("503", "test", 12)
private lateinit var cmd: FlagCommand
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt
index e679d47537b5..303aaa128378 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt
@@ -64,14 +64,14 @@ class FlagManagerTest : SysuiTestCase() {
verifyNoMoreInteractions(mFlagSettingsHelper)
// adding the first listener registers the observer
- mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener1)
+ mFlagManager.addListener(ReleasedFlag("1", "test"), listener1)
val observer = withArgCaptor<ContentObserver> {
verify(mFlagSettingsHelper).registerContentObserver(any(), any(), capture())
}
verifyNoMoreInteractions(mFlagSettingsHelper)
// adding another listener does nothing
- mFlagManager.addListener(ReleasedFlag(2, "2", "test"), listener2)
+ mFlagManager.addListener(ReleasedFlag("2", "test"), listener2)
verifyNoMoreInteractions(mFlagSettingsHelper)
// removing the original listener does nothing with second one still present
@@ -89,7 +89,7 @@ class FlagManagerTest : SysuiTestCase() {
val listener = mock<FlagListenable.Listener>()
val clearCacheAction = mock<Consumer<String>>()
mFlagManager.clearCacheAction = clearCacheAction
- mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener)
+ mFlagManager.addListener(ReleasedFlag("1", "test"), listener)
val observer = withArgCaptor<ContentObserver> {
verify(mFlagSettingsHelper).registerContentObserver(any(), any(), capture())
}
@@ -101,8 +101,8 @@ class FlagManagerTest : SysuiTestCase() {
fun testObserverInvokesListeners() {
val listener1 = mock<FlagListenable.Listener>()
val listener10 = mock<FlagListenable.Listener>()
- mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener1)
- mFlagManager.addListener(ReleasedFlag(10, "10", "test"), listener10)
+ mFlagManager.addListener(ReleasedFlag("1", "test"), listener1)
+ mFlagManager.addListener(ReleasedFlag("10", "test"), listener10)
val observer = withArgCaptor<ContentObserver> {
verify(mFlagSettingsHelper).registerContentObserver(any(), any(), capture())
}
@@ -127,8 +127,8 @@ class FlagManagerTest : SysuiTestCase() {
fun testOnlySpecificFlagListenerIsInvoked() {
val listener1 = mock<FlagListenable.Listener>()
val listener10 = mock<FlagListenable.Listener>()
- mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener1)
- mFlagManager.addListener(ReleasedFlag(10, "10", "test"), listener10)
+ mFlagManager.addListener(ReleasedFlag("1", "test"), listener1)
+ mFlagManager.addListener(ReleasedFlag("10", "test"), listener10)
mFlagManager.dispatchListenersAndMaybeRestart("1", null)
val flagEvent1 = withArgCaptor<FlagListenable.FlagEvent> {
@@ -148,8 +148,8 @@ class FlagManagerTest : SysuiTestCase() {
@Test
fun testSameListenerCanBeUsedForMultipleFlags() {
val listener = mock<FlagListenable.Listener>()
- mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener)
- mFlagManager.addListener(ReleasedFlag(10, "10", "test"), listener)
+ mFlagManager.addListener(ReleasedFlag("1", "test"), listener)
+ mFlagManager.addListener(ReleasedFlag("10", "test"), listener)
mFlagManager.dispatchListenersAndMaybeRestart("1", null)
val flagEvent1 = withArgCaptor<FlagListenable.FlagEvent> {
@@ -177,7 +177,7 @@ class FlagManagerTest : SysuiTestCase() {
@Test
fun testListenerCanSuppressRestart() {
val restartAction = mock<Consumer<Boolean>>()
- mFlagManager.addListener(ReleasedFlag(1, "1", "test")) { event ->
+ mFlagManager.addListener(ReleasedFlag("1", "test")) { event ->
event.requestNoRestart()
}
mFlagManager.dispatchListenersAndMaybeRestart("1", restartAction)
@@ -188,7 +188,7 @@ class FlagManagerTest : SysuiTestCase() {
@Test
fun testListenerOnlySuppressesRestartForOwnFlag() {
val restartAction = mock<Consumer<Boolean>>()
- mFlagManager.addListener(ReleasedFlag(10, "10", "test")) { event ->
+ mFlagManager.addListener(ReleasedFlag("10", "test")) { event ->
event.requestNoRestart()
}
mFlagManager.dispatchListenersAndMaybeRestart("1", restartAction)
@@ -199,10 +199,10 @@ class FlagManagerTest : SysuiTestCase() {
@Test
fun testRestartWhenNotAllListenersRequestSuppress() {
val restartAction = mock<Consumer<Boolean>>()
- mFlagManager.addListener(ReleasedFlag(10, "10", "test")) { event ->
+ mFlagManager.addListener(ReleasedFlag("10", "test")) { event ->
event.requestNoRestart()
}
- mFlagManager.addListener(ReleasedFlag(10, "10", "test")) {
+ mFlagManager.addListener(ReleasedFlag("10", "test")) {
// do not request
}
mFlagManager.dispatchListenersAndMaybeRestart("1", restartAction)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt
index 953b7fb32d56..1d1949d12479 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt
@@ -53,7 +53,7 @@ class ServerFlagReaderImplTest : SysuiTestCase() {
@Test
fun testChange_alertsListener() {
- val flag = ReleasedFlag(1, "flag_1", "test")
+ val flag = ReleasedFlag("flag_1", "test")
serverFlagReader.listenForChanges(listOf(flag), changeListener)
deviceConfig.setProperty(NAMESPACE, "flag_1", "1", false)
@@ -65,7 +65,7 @@ class ServerFlagReaderImplTest : SysuiTestCase() {
@Test
fun testChange_ignoresListenersDuringTest() {
val serverFlagReader = ServerFlagReaderImpl(NAMESPACE, deviceConfig, executor, true)
- val flag = ReleasedFlag(1, "1", " test")
+ val flag = ReleasedFlag("1", " test")
serverFlagReader.listenForChanges(listOf(flag), changeListener)
deviceConfig.setProperty(NAMESPACE, "flag_override_1", "1", false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 28328c2e6fae..847d58b8cd83 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -634,6 +634,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
TestableLooper.get(this).processAllMessages();
assertFalse(mViewMediator.isShowingAndNotOccluded());
+ verify(mKeyguardUnlockAnimationController).notifyFinishedKeyguardExitAnimation(false);
}
@Test
@@ -650,6 +651,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
TestableLooper.get(this).processAllMessages();
assertTrue(mViewMediator.isShowingAndNotOccluded());
+ verify(mKeyguardUnlockAnimationController).notifyFinishedKeyguardExitAnimation(true);
}
@Test
@@ -658,6 +660,9 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
startMockKeyguardExitAnimation();
cancelMockKeyguardExitAnimation();
+ // Calling cancel above results in keyguard not visible, as there is no pending lock
+ verify(mKeyguardUnlockAnimationController).notifyFinishedKeyguardExitAnimation(false);
+
mViewMediator.maybeHandlePendingLock();
TestableLooper.get(this).processAllMessages();
@@ -672,10 +677,15 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
@Test
@TestableLooper.RunWithLooper(setAsMainLooper = true)
- public void testStartKeyguardExitAnimation_expectSurfaceBehindRemoteAnimation() {
+ public void testStartKeyguardExitAnimation_expectSurfaceBehindRemoteAnimationAndExits() {
startMockKeyguardExitAnimation();
assertTrue(mViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehind());
+ mViewMediator.mViewMediatorCallback.keyguardDonePending(true,
+ mUpdateMonitor.getCurrentUser());
+ mViewMediator.mViewMediatorCallback.readyForKeyguardDone();
+ TestableLooper.get(this).processAllMessages();
+ verify(mKeyguardUnlockAnimationController).notifyFinishedKeyguardExitAnimation(false);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
index 7510373ed582..9d983b8c8943 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
@@ -137,27 +137,18 @@ class QrCodeScannerKeyguardQuickAffordanceConfigTest : SysuiTestCase() {
}
@Test
- fun getPickerScreenState_enabledIfConfiguredOnDevice_canOpenCamera() = runTest {
- whenever(controller.isAvailableOnDevice).thenReturn(true)
- whenever(controller.isAbleToOpenCameraApp).thenReturn(true)
+ fun getPickerScreenState_enabledIfConfiguredOnDevice_isEnabledForPickerState() = runTest {
+ whenever(controller.isAllowedOnLockScreen).thenReturn(true)
+ whenever(controller.isAbleToLaunchScannerActivity).thenReturn(true)
assertThat(underTest.getPickerScreenState())
.isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.Default())
}
@Test
- fun getPickerScreenState_disabledIfConfiguredOnDevice_cannotOpenCamera() = runTest {
- whenever(controller.isAvailableOnDevice).thenReturn(true)
- whenever(controller.isAbleToOpenCameraApp).thenReturn(false)
-
- assertThat(underTest.getPickerScreenState())
- .isInstanceOf(KeyguardQuickAffordanceConfig.PickerScreenState.Disabled::class.java)
- }
-
- @Test
- fun getPickerScreenState_unavailableIfNotConfiguredOnDevice() = runTest {
- whenever(controller.isAvailableOnDevice).thenReturn(false)
- whenever(controller.isAbleToOpenCameraApp).thenReturn(true)
+ fun getPickerScreenState_disabledIfConfiguredOnDevice_isDisabledForPickerState() = runTest {
+ whenever(controller.isAllowedOnLockScreen).thenReturn(true)
+ whenever(controller.isAbleToLaunchScannerActivity).thenReturn(false)
assertThat(underTest.getPickerScreenState())
.isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
index ec30732dda23..dcaafe8dd052 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
@@ -19,10 +19,10 @@ package com.android.systemui.keyguard.data.repository
import android.graphics.Point
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
-import androidx.core.animation.AnimatorTestRule
import androidx.test.filters.SmallTest
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.AnimatorTestRule
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt
deleted file mode 100644
index 86e56bf1e131..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.keyguard.domain.interactor
-
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.scene.SceneTestUtils
-import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.scene.shared.model.SceneModel
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@OptIn(ExperimentalCoroutinesApi::class)
-@SmallTest
-@RunWith(JUnit4::class)
-class LockscreenSceneInteractorTest : SysuiTestCase() {
-
- private val utils = SceneTestUtils(this)
- private val testScope = utils.testScope
- private val sceneInteractor = utils.sceneInteractor()
- private val authenticationInteractor =
- utils.authenticationInteractor(
- repository = utils.authenticationRepository(),
- )
- private val underTest =
- utils.lockScreenSceneInteractor(
- authenticationInteractor = authenticationInteractor,
- bouncerInteractor =
- utils.bouncerInteractor(
- authenticationInteractor = authenticationInteractor,
- sceneInteractor = sceneInteractor,
- ),
- )
-
- @Test
- fun isDeviceLocked() =
- testScope.runTest {
- val isDeviceLocked by collectLastValue(underTest.isDeviceLocked)
-
- utils.authenticationRepository.setUnlocked(false)
- assertThat(isDeviceLocked).isTrue()
-
- utils.authenticationRepository.setUnlocked(true)
- assertThat(isDeviceLocked).isFalse()
- }
-
- @Test
- fun isSwipeToDismissEnabled_deviceLockedAndAuthMethodSwipe_true() =
- testScope.runTest {
- val isSwipeToDismissEnabled by collectLastValue(underTest.isSwipeToDismissEnabled)
-
- utils.authenticationRepository.setUnlocked(false)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
-
- assertThat(isSwipeToDismissEnabled).isTrue()
- }
-
- @Test
- fun isSwipeToDismissEnabled_deviceUnlockedAndAuthMethodSwipe_false() =
- testScope.runTest {
- val isSwipeToDismissEnabled by collectLastValue(underTest.isSwipeToDismissEnabled)
-
- utils.authenticationRepository.setUnlocked(true)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
-
- assertThat(isSwipeToDismissEnabled).isFalse()
- }
-
- @Test
- fun dismissLockScreen_deviceLockedWithSecureAuthMethod_switchesToBouncer() =
- testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
- utils.authenticationRepository.setUnlocked(false)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
-
- underTest.dismissLockscreen()
-
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
- }
-
- @Test
- fun dismissLockScreen_deviceUnlocked_switchesToGone() =
- testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
- utils.authenticationRepository.setUnlocked(true)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
-
- underTest.dismissLockscreen()
-
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
- }
-
- @Test
- fun dismissLockScreen_deviceLockedWithInsecureAuthMethod_switchesToGone() =
- testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
- utils.authenticationRepository.setUnlocked(false)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
-
- underTest.dismissLockscreen()
-
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
- }
-
- @Test
- fun switchFromLockScreenToGone_authMethodNotSwipe_doesNotUnlockDevice() =
- testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Lockscreen), "reason")
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- assertThat(isUnlocked).isFalse()
-
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone), "reason")
-
- assertThat(isUnlocked).isFalse()
- }
-
- @Test
- fun switchFromNonLockScreenToGone_authMethodSwipe_doesNotUnlockDevice() =
- testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
- runCurrent()
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Shade), "reason")
- runCurrent()
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
- runCurrent()
- assertThat(isUnlocked).isFalse()
-
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone), "reason")
-
- assertThat(isUnlocked).isFalse()
- }
-
- @Test
- fun authMethodChangedToNone_notOnLockScreenScene_doesNotDismissLockScreen() =
- testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
- runCurrent()
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.QuickSettings), "reason")
- runCurrent()
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.QuickSettings))
-
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
-
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.QuickSettings))
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
index 66631dc9977b..addb1815cead 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
@@ -17,6 +17,8 @@
package com.android.systemui.keyguard.ui.view.layout.blueprints
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
import androidx.constraintlayout.widget.ConstraintSet
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -26,15 +28,17 @@ import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAr
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultLockIconSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultSettingsPopupMenuSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection
+import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusViewSection
+import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeGuidelines
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
-@RunWith(JUnit4::class)
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
@SmallTest
class DefaultKeyguardBlueprintTest : SysuiTestCase() {
private lateinit var underTest: DefaultKeyguardBlueprint
@@ -45,6 +49,8 @@ class DefaultKeyguardBlueprintTest : SysuiTestCase() {
@Mock
private lateinit var defaultAmbientIndicationAreaSection: DefaultAmbientIndicationAreaSection
@Mock private lateinit var defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection
+ @Mock private lateinit var defaultStatusViewSection: DefaultStatusViewSection
+ @Mock private lateinit var splitShadeGuidelines: SplitShadeGuidelines
@Before
fun setup() {
@@ -57,6 +63,8 @@ class DefaultKeyguardBlueprintTest : SysuiTestCase() {
defaultShortcutsSection,
defaultAmbientIndicationAreaSection,
defaultSettingsPopupMenuSection,
+ defaultStatusViewSection,
+ splitShadeGuidelines,
)
}
@@ -69,5 +77,7 @@ class DefaultKeyguardBlueprintTest : SysuiTestCase() {
verify(defaultShortcutsSection).apply(cs)
verify(defaultAmbientIndicationAreaSection).apply(cs)
verify(defaultSettingsPopupMenuSection).apply(cs)
+ verify(defaultStatusViewSection).apply(cs)
+ verify(splitShadeGuidelines).apply(cs)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSectionTest.kt
index 1444f8df4e4c..379c03c4353d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSectionTest.kt
@@ -25,6 +25,7 @@ import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthController
+import com.android.systemui.keyguard.ui.view.KeyguardRootView
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
index 63ee240fd2c6..45d7a5ebb60a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
@@ -19,7 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
-import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.authentication.data.model.AuthenticationMethodModel
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
@@ -49,14 +49,11 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
private val underTest =
LockscreenSceneViewModel(
applicationScope = testScope.backgroundScope,
- interactor =
- utils.lockScreenSceneInteractor(
+ authenticationInteractor = authenticationInteractor,
+ bouncerInteractor =
+ utils.bouncerInteractor(
authenticationInteractor = authenticationInteractor,
- bouncerInteractor =
- utils.bouncerInteractor(
- authenticationInteractor = authenticationInteractor,
- sceneInteractor = sceneInteractor,
- ),
+ sceneInteractor = sceneInteractor,
),
)
@@ -87,17 +84,18 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
}
@Test
- fun upTransitionSceneKey_swipeToUnlockedEnabled_gone() =
+ fun upTransitionSceneKey_swipeToUnlockEnabled_gone() =
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.authenticationRepository.setLockscreenEnabled(true)
utils.authenticationRepository.setUnlocked(false)
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone)
}
@Test
- fun upTransitionSceneKey_swipeToUnlockedNotEnabled_bouncer() =
+ fun upTransitionSceneKey_swipeToUnlockNotEnabled_bouncer() =
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
@@ -109,7 +107,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
@Test
fun onLockButtonClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
runCurrent()
@@ -122,7 +120,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
@Test
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
runCurrent()
@@ -135,7 +133,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
@Test
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
runCurrent()
@@ -148,7 +146,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
@Test
fun onLockButtonClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index ab24c46825e4..db00e0927886 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -278,6 +278,21 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
}
@Test
+ public void
+ whenNotBroadcasting_verifyLeBroadcastServiceCallBackIsUnregisteredIfProfileEnabled() {
+ when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
+ mLocalBluetoothLeBroadcast);
+ mIsBroadcasting = true;
+
+ mMediaOutputBaseDialogImpl.start();
+ verify(mLocalBluetoothLeBroadcast).registerServiceCallBack(any(), any());
+
+ mIsBroadcasting = false;
+ mMediaOutputBaseDialogImpl.stop();
+ verify(mLocalBluetoothLeBroadcast).unregisterServiceCallBack(any());
+ }
+
+ @Test
public void refresh_checkStopText() {
mStopText = "test_string";
mMediaOutputBaseDialogImpl.refresh();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index 3e69a29bd963..bfc8c83c1c2a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -256,6 +256,30 @@ public class MediaOutputDialogTest extends SysuiTestCase {
}
@Test
+ public void isBroadcastSupported_noBleDeviceAndEnabledBroadcast_returnsTrue() {
+ when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
+ mLocalBluetoothLeBroadcast);
+ when(mLocalBluetoothLeBroadcast.isEnabled(any())).thenReturn(true);
+ FeatureFlagUtils.setEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true);
+ when(mMediaDevice.isBLEDevice()).thenReturn(false);
+
+ assertThat(mMediaOutputDialog.isBroadcastSupported()).isTrue();
+ }
+
+ @Test
+ public void isBroadcastSupported_noBleDeviceAndDisabledBroadcast_returnsFalse() {
+ when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
+ mLocalBluetoothLeBroadcast);
+ when(mLocalBluetoothLeBroadcast.isEnabled(any())).thenReturn(false);
+ FeatureFlagUtils.setEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true);
+ when(mMediaDevice.isBLEDevice()).thenReturn(false);
+
+ assertThat(mMediaOutputDialog.isBroadcastSupported()).isFalse();
+ }
+
+ @Test
public void getBroadcastIconVisibility_isBroadcasting_returnVisible() {
when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
mLocalBluetoothLeBroadcast);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerControllerTest.java
index 65210d63e5c5..e905e9cad459 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qrcodescanner/controller/QRCodeScannerControllerTest.java
@@ -132,7 +132,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true);
verifyActivityDetails(null);
assertThat(mController.isEnabledForLockScreenButton()).isFalse();
- assertThat(mController.isAbleToOpenCameraApp()).isFalse();
+ assertThat(mController.isAbleToLaunchScannerActivity()).isFalse();
}
@Test
@@ -151,7 +151,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true);
verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
- assertThat(mController.isAbleToOpenCameraApp()).isTrue();
+ assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
}
@Test
@@ -161,7 +161,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true);
verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
- assertThat(mController.isAbleToOpenCameraApp()).isTrue();
+ assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
}
@Test
@@ -171,7 +171,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true);
verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
- assertThat(mController.isAbleToOpenCameraApp()).isTrue();
+ assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
}
@Test
@@ -181,7 +181,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true);
verifyActivityDetails("abc/abc.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
- assertThat(mController.isAbleToOpenCameraApp()).isTrue();
+ assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
}
@Test
@@ -191,7 +191,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true);
verifyActivityDetails(null);
assertThat(mController.isEnabledForLockScreenButton()).isFalse();
- assertThat(mController.isAbleToOpenCameraApp()).isFalse();
+ assertThat(mController.isAbleToLaunchScannerActivity()).isFalse();
}
@Test
@@ -201,24 +201,24 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true);
verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
- assertThat(mController.isAbleToOpenCameraApp()).isTrue();
+ assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
mProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.DEFAULT_QR_CODE_SCANNER,
"def/.ijk", false);
verifyActivityDetails("def/.ijk");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
- assertThat(mController.isAbleToOpenCameraApp()).isTrue();
+ assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
mProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.DEFAULT_QR_CODE_SCANNER,
null, false);
verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
- assertThat(mController.isAbleToOpenCameraApp()).isTrue();
+ assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
- // Once from setup + twice from this function
- verify(mCallback, times(3)).onQRCodeScannerActivityChanged();
+ // twice from this function
+ verify(mCallback, times(2)).onQRCodeScannerActivityChanged();
}
@Test
@@ -228,7 +228,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true);
verifyActivityDetails(null);
assertThat(mController.isEnabledForLockScreenButton()).isFalse();
- assertThat(mController.isAbleToOpenCameraApp()).isFalse();
+ assertThat(mController.isAbleToLaunchScannerActivity()).isFalse();
mProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.DEFAULT_QR_CODE_SCANNER,
@@ -236,14 +236,14 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
verifyActivityDetails("def/.ijk");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
- assertThat(mController.isAbleToOpenCameraApp()).isTrue();
+ assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
mProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.DEFAULT_QR_CODE_SCANNER,
null, false);
verifyActivityDetails(null);
assertThat(mController.isEnabledForLockScreenButton()).isFalse();
- assertThat(mController.isAbleToOpenCameraApp()).isFalse();
+ assertThat(mController.isAbleToLaunchScannerActivity()).isFalse();
verify(mCallback, times(2)).onQRCodeScannerActivityChanged();
}
@@ -295,19 +295,20 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true);
verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
- assertThat(mController.isAbleToOpenCameraApp()).isTrue();
+ assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
mSecureSettings.putStringForUser(LOCK_SCREEN_SHOW_QR_CODE_SCANNER, "0",
UserHandle.USER_CURRENT);
verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isFalse();
- assertThat(mController.isAbleToOpenCameraApp()).isTrue();
+ assertThat(mController.isAllowedOnLockScreen()).isTrue();
+ assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
mSecureSettings.putStringForUser(LOCK_SCREEN_SHOW_QR_CODE_SCANNER, "1",
UserHandle.USER_CURRENT);
verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
- assertThat(mController.isAbleToOpenCameraApp()).isTrue();
+ assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
// Once from setup + twice from this function
verify(mCallback, times(3)).onQRCodeScannerPreferenceChanged();
}
@@ -319,13 +320,13 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ true);
verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
- assertThat(mController.isAbleToOpenCameraApp()).isTrue();
+ assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
+ // even if unregistered, intent and activity details are retained
mController.unregisterQRCodeScannerChangeObservers(DEFAULT_QR_CODE_SCANNER_CHANGE,
QR_CODE_SCANNER_PREFERENCE_CHANGE);
- verifyActivityDetails(null);
- assertThat(mController.isEnabledForLockScreenButton()).isFalse();
- assertThat(mController.isAbleToOpenCameraApp()).isFalse();
+ assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
+ assertThat(mController.isAllowedOnLockScreen()).isTrue();
// Unregister once again and make sure it affects the next register event
mController.unregisterQRCodeScannerChangeObservers(DEFAULT_QR_CODE_SCANNER_CHANGE,
@@ -334,7 +335,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
QR_CODE_SCANNER_PREFERENCE_CHANGE);
verifyActivityDetails("abc/.def");
assertThat(mController.isEnabledForLockScreenButton()).isTrue();
- assertThat(mController.isAbleToOpenCameraApp()).isTrue();
+ assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
}
@Test
@@ -344,7 +345,7 @@ public class QRCodeScannerControllerTest extends SysuiTestCase {
/* enableOnLockScreen */ false);
assertThat(mController.getIntent()).isNotNull();
assertThat(mController.isEnabledForLockScreenButton()).isFalse();
- assertThat(mController.isAbleToOpenCameraApp()).isTrue();
+ assertThat(mController.isAbleToLaunchScannerActivity()).isTrue();
assertThat(getSettingsQRCodeDefaultComponent()).isNull();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java
index 6f2d904dda64..71aa7a8d0015 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java
@@ -117,7 +117,7 @@ public class QRCodeScannerTileTest extends SysuiTestCase {
@Test
public void testQRCodeTileUnavailable() {
- when(mController.isAbleToOpenCameraApp()).thenReturn(false);
+ when(mController.isAbleToLaunchScannerActivity()).thenReturn(false);
QSTile.State state = new QSTile.State();
mTile.handleUpdateState(state, null);
assertEquals(state.state, Tile.STATE_UNAVAILABLE);
@@ -127,7 +127,7 @@ public class QRCodeScannerTileTest extends SysuiTestCase {
@Test
public void testQRCodeTileAvailable() {
- when(mController.isAbleToOpenCameraApp()).thenReturn(true);
+ when(mController.isAbleToLaunchScannerActivity()).thenReturn(true);
QSTile.State state = new QSTile.State();
mTile.handleUpdateState(state, null);
assertEquals(state.state, Tile.STATE_INACTIVE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
index ee42a7011264..2cb02058ab03 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
@@ -18,7 +18,7 @@ package com.android.systemui.qs.ui.viewmodel
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.authentication.data.model.AuthenticationMethodModel
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.SceneKey
@@ -46,21 +46,17 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
private val underTest =
QuickSettingsSceneViewModel(
- lockscreenSceneInteractor =
- utils.lockScreenSceneInteractor(
+ bouncerInteractor =
+ utils.bouncerInteractor(
authenticationInteractor = authenticationInteractor,
- bouncerInteractor =
- utils.bouncerInteractor(
- authenticationInteractor = authenticationInteractor,
- sceneInteractor = sceneInteractor,
- ),
+ sceneInteractor = sceneInteractor,
),
)
@Test
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
runCurrent()
@@ -73,7 +69,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
@Test
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
index 56e3e9649fe7..181f8a7e3003 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
@@ -25,7 +25,6 @@ import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
-import com.android.systemui.scene.shared.model.SceneTransitionModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
@@ -39,6 +38,7 @@ import org.junit.runners.JUnit4
class SceneContainerRepositoryTest : SysuiTestCase() {
private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
@Test
fun allSceneKeys() {
@@ -56,97 +56,82 @@ class SceneContainerRepositoryTest : SysuiTestCase() {
}
@Test
- fun currentScene() = runTest {
- val underTest = utils.fakeSceneContainerRepository()
- val currentScene by collectLastValue(underTest.currentScene)
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
+ fun desiredScene() =
+ testScope.runTest {
+ val underTest = utils.fakeSceneContainerRepository()
+ val currentScene by collectLastValue(underTest.desiredScene)
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
- underTest.setCurrentScene(SceneModel(SceneKey.Shade))
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade))
- }
+ underTest.setDesiredScene(SceneModel(SceneKey.Shade))
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade))
+ }
@Test(expected = IllegalStateException::class)
- fun setCurrentScene_noSuchSceneInContainer_throws() {
+ fun setDesiredScene_noSuchSceneInContainer_throws() {
val underTest =
utils.fakeSceneContainerRepository(
utils.fakeSceneContainerConfig(listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)),
)
- underTest.setCurrentScene(SceneModel(SceneKey.Shade))
+ underTest.setDesiredScene(SceneModel(SceneKey.Shade))
}
@Test
- fun isVisible() = runTest {
- val underTest = utils.fakeSceneContainerRepository()
- val isVisible by collectLastValue(underTest.isVisible)
- assertThat(isVisible).isTrue()
+ fun isVisible() =
+ testScope.runTest {
+ val underTest = utils.fakeSceneContainerRepository()
+ val isVisible by collectLastValue(underTest.isVisible)
+ assertThat(isVisible).isTrue()
- underTest.setVisible(false)
- assertThat(isVisible).isFalse()
+ underTest.setVisible(false)
+ assertThat(isVisible).isFalse()
- underTest.setVisible(true)
- assertThat(isVisible).isTrue()
- }
+ underTest.setVisible(true)
+ assertThat(isVisible).isTrue()
+ }
@Test
- fun transitionProgress() = runTest {
- val underTest = utils.fakeSceneContainerRepository()
- val sceneTransitionProgress by collectLastValue(underTest.transitionProgress)
- assertThat(sceneTransitionProgress).isEqualTo(1f)
-
- val transitionState =
- MutableStateFlow<ObservableTransitionState>(
- ObservableTransitionState.Idle(SceneKey.Lockscreen)
- )
- underTest.setTransitionState(transitionState)
- assertThat(sceneTransitionProgress).isEqualTo(1f)
-
- val progress = MutableStateFlow(1f)
- transitionState.value =
- ObservableTransitionState.Transition(
- fromScene = SceneKey.Lockscreen,
- toScene = SceneKey.Shade,
- progress = progress,
- )
- assertThat(sceneTransitionProgress).isEqualTo(1f)
-
- progress.value = 0.1f
- assertThat(sceneTransitionProgress).isEqualTo(0.1f)
-
- progress.value = 0.9f
- assertThat(sceneTransitionProgress).isEqualTo(0.9f)
-
- underTest.setTransitionState(null)
- assertThat(sceneTransitionProgress).isEqualTo(1f)
- }
+ fun transitionState_defaultsToIdle() =
+ testScope.runTest {
+ val underTest = utils.fakeSceneContainerRepository()
+ val transitionState by collectLastValue(underTest.transitionState)
+
+ assertThat(transitionState)
+ .isEqualTo(
+ ObservableTransitionState.Idle(utils.fakeSceneContainerConfig().initialSceneKey)
+ )
+ }
@Test
- fun setSceneTransition() = runTest {
- val underTest = utils.fakeSceneContainerRepository()
- val sceneTransition by collectLastValue(underTest.transitions)
- assertThat(sceneTransition).isNull()
+ fun transitionState_reflectsUpdates() =
+ testScope.runTest {
+ val underTest = utils.fakeSceneContainerRepository()
+ val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(SceneKey.Lockscreen)
+ )
+ underTest.setTransitionState(transitionState)
+ val reflectedTransitionState by collectLastValue(underTest.transitionState)
+ assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
+
+ val progress = MutableStateFlow(1f)
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = SceneKey.Lockscreen,
+ toScene = SceneKey.Shade,
+ progress = progress,
+ )
+ assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
- underTest.setSceneTransition(SceneKey.Lockscreen, SceneKey.QuickSettings)
- assertThat(sceneTransition)
- .isEqualTo(
- SceneTransitionModel(from = SceneKey.Lockscreen, to = SceneKey.QuickSettings)
- )
- }
+ progress.value = 0.1f
+ assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
- @Test(expected = IllegalStateException::class)
- fun setSceneTransition_noFromSceneInContainer_throws() {
- val underTest =
- utils.fakeSceneContainerRepository(
- utils.fakeSceneContainerConfig(listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)),
- )
- underTest.setSceneTransition(SceneKey.Shade, SceneKey.Lockscreen)
- }
+ progress.value = 0.9f
+ assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
- @Test(expected = IllegalStateException::class)
- fun setSceneTransition_noToSceneInContainer_throws() {
- val underTest =
- utils.fakeSceneContainerRepository(
- utils.fakeSceneContainerConfig(listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)),
- )
- underTest.setSceneTransition(SceneKey.Shade, SceneKey.Lockscreen)
- }
+ underTest.setTransitionState(null)
+ assertThat(reflectedTransitionState)
+ .isEqualTo(
+ ObservableTransitionState.Idle(utils.fakeSceneContainerConfig().initialSceneKey)
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index 4facc7a6a36d..0a93a7ca465f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -25,10 +25,12 @@ import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
-import com.android.systemui.scene.shared.model.SceneTransitionModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
@@ -39,6 +41,7 @@ import org.junit.runners.JUnit4
class SceneInteractorTest : SysuiTestCase() {
private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val repository = utils.fakeSceneContainerRepository()
private val underTest = utils.sceneInteractor(repository = repository)
@@ -48,77 +51,156 @@ class SceneInteractorTest : SysuiTestCase() {
}
@Test
- fun currentScene() = runTest {
- val currentScene by collectLastValue(underTest.currentScene)
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
+ fun changeScene() =
+ testScope.runTest {
+ val desiredScene by collectLastValue(underTest.desiredScene)
+ assertThat(desiredScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
- underTest.setCurrentScene(SceneModel(SceneKey.Shade), "reason")
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade))
- }
+ underTest.changeScene(SceneModel(SceneKey.Shade), "reason")
+ assertThat(desiredScene).isEqualTo(SceneModel(SceneKey.Shade))
+ }
+
+ @Test
+ fun onSceneChanged() =
+ testScope.runTest {
+ val desiredScene by collectLastValue(underTest.desiredScene)
+ assertThat(desiredScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
+
+ underTest.onSceneChanged(SceneModel(SceneKey.Shade), "reason")
+ assertThat(desiredScene).isEqualTo(SceneModel(SceneKey.Shade))
+ }
@Test
- fun sceneTransitionProgress() = runTest {
- val transitionProgress by collectLastValue(underTest.transitionProgress)
- assertThat(transitionProgress).isEqualTo(1f)
+ fun transitionState() =
+ testScope.runTest {
+ val underTest = utils.fakeSceneContainerRepository()
+ val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(SceneKey.Lockscreen)
+ )
+ underTest.setTransitionState(transitionState)
+ val reflectedTransitionState by collectLastValue(underTest.transitionState)
+ assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
- val progress = MutableStateFlow(0.55f)
- repository.setTransitionState(
- MutableStateFlow(
+ val progress = MutableStateFlow(1f)
+ transitionState.value =
ObservableTransitionState.Transition(
fromScene = SceneKey.Lockscreen,
toScene = SceneKey.Shade,
progress = progress,
- ),
- )
- )
- assertThat(transitionProgress).isEqualTo(0.55f)
- }
+ )
+ assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
+
+ progress.value = 0.1f
+ assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
+
+ progress.value = 0.9f
+ assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
+
+ underTest.setTransitionState(null)
+ assertThat(reflectedTransitionState)
+ .isEqualTo(
+ ObservableTransitionState.Idle(utils.fakeSceneContainerConfig().initialSceneKey)
+ )
+ }
@Test
- fun isVisible() = runTest {
- val isVisible by collectLastValue(underTest.isVisible)
- assertThat(isVisible).isTrue()
+ fun isVisible() =
+ testScope.runTest {
+ val isVisible by collectLastValue(underTest.isVisible)
+ assertThat(isVisible).isTrue()
- underTest.setVisible(false, "reason")
- assertThat(isVisible).isFalse()
+ underTest.setVisible(false, "reason")
+ assertThat(isVisible).isFalse()
- underTest.setVisible(true, "reason")
- assertThat(isVisible).isTrue()
- }
+ underTest.setVisible(true, "reason")
+ assertThat(isVisible).isTrue()
+ }
@Test
- fun sceneTransitions() = runTest {
- val transitions by collectLastValue(underTest.transitions)
- assertThat(transitions).isNull()
-
- val initialSceneKey = underTest.currentScene.value.key
- underTest.setCurrentScene(SceneModel(SceneKey.Shade), "reason")
- assertThat(transitions)
- .isEqualTo(
- SceneTransitionModel(
- from = initialSceneKey,
- to = SceneKey.Shade,
+ fun finishedSceneTransitions() =
+ testScope.runTest {
+ val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(SceneKey.Lockscreen)
)
- )
-
- underTest.setCurrentScene(SceneModel(SceneKey.QuickSettings), "reason")
- assertThat(transitions)
- .isEqualTo(
- SceneTransitionModel(
- from = SceneKey.Shade,
- to = SceneKey.QuickSettings,
+ underTest.setTransitionState(transitionState)
+ var transitionCount = 0
+ val job = launch {
+ underTest
+ .finishedSceneTransitions(
+ from = SceneKey.Shade,
+ to = SceneKey.QuickSettings,
+ )
+ .collect { transitionCount++ }
+ }
+
+ assertThat(transitionCount).isEqualTo(0)
+
+ underTest.changeScene(SceneModel(SceneKey.Shade), "reason")
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = SceneKey.Lockscreen,
+ toScene = SceneKey.Shade,
+ progress = flowOf(0.5f),
)
- )
- }
+ runCurrent()
+ underTest.onSceneChanged(SceneModel(SceneKey.Shade), "reason")
+ transitionState.value = ObservableTransitionState.Idle(SceneKey.Shade)
+ runCurrent()
+ assertThat(transitionCount).isEqualTo(0)
+
+ underTest.changeScene(SceneModel(SceneKey.QuickSettings), "reason")
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = SceneKey.Shade,
+ toScene = SceneKey.QuickSettings,
+ progress = flowOf(0.5f),
+ )
+ runCurrent()
+ underTest.onSceneChanged(SceneModel(SceneKey.QuickSettings), "reason")
+ transitionState.value = ObservableTransitionState.Idle(SceneKey.QuickSettings)
+ runCurrent()
+ assertThat(transitionCount).isEqualTo(1)
+
+ underTest.changeScene(SceneModel(SceneKey.Shade), "reason")
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = SceneKey.QuickSettings,
+ toScene = SceneKey.Shade,
+ progress = flowOf(0.5f),
+ )
+ runCurrent()
+ underTest.onSceneChanged(SceneModel(SceneKey.Shade), "reason")
+ transitionState.value = ObservableTransitionState.Idle(SceneKey.Shade)
+ runCurrent()
+ assertThat(transitionCount).isEqualTo(1)
+
+ underTest.changeScene(SceneModel(SceneKey.QuickSettings), "reason")
+ transitionState.value =
+ ObservableTransitionState.Transition(
+ fromScene = SceneKey.Shade,
+ toScene = SceneKey.QuickSettings,
+ progress = flowOf(0.5f),
+ )
+ runCurrent()
+ underTest.onSceneChanged(SceneModel(SceneKey.QuickSettings), "reason")
+ transitionState.value = ObservableTransitionState.Idle(SceneKey.QuickSettings)
+ runCurrent()
+ assertThat(transitionCount).isEqualTo(2)
- @Test
- fun remoteUserInput() = runTest {
- val remoteUserInput by collectLastValue(underTest.remoteUserInput)
- assertThat(remoteUserInput).isNull()
+ job.cancel()
+ }
- for (input in SceneTestUtils.REMOTE_INPUT_DOWN_GESTURE) {
- underTest.onRemoteUserInput(input)
- assertThat(remoteUserInput).isEqualTo(input)
+ @Test
+ fun remoteUserInput() =
+ testScope.runTest {
+ val remoteUserInput by collectLastValue(underTest.remoteUserInput)
+ assertThat(remoteUserInput).isNull()
+
+ for (input in SceneTestUtils.REMOTE_INPUT_DOWN_GESTURE) {
+ underTest.onRemoteUserInput(input)
+ assertThat(remoteUserInput).isEqualTo(input)
+ }
}
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index 6be19b99dd3b..45db7a0b17f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -21,6 +21,7 @@ package com.android.systemui.scene.domain.startable
import android.view.Display
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.model.AuthenticationMethodModel
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.shared.model.WakeSleepReason
@@ -28,15 +29,17 @@ import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.model.SysUiState
import com.android.systemui.scene.SceneTestUtils
+import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -76,59 +79,86 @@ class SceneContainerStartableTest : SysuiTestCase() {
sceneLogger = mock(),
)
- @Before
- fun setUp() {
- prepareState()
- }
-
@Test
fun hydrateVisibility_featureEnabled() =
testScope.runTest {
- val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
+ val currentDesiredSceneKey by
+ collectLastValue(sceneInteractor.desiredScene.map { it.key })
val isVisible by collectLastValue(sceneInteractor.isVisible)
- prepareState(
- isFeatureEnabled = true,
- isDeviceUnlocked = true,
- initialSceneKey = SceneKey.Gone,
- )
- assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
+ val transitionStateFlow =
+ prepareState(
+ isFeatureEnabled = true,
+ isDeviceUnlocked = true,
+ initialSceneKey = SceneKey.Gone,
+ )
+ assertThat(currentDesiredSceneKey).isEqualTo(SceneKey.Gone)
assertThat(isVisible).isTrue()
underTest.start()
-
assertThat(isVisible).isFalse()
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Shade), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Shade), "reason")
+ transitionStateFlow.value =
+ ObservableTransitionState.Transition(
+ fromScene = SceneKey.Gone,
+ toScene = SceneKey.Shade,
+ progress = flowOf(0.5f),
+ )
+ assertThat(isVisible).isTrue()
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Shade), "reason")
+ transitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Shade)
+ assertThat(isVisible).isTrue()
+
+ sceneInteractor.changeScene(SceneModel(SceneKey.Gone), "reason")
+ transitionStateFlow.value =
+ ObservableTransitionState.Transition(
+ fromScene = SceneKey.Shade,
+ toScene = SceneKey.Gone,
+ progress = flowOf(0.5f),
+ )
assertThat(isVisible).isTrue()
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone), "reason")
+ transitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Gone)
+ assertThat(isVisible).isFalse()
}
@Test
fun hydrateVisibility_featureDisabled() =
testScope.runTest {
- val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
+ val currentDesiredSceneKey by
+ collectLastValue(sceneInteractor.desiredScene.map { it.key })
val isVisible by collectLastValue(sceneInteractor.isVisible)
- prepareState(
- isFeatureEnabled = false,
- isDeviceUnlocked = true,
- initialSceneKey = SceneKey.Lockscreen,
- )
- assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+ val transitionStateFlow =
+ prepareState(
+ isFeatureEnabled = false,
+ isDeviceUnlocked = true,
+ initialSceneKey = SceneKey.Gone,
+ )
+ assertThat(currentDesiredSceneKey).isEqualTo(SceneKey.Gone)
assertThat(isVisible).isTrue()
underTest.start()
+
assertThat(isVisible).isTrue()
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Gone), "reason")
+ sceneInteractor.changeScene(SceneModel(SceneKey.Shade), "reason")
+ transitionStateFlow.value =
+ ObservableTransitionState.Transition(
+ fromScene = SceneKey.Gone,
+ toScene = SceneKey.Shade,
+ progress = flowOf(0.5f),
+ )
assertThat(isVisible).isTrue()
- sceneInteractor.setCurrentScene(SceneModel(SceneKey.Shade), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Shade), "reason")
+ transitionStateFlow.value = ObservableTransitionState.Idle(SceneKey.Shade)
assertThat(isVisible).isTrue()
}
@Test
fun switchToLockscreenWhenDeviceLocks_featureEnabled() =
testScope.runTest {
- val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
+ val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = true,
isDeviceUnlocked = true,
@@ -145,7 +175,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchToLockscreenWhenDeviceLocks_featureDisabled() =
testScope.runTest {
- val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
+ val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = false,
isDeviceUnlocked = false,
@@ -162,7 +192,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchFromBouncerToGoneWhenDeviceUnlocked_featureEnabled() =
testScope.runTest {
- val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
+ val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = true,
isDeviceUnlocked = false,
@@ -179,7 +209,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchFromBouncerToGoneWhenDeviceUnlocked_featureDisabled() =
testScope.runTest {
- val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
+ val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = false,
isDeviceUnlocked = false,
@@ -196,7 +226,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchFromLockscreenToGoneWhenDeviceUnlocksWithBypassOn_featureOn_bypassOn() =
testScope.runTest {
- val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
+ val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = true,
isBypassEnabled = true,
@@ -213,7 +243,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchFromLockscreenToGoneWhenDeviceUnlocksWithBypassOn_featureOn_bypassOff() =
testScope.runTest {
- val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
+ val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = true,
isBypassEnabled = false,
@@ -230,7 +260,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchFromLockscreenToGoneWhenDeviceUnlocksWithBypassOn_featureOff_bypassOn() =
testScope.runTest {
- val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
+ val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = false,
isBypassEnabled = true,
@@ -245,43 +275,9 @@ class SceneContainerStartableTest : SysuiTestCase() {
}
@Test
- fun switchToGoneWhenDeviceSleepsUnlocked_featureEnabled() =
- testScope.runTest {
- val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
- prepareState(
- isFeatureEnabled = true,
- isDeviceUnlocked = true,
- initialSceneKey = SceneKey.Shade,
- )
- assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
- underTest.start()
-
- keyguardRepository.setWakefulnessModel(ASLEEP)
-
- assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
- }
-
- @Test
- fun switchToGoneWhenDeviceSleepsUnlocked_featureDisabled() =
- testScope.runTest {
- val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
- prepareState(
- isFeatureEnabled = false,
- isDeviceUnlocked = true,
- initialSceneKey = SceneKey.Shade,
- )
- assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
- underTest.start()
-
- keyguardRepository.setWakefulnessModel(ASLEEP)
-
- assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
- }
-
- @Test
fun switchToLockscreenWhenDeviceSleepsLocked_featureEnabled() =
testScope.runTest {
- val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
+ val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = true,
isDeviceUnlocked = false,
@@ -290,7 +286,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
underTest.start()
- keyguardRepository.setWakefulnessModel(ASLEEP)
+ keyguardRepository.setWakefulnessModel(STARTING_TO_SLEEP)
assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
}
@@ -298,7 +294,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun switchToLockscreenWhenDeviceSleepsLocked_featureDisabled() =
testScope.runTest {
- val currentSceneKey by collectLastValue(sceneInteractor.currentScene.map { it.key })
+ val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
prepareState(
isFeatureEnabled = false,
isDeviceUnlocked = false,
@@ -307,7 +303,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
underTest.start()
- keyguardRepository.setWakefulnessModel(ASLEEP)
+ keyguardRepository.setWakefulnessModel(STARTING_TO_SLEEP)
assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
}
@@ -315,6 +311,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
@Test
fun hydrateSystemUiState() =
testScope.runTest {
+ val transitionStateFlow = prepareState()
underTest.start()
runCurrent()
clearInvocations(sysUiState)
@@ -327,29 +324,110 @@ class SceneContainerStartableTest : SysuiTestCase() {
SceneKey.QuickSettings,
)
.forEachIndexed { index, sceneKey ->
- sceneInteractor.setCurrentScene(SceneModel(sceneKey), "reason")
+ sceneInteractor.changeScene(SceneModel(sceneKey), "reason")
+ runCurrent()
+ verify(sysUiState, times(index)).commitUpdate(Display.DEFAULT_DISPLAY)
+
+ sceneInteractor.onSceneChanged(SceneModel(sceneKey), "reason")
runCurrent()
+ verify(sysUiState, times(index)).commitUpdate(Display.DEFAULT_DISPLAY)
+ transitionStateFlow.value = ObservableTransitionState.Idle(sceneKey)
+ runCurrent()
verify(sysUiState, times(index + 1)).commitUpdate(Display.DEFAULT_DISPLAY)
}
}
+ @Test
+ fun switchToGoneWhenDeviceStartsToWakeUp_authMethodNone_featureEnabled() =
+ testScope.runTest {
+ val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
+ prepareState(
+ isFeatureEnabled = true,
+ initialSceneKey = SceneKey.Lockscreen,
+ authenticationMethod = AuthenticationMethodModel.None,
+ )
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+ underTest.start()
+
+ keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE)
+
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
+ }
+
+ @Test
+ fun switchToGoneWhenDeviceStartsToWakeUp_authMethodNotNone_featureEnabled() =
+ testScope.runTest {
+ val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
+ prepareState(
+ isFeatureEnabled = true,
+ initialSceneKey = SceneKey.Lockscreen,
+ authenticationMethod = AuthenticationMethodModel.Pin,
+ )
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+ underTest.start()
+
+ keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE)
+
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+ }
+
+ @Test
+ fun switchToGoneWhenDeviceStartsToWakeUp_authMethodNone_featureDisabled() =
+ testScope.runTest {
+ val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
+ prepareState(
+ isFeatureEnabled = false,
+ initialSceneKey = SceneKey.Lockscreen,
+ authenticationMethod = AuthenticationMethodModel.None,
+ )
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+ underTest.start()
+
+ keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE)
+
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+ }
+
private fun prepareState(
isFeatureEnabled: Boolean = true,
isDeviceUnlocked: Boolean = false,
isBypassEnabled: Boolean = false,
initialSceneKey: SceneKey? = null,
- ) {
+ authenticationMethod: AuthenticationMethodModel? = null,
+ ): MutableStateFlow<ObservableTransitionState> {
featureFlags.set(Flags.SCENE_CONTAINER, isFeatureEnabled)
authenticationRepository.setUnlocked(isDeviceUnlocked)
keyguardRepository.setBypassEnabled(isBypassEnabled)
- initialSceneKey?.let { sceneInteractor.setCurrentScene(SceneModel(it), "reason") }
+ val transitionStateFlow =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(SceneKey.Lockscreen)
+ )
+ sceneInteractor.setTransitionState(transitionStateFlow)
+ initialSceneKey?.let {
+ transitionStateFlow.value = ObservableTransitionState.Idle(it)
+ sceneInteractor.changeScene(SceneModel(it), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(it), "reason")
+ }
+ authenticationMethod?.let {
+ authenticationRepository.setAuthenticationMethod(authenticationMethod)
+ authenticationRepository.setLockscreenEnabled(
+ authenticationMethod != AuthenticationMethodModel.None
+ )
+ }
+ return transitionStateFlow
}
companion object {
- private val ASLEEP =
+ private val STARTING_TO_SLEEP =
+ WakefulnessModel(
+ state = WakefulnessState.STARTING_TO_SLEEP,
+ lastWakeReason = WakeSleepReason.POWER_BUTTON,
+ lastSleepReason = WakeSleepReason.POWER_BUTTON
+ )
+ private val STARTING_TO_WAKE =
WakefulnessModel(
- state = WakefulnessState.ASLEEP,
+ state = WakefulnessState.STARTING_TO_WAKE,
lastWakeReason = WakeSleepReason.POWER_BUTTON,
lastSleepReason = WakeSleepReason.POWER_BUTTON
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
index 9f3b12bd2042..da6c42694666 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
@@ -69,7 +69,8 @@ class SceneContainerViewModelTest : SysuiTestCase() {
val currentScene by collectLastValue(underTest.currentScene)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
- underTest.setCurrentScene(SceneModel(SceneKey.Shade))
+ underTest.onSceneChanged(SceneModel(SceneKey.Shade))
+
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade))
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt
index 7ba2cf7f6374..2d3ee0e5cff9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt
@@ -20,12 +20,13 @@ import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.net.Uri
+import androidx.test.ext.truth.content.IntentSubject.assertThat
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
-import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
import org.junit.Test
import org.mockito.Mockito.`when` as whenever
@@ -33,113 +34,132 @@ import org.mockito.Mockito.`when` as whenever
class ActionIntentCreatorTest : SysuiTestCase() {
@Test
- fun testCreateShareIntent() {
+ fun testCreateShare() {
val uri = Uri.parse("content://fake")
- val output = ActionIntentCreator.createShareIntent(uri)
+ val output = ActionIntentCreator.createShare(uri)
- assertThat(output.action).isEqualTo(Intent.ACTION_CHOOSER)
- assertFlagsSet(
- Intent.FLAG_ACTIVITY_NEW_TASK or
- Intent.FLAG_ACTIVITY_CLEAR_TASK or
- Intent.FLAG_GRANT_READ_URI_PERMISSION,
- output.flags
- )
+ assertThat(output).hasAction(Intent.ACTION_CHOOSER)
+ assertThat(output)
+ .hasFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK or
+ Intent.FLAG_ACTIVITY_CLEAR_TASK or
+ Intent.FLAG_GRANT_READ_URI_PERMISSION
+ )
+ assertThat(output).extras().parcelable<Intent>(Intent.EXTRA_INTENT).isNotNull()
val wrappedIntent = output.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
- assertThat(wrappedIntent?.action).isEqualTo(Intent.ACTION_SEND)
- assertThat(wrappedIntent?.data).isEqualTo(uri)
- assertThat(wrappedIntent?.type).isEqualTo("image/png")
- assertThat(wrappedIntent?.getStringExtra(Intent.EXTRA_SUBJECT)).isNull()
- assertThat(wrappedIntent?.getStringExtra(Intent.EXTRA_TEXT)).isNull()
- assertThat(wrappedIntent?.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java))
- .isEqualTo(uri)
+
+ assertThat(wrappedIntent).hasAction(Intent.ACTION_SEND)
+ assertThat(wrappedIntent).hasData(uri)
+ assertThat(wrappedIntent).hasType("image/png")
+ assertThat(wrappedIntent).extras().doesNotContainKey(Intent.EXTRA_SUBJECT)
+ assertThat(wrappedIntent).extras().doesNotContainKey(Intent.EXTRA_TEXT)
+ assertThat(wrappedIntent).extras().parcelable<Uri>(Intent.EXTRA_STREAM).isEqualTo(uri)
}
@Test
- fun testCreateShareIntentWithSubject() {
+ fun testCreateShare_embeddedUserIdRemoved() {
+ val uri = Uri.parse("content://555@fake")
+
+ val output = ActionIntentCreator.createShare(uri)
+
+ assertThat(output.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java))
+ .hasData(Uri.parse("content://fake"))
+ }
+
+ @Test
+ fun testCreateShareWithSubject() {
val uri = Uri.parse("content://fake")
val subject = "Example subject"
- val output = ActionIntentCreator.createShareIntentWithSubject(uri, subject)
+ val output = ActionIntentCreator.createShareWithSubject(uri, subject)
- assertThat(output.action).isEqualTo(Intent.ACTION_CHOOSER)
- assertFlagsSet(
- Intent.FLAG_ACTIVITY_NEW_TASK or
- Intent.FLAG_ACTIVITY_CLEAR_TASK or
- Intent.FLAG_GRANT_READ_URI_PERMISSION,
- output.flags
- )
+ assertThat(output).hasAction(Intent.ACTION_CHOOSER)
+ assertThat(output)
+ .hasFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK or
+ Intent.FLAG_ACTIVITY_CLEAR_TASK or
+ Intent.FLAG_GRANT_READ_URI_PERMISSION
+ )
val wrappedIntent = output.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
- assertThat(wrappedIntent?.action).isEqualTo(Intent.ACTION_SEND)
- assertThat(wrappedIntent?.data).isEqualTo(uri)
- assertThat(wrappedIntent?.type).isEqualTo("image/png")
- assertThat(wrappedIntent?.getStringExtra(Intent.EXTRA_SUBJECT)).isEqualTo(subject)
- assertThat(wrappedIntent?.getStringExtra(Intent.EXTRA_TEXT)).isNull()
- assertThat(wrappedIntent?.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java))
- .isEqualTo(uri)
+ assertThat(wrappedIntent).hasAction(Intent.ACTION_SEND)
+ assertThat(wrappedIntent).hasData(uri)
+ assertThat(wrappedIntent).hasType("image/png")
+ assertThat(wrappedIntent).extras().string(Intent.EXTRA_SUBJECT).isEqualTo(subject)
+ assertThat(wrappedIntent).extras().doesNotContainKey(Intent.EXTRA_TEXT)
+ assertThat(wrappedIntent).extras().parcelable<Uri>(Intent.EXTRA_STREAM).isEqualTo(uri)
}
@Test
- fun testCreateShareIntentWithExtraText() {
+ fun testCreateShareWithText() {
val uri = Uri.parse("content://fake")
val extraText = "Extra text"
- val output = ActionIntentCreator.createShareIntentWithExtraText(uri, extraText)
+ val output = ActionIntentCreator.createShareWithText(uri, extraText)
- assertThat(output.action).isEqualTo(Intent.ACTION_CHOOSER)
- assertFlagsSet(
- Intent.FLAG_ACTIVITY_NEW_TASK or
- Intent.FLAG_ACTIVITY_CLEAR_TASK or
- Intent.FLAG_GRANT_READ_URI_PERMISSION,
- output.flags
- )
+ assertThat(output).hasAction(Intent.ACTION_CHOOSER)
+ assertThat(output)
+ .hasFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK or
+ Intent.FLAG_ACTIVITY_CLEAR_TASK or
+ Intent.FLAG_GRANT_READ_URI_PERMISSION
+ )
val wrappedIntent = output.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
- assertThat(wrappedIntent?.action).isEqualTo(Intent.ACTION_SEND)
- assertThat(wrappedIntent?.data).isEqualTo(uri)
- assertThat(wrappedIntent?.type).isEqualTo("image/png")
- assertThat(wrappedIntent?.getStringExtra(Intent.EXTRA_SUBJECT)).isNull()
- assertThat(wrappedIntent?.getStringExtra(Intent.EXTRA_TEXT)).isEqualTo(extraText)
- assertThat(wrappedIntent?.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java))
- .isEqualTo(uri)
+ assertThat(wrappedIntent).hasAction(Intent.ACTION_SEND)
+ assertThat(wrappedIntent).hasData(uri)
+ assertThat(wrappedIntent).hasType("image/png")
+ assertThat(wrappedIntent).extras().doesNotContainKey(Intent.EXTRA_SUBJECT)
+ assertThat(wrappedIntent).extras().string(Intent.EXTRA_TEXT).isEqualTo(extraText)
+ assertThat(wrappedIntent).extras().parcelable<Uri>(Intent.EXTRA_STREAM).isEqualTo(uri)
}
@Test
- fun testCreateEditIntent() {
+ fun testCreateEdit() {
val uri = Uri.parse("content://fake")
val context = mock<Context>()
- val output = ActionIntentCreator.createEditIntent(uri, context)
+ whenever(context.getString(eq(R.string.config_screenshotEditor))).thenReturn("")
+
+ val output = ActionIntentCreator.createEdit(uri, context)
+
+ assertThat(output).hasAction(Intent.ACTION_EDIT)
+ assertThat(output).hasData(uri)
+ assertThat(output).hasType("image/png")
+ assertWithMessage("getComponent()").that(output.component).isNull()
+ assertThat(output)
+ .hasFlags(
+ Intent.FLAG_GRANT_READ_URI_PERMISSION or
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
+ Intent.FLAG_ACTIVITY_NEW_TASK or
+ Intent.FLAG_ACTIVITY_CLEAR_TASK
+ )
+ }
- assertThat(output.action).isEqualTo(Intent.ACTION_EDIT)
- assertThat(output.data).isEqualTo(uri)
- assertThat(output.type).isEqualTo("image/png")
- assertThat(output.component).isNull()
- val expectedFlags =
- Intent.FLAG_GRANT_READ_URI_PERMISSION or
- Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
- Intent.FLAG_ACTIVITY_NEW_TASK or
- Intent.FLAG_ACTIVITY_CLEAR_TASK
- assertFlagsSet(expectedFlags, output.flags)
+ @Test
+ fun testCreateEdit_embeddedUserIdRemoved() {
+ val uri = Uri.parse("content://555@fake")
+ val context = mock<Context>()
+ whenever(context.getString(eq(R.string.config_screenshotEditor))).thenReturn("")
+
+ val output = ActionIntentCreator.createEdit(uri, context)
+
+ assertThat(output).hasData(Uri.parse("content://fake"))
}
@Test
- fun testCreateEditIntent_withEditor() {
+ fun testCreateEdit_withEditor() {
val uri = Uri.parse("content://fake")
val context = mock<Context>()
- var component = ComponentName("com.android.foo", "com.android.foo.Something")
+ val component = ComponentName("com.android.foo", "com.android.foo.Something")
whenever(context.getString(eq(R.string.config_screenshotEditor)))
.thenReturn(component.flattenToString())
- val output = ActionIntentCreator.createEditIntent(uri, context)
-
- assertThat(output.component).isEqualTo(component)
- }
+ val output = ActionIntentCreator.createEdit(uri, context)
- private fun assertFlagsSet(expected: Int, observed: Int) {
- assertThat(observed and expected).isEqualTo(expected)
+ assertThat(output).hasComponent(component)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index c3540cfec72d..981e44bea846 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -424,6 +424,10 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame);
when(mView.findViewById(R.id.keyguard_status_view))
.thenReturn(mock(KeyguardStatusView.class));
+ View rootView = mock(View.class);
+ when(mView.getRootView()).thenReturn(rootView);
+ when(rootView.findViewById(R.id.keyguard_status_view))
+ .thenReturn(mock(KeyguardStatusView.class));
mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null);
mNotificationContainerParent.addView(keyguardStatusView);
mNotificationContainerParent.onFinishInflate();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt
index 2bc112d68ae2..112a09bcfe62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt
@@ -144,27 +144,52 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() {
@Test
fun testSmallScreen_updateResources_splitShadeHeightIsSet() {
overrideResource(R.bool.config_use_large_screen_shade_header, false)
- overrideResource(R.dimen.qs_header_height, 1)
- overrideResource(R.dimen.large_screen_shade_header_height, 2)
+ overrideResource(R.dimen.qs_header_height, 10)
+ overrideResource(R.dimen.large_screen_shade_header_height, 20)
+
+ // ensure the estimated height (would be 3 here) wouldn't impact this test case
+ overrideResource(R.dimen.large_screen_shade_header_min_height, 1)
+ overrideResource(R.dimen.new_qs_header_non_clickable_element_height, 1)
underTest.updateResources()
val captor = ArgumentCaptor.forClass(ConstraintSet::class.java)
verify(view).applyConstraints(capture(captor))
- assertThat(captor.value.getHeight(R.id.split_shade_status_bar)).isEqualTo(1)
+ assertThat(captor.value.getHeight(R.id.split_shade_status_bar)).isEqualTo(10)
}
@Test
fun testLargeScreen_updateResources_splitShadeHeightIsSet() {
overrideResource(R.bool.config_use_large_screen_shade_header, true)
- overrideResource(R.dimen.qs_header_height, 1)
- overrideResource(R.dimen.large_screen_shade_header_height, 2)
+ overrideResource(R.dimen.qs_header_height, 10)
+ overrideResource(R.dimen.large_screen_shade_header_height, 20)
+
+ // ensure the estimated height (would be 3 here) wouldn't impact this test case
+ overrideResource(R.dimen.large_screen_shade_header_min_height, 1)
+ overrideResource(R.dimen.new_qs_header_non_clickable_element_height, 1)
underTest.updateResources()
val captor = ArgumentCaptor.forClass(ConstraintSet::class.java)
verify(view).applyConstraints(capture(captor))
- assertThat(captor.value.getHeight(R.id.split_shade_status_bar)).isEqualTo(2)
+ assertThat(captor.value.getHeight(R.id.split_shade_status_bar)).isEqualTo(20)
+ }
+
+ @Test
+ fun testSmallScreen_estimatedHeightIsLargerThanDimenValue_shadeHeightIsSetToEstimatedHeight() {
+ overrideResource(R.bool.config_use_large_screen_shade_header, false)
+ overrideResource(R.dimen.qs_header_height, 10)
+ overrideResource(R.dimen.large_screen_shade_header_height, 20)
+
+ // make the estimated height (would be 15 here) larger than qs_header_height
+ overrideResource(R.dimen.large_screen_shade_header_min_height, 5)
+ overrideResource(R.dimen.new_qs_header_non_clickable_element_height, 5)
+
+ underTest.updateResources()
+
+ val captor = ArgumentCaptor.forClass(ConstraintSet::class.java)
+ verify(view).applyConstraints(capture(captor))
+ assertThat(captor.value.getHeight(R.id.split_shade_status_bar)).isEqualTo(15)
}
@Test
@@ -388,6 +413,10 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() {
val largeScreenHeaderHeight = 100
overrideResource(R.dimen.large_screen_shade_header_height, largeScreenHeaderHeight)
+ // ensure the estimated height (would be 30 here) wouldn't impact this test case
+ overrideResource(R.dimen.large_screen_shade_header_min_height, 10)
+ overrideResource(R.dimen.new_qs_header_non_clickable_element_height, 10)
+
underTest.updateResources()
assertThat(getConstraintSetLayout(R.id.qs_frame).topMargin)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt
index a5048187b1b4..8d3c4b21aa26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt
@@ -143,27 +143,52 @@ class NotificationsQSContainerControllerTest : SysuiTestCase() {
@Test
fun testSmallScreen_updateResources_splitShadeHeightIsSet() {
overrideResource(R.bool.config_use_large_screen_shade_header, false)
- overrideResource(R.dimen.qs_header_height, 1)
- overrideResource(R.dimen.large_screen_shade_header_height, 2)
+ overrideResource(R.dimen.qs_header_height, 10)
+ overrideResource(R.dimen.large_screen_shade_header_height, 20)
+
+ // ensure the estimated height (would be 3 here) wouldn't impact this test case
+ overrideResource(R.dimen.large_screen_shade_header_min_height, 1)
+ overrideResource(R.dimen.new_qs_header_non_clickable_element_height, 1)
underTest.updateResources()
val captor = ArgumentCaptor.forClass(ConstraintSet::class.java)
verify(view).applyConstraints(capture(captor))
- assertThat(captor.value.getHeight(R.id.split_shade_status_bar)).isEqualTo(1)
+ assertThat(captor.value.getHeight(R.id.split_shade_status_bar)).isEqualTo(10)
}
@Test
fun testLargeScreen_updateResources_splitShadeHeightIsSet() {
overrideResource(R.bool.config_use_large_screen_shade_header, true)
- overrideResource(R.dimen.qs_header_height, 1)
- overrideResource(R.dimen.large_screen_shade_header_height, 2)
+ overrideResource(R.dimen.qs_header_height, 10)
+ overrideResource(R.dimen.large_screen_shade_header_height, 20)
+
+ // ensure the estimated height (would be 3 here) wouldn't impact this test case
+ overrideResource(R.dimen.large_screen_shade_header_min_height, 1)
+ overrideResource(R.dimen.new_qs_header_non_clickable_element_height, 1)
underTest.updateResources()
val captor = ArgumentCaptor.forClass(ConstraintSet::class.java)
verify(view).applyConstraints(capture(captor))
- assertThat(captor.value.getHeight(R.id.split_shade_status_bar)).isEqualTo(2)
+ assertThat(captor.value.getHeight(R.id.split_shade_status_bar)).isEqualTo(20)
+ }
+
+ @Test
+ fun testSmallScreen_estimatedHeightIsLargerThanDimenValue_shadeHeightIsSetToEstimatedHeight() {
+ overrideResource(R.bool.config_use_large_screen_shade_header, false)
+ overrideResource(R.dimen.qs_header_height, 10)
+ overrideResource(R.dimen.large_screen_shade_header_height, 20)
+
+ // make the estimated height (would be 15 here) larger than qs_header_height
+ overrideResource(R.dimen.large_screen_shade_header_min_height, 5)
+ overrideResource(R.dimen.new_qs_header_non_clickable_element_height, 5)
+
+ underTest.updateResources()
+
+ val captor = ArgumentCaptor.forClass(ConstraintSet::class.java)
+ verify(view).applyConstraints(capture(captor))
+ assertThat(captor.value.getHeight(R.id.split_shade_status_bar)).isEqualTo(15)
}
@Test
@@ -376,6 +401,10 @@ class NotificationsQSContainerControllerTest : SysuiTestCase() {
val largeScreenHeaderHeight = 100
overrideResource(R.dimen.large_screen_shade_header_height, largeScreenHeaderHeight)
+ // ensure the estimated height (would be 30 here) wouldn't impact this test case
+ overrideResource(R.dimen.large_screen_shade_header_min_height, 10)
+ overrideResource(R.dimen.new_qs_header_non_clickable_element_height, 10)
+
underTest.updateResources()
assertThat(getConstraintSetLayout(R.id.qs_frame).topMargin)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
index 8739b28c940e..7443097a2628 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
@@ -18,7 +18,7 @@ package com.android.systemui.shade.ui.viewmodel
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.authentication.data.model.AuthenticationMethodModel
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.SceneKey
@@ -47,14 +47,11 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
private val underTest =
ShadeSceneViewModel(
applicationScope = testScope.backgroundScope,
- lockscreenSceneInteractor =
- utils.lockScreenSceneInteractor(
+ authenticationInteractor = authenticationInteractor,
+ bouncerInteractor =
+ utils.bouncerInteractor(
authenticationInteractor = authenticationInteractor,
- bouncerInteractor =
- utils.bouncerInteractor(
- authenticationInteractor = authenticationInteractor,
- sceneInteractor = sceneInteractor,
- ),
+ sceneInteractor = sceneInteractor,
),
)
@@ -81,7 +78,7 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
@Test
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
runCurrent()
@@ -94,7 +91,7 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
@Test
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentScene by collectLastValue(sceneInteractor.desiredScene)
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt
new file mode 100644
index 000000000000..f5a24ff0c731
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shadow/DoubleShadowTextClockTest.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.shadow
+
+import android.content.Context
+import android.content.res.Resources
+import android.content.res.TypedArray
+import android.testing.AndroidTestingRunner
+import android.util.AttributeSet
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.shared.shadow.DoubleShadowTextClock
+import com.android.systemui.util.mockito.whenever
+import junit.framework.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class DoubleShadowTextClockTest : SysuiTestCase() {
+ @get:Rule val mockito: MockitoRule = MockitoJUnit.rule()
+
+ @Mock lateinit var resources: Resources
+
+ @Mock lateinit var attributes: TypedArray
+
+ private lateinit var context: Context
+ private var attrs: AttributeSet? = null
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ context = getContext()
+ whenever(attributes.getBoolean(R.styleable.DoubleShadowTextClock_removeTextDescent, false))
+ .thenReturn(true)
+ }
+
+ @Test
+ fun testAddingPaddingToBottomOfClockWhenConfigIsTrue() {
+ whenever(resources.getBoolean(R.bool.dream_overlay_complication_clock_bottom_padding))
+ .thenReturn(true)
+
+ val doubleShadowTextClock =
+ DoubleShadowTextClock(
+ resources = resources,
+ context = context,
+ attrs = attrs,
+ attributesInput = attributes
+ )
+ assertTrue(doubleShadowTextClock.paddingBottom > 0)
+ }
+
+ @Test
+ fun testRemovingPaddingToBottomOfClockWhenConfigIsFalse() {
+ whenever(resources.getBoolean(R.bool.dream_overlay_complication_clock_bottom_padding))
+ .thenReturn(false)
+
+ val doubleShadowTextClock =
+ DoubleShadowTextClock(
+ resources = resources,
+ context = context,
+ attrs = attrs,
+ attributesInput = attributes
+ )
+ assertTrue(doubleShadowTextClock.paddingBottom < 0)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
index 0cfca614a256..2e223f6d8c1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
@@ -24,9 +24,9 @@ import android.util.Pair
import android.view.Gravity
import android.view.View
import android.widget.FrameLayout
-import androidx.core.animation.AnimatorTestRule
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.AnimatorTestRule
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.statusbar.phone.StatusBarContentInsetsChangedListener
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
index 2af0cebf3519..414256fb1d5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
@@ -22,9 +22,9 @@ import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.View
import android.widget.FrameLayout
-import androidx.core.animation.AnimatorTestRule
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.AnimatorTestRule
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
index 78c0982df414..40edea2149ce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
@@ -18,9 +18,9 @@ package com.android.systemui.statusbar.notification
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
-import androidx.core.animation.AnimatorTestRule
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.AnimatorTestRule
import com.android.systemui.dump.DumpManager
import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.plugins.statusbar.StatusBarStateController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
index 764005b81a5d..0cc0b987aa34 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
@@ -17,6 +17,10 @@
package com.android.systemui.statusbar.notification.row
+import android.app.Notification
+import android.net.Uri
+import android.os.UserHandle
+import android.os.UserHandle.USER_ALL
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
@@ -29,13 +33,17 @@ import com.android.systemui.flags.FeatureFlags
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.PluginManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.SbnBuilder
import com.android.systemui.statusbar.SmartReplyController
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider
import com.android.systemui.statusbar.notification.collection.render.FakeNodeController
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager
import com.android.systemui.statusbar.notification.logging.NotificationLogger
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController.BUBBLES_SETTING_URI
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
@@ -46,9 +54,9 @@ import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.withArgCaptor
import com.android.systemui.util.time.SystemClock
import com.android.systemui.wmshell.BubblesManager
-import java.util.Optional
import junit.framework.Assert
import org.junit.After
import org.junit.Before
@@ -56,9 +64,11 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
+import java.util.Optional
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -94,10 +104,10 @@ class ExpandableNotificationRowControllerTest : SysuiTestCase() {
private val featureFlags: FeatureFlags = mock()
private val peopleNotificationIdentifier: PeopleNotificationIdentifier = mock()
private val bubblesManager: BubblesManager = mock()
+ private val settingsController: NotificationSettingsController = mock()
private val dragController: ExpandableNotificationRowDragController = mock()
private val dismissibilityProvider: NotificationDismissibilityProvider = mock()
private val statusBarService: IStatusBarService = mock()
-
private lateinit var controller: ExpandableNotificationRowController
@Before
@@ -134,11 +144,16 @@ class ExpandableNotificationRowControllerTest : SysuiTestCase() {
featureFlags,
peopleNotificationIdentifier,
Optional.of(bubblesManager),
+ settingsController,
dragController,
dismissibilityProvider,
statusBarService
)
whenever(view.childrenContainer).thenReturn(childrenContainer)
+
+ val notification = Notification.Builder(mContext).build()
+ val sbn = SbnBuilder().setNotification(notification).build()
+ whenever(view.entry).thenReturn(NotificationEntryBuilder().setSbn(sbn).build())
}
@After
@@ -206,4 +221,74 @@ class ExpandableNotificationRowControllerTest : SysuiTestCase() {
verify(view).removeChildNotification(eq(childView))
verify(listContainer).notifyGroupChildRemoved(eq(childView), eq(childrenContainer))
}
+
+ @Test
+ fun registerSettingsListener_forBubbles() {
+ controller.init(mock(NotificationEntry::class.java))
+ val viewStateObserver = withArgCaptor {
+ verify(view).addOnAttachStateChangeListener(capture());
+ }
+ viewStateObserver.onViewAttachedToWindow(view);
+ verify(settingsController).addCallback(any(), any());
+ }
+
+ @Test
+ fun unregisterSettingsListener_forBubbles() {
+ controller.init(mock(NotificationEntry::class.java))
+ val viewStateObserver = withArgCaptor {
+ verify(view).addOnAttachStateChangeListener(capture());
+ }
+ viewStateObserver.onViewDetachedFromWindow(view);
+ verify(settingsController).removeCallback(any(), any());
+ }
+
+ @Test
+ fun settingsListener_invalidUri() {
+ controller.mSettingsListener.onSettingChanged(Uri.EMPTY, view.entry.sbn.userId, "1")
+
+ verify(view, never()).getPrivateLayout()
+ }
+
+ @Test
+ fun settingsListener_invalidUserId() {
+ controller.mSettingsListener.onSettingChanged(BUBBLES_SETTING_URI, -1000, "1")
+ controller.mSettingsListener.onSettingChanged(BUBBLES_SETTING_URI, -1000, null)
+
+ verify(view, never()).getPrivateLayout()
+ }
+
+ @Test
+ fun settingsListener_validUserId() {
+ val childView: NotificationContentView = mock()
+ whenever(view.privateLayout).thenReturn(childView)
+
+ controller.mSettingsListener.onSettingChanged(
+ BUBBLES_SETTING_URI, view.entry.sbn.userId, "1")
+ verify(childView).setBubblesEnabledForUser(true)
+
+ controller.mSettingsListener.onSettingChanged(
+ BUBBLES_SETTING_URI, view.entry.sbn.userId, "9")
+ verify(childView).setBubblesEnabledForUser(false)
+ }
+
+ @Test
+ fun settingsListener_userAll() {
+ val childView: NotificationContentView = mock()
+ whenever(view.privateLayout).thenReturn(childView)
+
+ val notification = Notification.Builder(mContext).build()
+ val sbn = SbnBuilder().setNotification(notification)
+ .setUser(UserHandle.of(USER_ALL))
+ .build()
+ whenever(view.entry).thenReturn(NotificationEntryBuilder()
+ .setSbn(sbn)
+ .setUser(UserHandle.of(USER_ALL))
+ .build())
+
+ controller.mSettingsListener.onSettingChanged(BUBBLES_SETTING_URI, 9, "1")
+ verify(childView).setBubblesEnabledForUser(true)
+
+ controller.mSettingsListener.onSettingChanged(BUBBLES_SETTING_URI, 1, "0")
+ verify(childView).setBubblesEnabledForUser(false)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
index 0b90ebec3ec6..c4baa691e612 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
@@ -250,6 +250,9 @@ class NotificationContentViewTest : SysuiTestCase() {
.thenReturn(actionListMarginTarget)
view.setContainingNotification(mockContainingNotification)
+ // Given: controller says bubbles are enabled for the user
+ view.setBubblesEnabledForUser(true);
+
// When: call NotificationContentView.setExpandedChild() to set the expandedChild
view.expandedChild = mockExpandedChild
@@ -305,6 +308,12 @@ class NotificationContentViewTest : SysuiTestCase() {
// NotificationEntry, which should show bubble button
view.onNotificationUpdated(createMockNotificationEntry(true))
+ // Then: no bubble yet
+ assertEquals(notificationContentMargin, getMarginBottom(actionListMarginTarget))
+
+ // Given: controller says bubbles are enabled for the user
+ view.setBubblesEnabledForUser(true);
+
// Then: bottom margin of actionListMarginTarget should not change, still be 20
assertEquals(0, getMarginBottom(actionListMarginTarget))
}
@@ -405,7 +414,6 @@ class NotificationContentViewTest : SysuiTestCase() {
val userMock: UserHandle = mock()
whenever(this.sbn).thenReturn(sbnMock)
whenever(sbnMock.user).thenReturn(userMock)
- doReturn(showButton).whenever(view).shouldShowBubbleButton(this)
}
private fun createLinearLayoutWithBottomMargin(bottomMargin: Int): LinearLayout {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 90adabfadd5d..596e9a2613d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -62,6 +62,7 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Handler;
import android.os.UserHandle;
+import android.os.UserManager;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -132,6 +133,8 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
@Mock
private PackageManager mMockPackageManager;
@Mock
+ private UserManager mUserManager;
+ @Mock
private OnUserInteractionCallback mOnUserInteractionCallback;
@Mock
private BubblesManager mBubblesManager;
@@ -238,6 +241,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -262,6 +266,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -314,6 +319,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -339,6 +345,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -363,6 +370,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -398,6 +406,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -423,6 +432,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -452,6 +462,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -476,6 +487,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -504,6 +516,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -532,6 +545,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -563,6 +577,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -600,6 +615,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -628,6 +644,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -663,6 +680,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -691,6 +709,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -735,6 +754,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -778,6 +798,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -822,6 +843,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -860,6 +882,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -896,6 +919,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -936,6 +960,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -967,6 +992,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -996,6 +1022,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -1033,6 +1060,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -1069,6 +1097,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -1104,6 +1133,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -1143,6 +1173,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -1173,6 +1204,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -1198,6 +1230,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -1219,11 +1252,13 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
@Test
public void testSelectPriorityRequestsPinPeopleTile() {
+ when(mUserManager.isSameProfileGroup(anyInt(), anyInt())).thenReturn(true);
//WHEN channel is default importance
mNotificationChannel.setImportantConversation(false);
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -1250,10 +1285,45 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
}
@Test
+ public void testSelectPriorityRequestsPinPeopleTile_noMultiuser() {
+ when(mUserManager.isSameProfileGroup(anyInt(), anyInt())).thenReturn(false);
+ //WHEN channel is default importance
+ mNotificationChannel.setImportantConversation(false);
+ mNotificationInfo.bindNotification(
+ mShortcutManager,
+ mMockPackageManager,
+ mUserManager,
+ mPeopleSpaceWidgetManager,
+ mMockINotificationManager,
+ mOnUserInteractionCallback,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mEntry,
+ mBubbleMetadata,
+ null,
+ mIconFactory,
+ mContext,
+ true,
+ mTestHandler,
+ mTestHandler, null, Optional.of(mBubblesManager),
+ mShadeController);
+
+ // WHEN user clicks "priority"
+ mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE);
+
+ // and then done
+ mNotificationInfo.findViewById(R.id.done).performClick();
+
+ // No widget prompt; on a secondary user
+ verify(mPeopleSpaceWidgetManager, never()).requestPinAppWidget(any(), any());
+ }
+
+ @Test
public void testSelectDefaultDoesNotRequestPinPeopleTile() {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
@@ -1288,6 +1358,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(
mShortcutManager,
mMockPackageManager,
+ mUserManager,
mPeopleSpaceWidgetManager,
mMockINotificationManager,
mOnUserInteractionCallback,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 3cefc9973d09..705d52bcf13f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -52,6 +52,7 @@ import android.content.pm.ShortcutManager;
import android.graphics.Color;
import android.os.Binder;
import android.os.Handler;
+import android.os.UserManager;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
@@ -137,6 +138,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
@Mock private HeadsUpManagerPhone mHeadsUpManagerPhone;
@Mock private ActivityStarter mActivityStarter;
+ @Mock private UserManager mUserManager;
+
@Before
public void setUp() {
mTestableLooper = TestableLooper.get(this);
@@ -147,7 +150,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
mGutsManager = new NotificationGutsManager(mContext, mHandler, mHandler,
mAccessibilityManager,
- mHighPriorityProvider, mINotificationManager,
+ mHighPriorityProvider, mINotificationManager, mUserManager,
mPeopleSpaceWidgetManager, mLauncherApps, mShortcutManager,
mChannelEditorDialogController, mContextTracker, mAssistantFeedbackController,
Optional.of(mBubblesManager), new UiEventLoggerFake(), mOnUserInteractionCallback,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSettingsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSettingsControllerTest.kt
new file mode 100644
index 000000000000..614995b9bf46
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSettingsControllerTest.kt
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.statusbar.notification.row
+
+import android.app.ActivityManager
+import android.database.ContentObserver
+import android.net.Uri
+import android.os.Handler
+import android.provider.Settings.Secure
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.statusbar.notification.row.NotificationSettingsController.Listener
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.settings.SecureSettings
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class NotificationSettingsControllerTest : SysuiTestCase() {
+
+ val setting1: String = Secure.NOTIFICATION_BUBBLES
+ val setting2: String = Secure.ACCESSIBILITY_ENABLED
+ val settingUri1: Uri = Secure.getUriFor(setting1)
+ val settingUri2: Uri = Secure.getUriFor(setting2)
+
+ @Mock
+ private lateinit var userTracker: UserTracker
+ private lateinit var mainHandler: Handler
+ private lateinit var backgroundHandler: Handler
+ private lateinit var testableLooper: TestableLooper
+ @Mock
+ private lateinit var secureSettings: SecureSettings
+ @Mock
+ private lateinit var dumpManager: DumpManager
+
+ @Captor
+ private lateinit var userTrackerCallbackCaptor: ArgumentCaptor<UserTracker.Callback>
+ @Captor
+ private lateinit var settingsObserverCaptor: ArgumentCaptor<ContentObserver>
+
+ private lateinit var controller: NotificationSettingsController
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ testableLooper = TestableLooper.get(this)
+ mainHandler = Handler(testableLooper.looper)
+ backgroundHandler = Handler(testableLooper.looper)
+ allowTestableLooperAsMainThread()
+ controller =
+ NotificationSettingsController(
+ userTracker,
+ mainHandler,
+ backgroundHandler,
+ secureSettings,
+ dumpManager
+ )
+ }
+
+ @After
+ fun tearDown() {
+ disallowTestableLooperAsMainThread()
+ }
+
+ @Test
+ fun creationRegistersCallbacks() {
+ verify(userTracker).addCallback(any(), any())
+ verify(dumpManager).registerNormalDumpable(anyString(), eq(controller))
+ }
+ @Test
+ fun updateContentObserverRegistration_onUserChange_noSettingsListeners() {
+ verify(userTracker).addCallback(capture(userTrackerCallbackCaptor), any())
+ val userCallback = userTrackerCallbackCaptor.value
+ val userId = 9
+
+ // When: User is changed
+ userCallback.onUserChanged(userId, context)
+
+ // Validate: Nothing to do, since we aren't monitoring settings
+ verify(secureSettings, never()).unregisterContentObserver(any())
+ verify(secureSettings, never()).registerContentObserverForUser(
+ any(Uri::class.java), anyBoolean(), any(), anyInt())
+ }
+ @Test
+ fun updateContentObserverRegistration_onUserChange_withSettingsListeners() {
+ // When: someone is listening to a setting
+ controller.addCallback(settingUri1,
+ Mockito.mock(Listener::class.java))
+
+ verify(userTracker).addCallback(capture(userTrackerCallbackCaptor), any())
+ val userCallback = userTrackerCallbackCaptor.value
+ val userId = 9
+
+ // Then: User is changed
+ userCallback.onUserChanged(userId, context)
+
+ // Validate: The tracker is unregistered and re-registered with the new user
+ verify(secureSettings).unregisterContentObserver(any())
+ verify(secureSettings).registerContentObserverForUser(
+ eq(settingUri1), eq(false), any(), eq(userId))
+ }
+
+ @Test
+ fun addCallback_onlyFirstForUriRegistersObserver() {
+ controller.addCallback(settingUri1,
+ Mockito.mock(Listener::class.java))
+ verify(secureSettings).registerContentObserverForUser(
+ eq(settingUri1), eq(false), any(), eq(ActivityManager.getCurrentUser()))
+
+ controller.addCallback(settingUri1,
+ Mockito.mock(Listener::class.java))
+ verify(secureSettings).registerContentObserverForUser(
+ any(Uri::class.java), anyBoolean(), any(), anyInt())
+ }
+
+ @Test
+ fun addCallback_secondUriRegistersObserver() {
+ controller.addCallback(settingUri1,
+ Mockito.mock(Listener::class.java))
+ verify(secureSettings).registerContentObserverForUser(
+ eq(settingUri1), eq(false), any(), eq(ActivityManager.getCurrentUser()))
+
+ controller.addCallback(settingUri2,
+ Mockito.mock(Listener::class.java))
+ verify(secureSettings).registerContentObserverForUser(
+ eq(settingUri2), eq(false), any(), eq(ActivityManager.getCurrentUser()))
+ verify(secureSettings).registerContentObserverForUser(
+ eq(settingUri1), anyBoolean(), any(), anyInt())
+ }
+
+ @Test
+ fun removeCallback_lastUnregistersObserver() {
+ val listenerSetting1 : Listener = mock()
+ val listenerSetting2 : Listener = mock()
+ controller.addCallback(settingUri1, listenerSetting1)
+ verify(secureSettings).registerContentObserverForUser(
+ eq(settingUri1), eq(false), any(), eq(ActivityManager.getCurrentUser()))
+
+ controller.addCallback(settingUri2, listenerSetting2)
+ verify(secureSettings).registerContentObserverForUser(
+ eq(settingUri2), anyBoolean(), any(), anyInt())
+
+ controller.removeCallback(settingUri2, listenerSetting2)
+ verify(secureSettings, never()).unregisterContentObserver(any())
+
+ controller.removeCallback(settingUri1, listenerSetting1)
+ verify(secureSettings).unregisterContentObserver(any())
+ }
+
+ @Test
+ fun addCallback_updatesCurrentValue() {
+ whenever(secureSettings.getStringForUser(
+ setting1, ActivityManager.getCurrentUser())).thenReturn("9")
+ whenever(secureSettings.getStringForUser(
+ setting2, ActivityManager.getCurrentUser())).thenReturn("5")
+
+ val listenerSetting1a : Listener = mock()
+ val listenerSetting1b : Listener = mock()
+ val listenerSetting2 : Listener = mock()
+
+ controller.addCallback(settingUri1, listenerSetting1a)
+ controller.addCallback(settingUri1, listenerSetting1b)
+ controller.addCallback(settingUri2, listenerSetting2)
+
+ testableLooper.processAllMessages()
+
+ verify(listenerSetting1a).onSettingChanged(
+ settingUri1, ActivityManager.getCurrentUser(), "9")
+ verify(listenerSetting1b).onSettingChanged(
+ settingUri1, ActivityManager.getCurrentUser(), "9")
+ verify(listenerSetting2).onSettingChanged(
+ settingUri2, ActivityManager.getCurrentUser(), "5")
+ }
+
+ @Test
+ fun removeCallback_noMoreUpdates() {
+ whenever(secureSettings.getStringForUser(
+ setting1, ActivityManager.getCurrentUser())).thenReturn("9")
+
+ val listenerSetting1a : Listener = mock()
+ val listenerSetting1b : Listener = mock()
+
+ // First, register
+ controller.addCallback(settingUri1, listenerSetting1a)
+ controller.addCallback(settingUri1, listenerSetting1b)
+ testableLooper.processAllMessages()
+
+ verify(secureSettings).registerContentObserverForUser(
+ any(Uri::class.java), anyBoolean(), capture(settingsObserverCaptor), anyInt())
+ verify(listenerSetting1a).onSettingChanged(
+ settingUri1, ActivityManager.getCurrentUser(), "9")
+ verify(listenerSetting1b).onSettingChanged(
+ settingUri1, ActivityManager.getCurrentUser(), "9")
+ Mockito.clearInvocations(listenerSetting1b)
+ Mockito.clearInvocations(listenerSetting1a)
+
+ // Remove one of them
+ controller.removeCallback(settingUri1, listenerSetting1a)
+
+ // On update, only remaining listener should get the callback
+ settingsObserverCaptor.value.onChange(false, settingUri1)
+ testableLooper.processAllMessages()
+
+ verify(listenerSetting1a, never()).onSettingChanged(
+ settingUri1, ActivityManager.getCurrentUser(), "9")
+ verify(listenerSetting1b).onSettingChanged(
+ settingUri1, ActivityManager.getCurrentUser(), "9")
+ }
+
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 5dcb90144b70..823155b0d7e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -45,12 +45,12 @@ import android.view.View;
import android.view.ViewPropertyAnimator;
import android.widget.FrameLayout;
-import androidx.core.animation.AnimatorTestRule;
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
import com.android.systemui.SysuiBaseFragmentTest;
+import com.android.systemui.animation.AnimatorTestRule;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.log.LogBuffer;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/MultiSourceMinAlphaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/MultiSourceMinAlphaControllerTest.kt
index 2617613d1fc5..2ce060c5d097 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/MultiSourceMinAlphaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/MultiSourceMinAlphaControllerTest.kt
@@ -19,9 +19,9 @@ package com.android.systemui.statusbar.phone.fragment
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
-import androidx.core.animation.AnimatorTestRule
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.AnimatorTestRule
import junit.framework.Assert.assertEquals
import org.junit.Before
import org.junit.Rule
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
index 6306a36d9730..50ee6a31d389 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
@@ -55,6 +55,8 @@ class FakeMobileConnectionRepository(
override val networkName =
MutableStateFlow<NetworkNameModel>(NetworkNameModel.Default("default"))
+ override val isAllowedDuringAirplaneMode = MutableStateFlow(false)
+
fun setDataEnabled(enabled: Boolean) {
_dataEnabled.value = enabled
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
index 441186acb6b7..a251c2850d41 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
@@ -20,6 +20,7 @@ import android.telephony.TelephonyManager
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
@@ -319,6 +320,14 @@ class CarrierMergedConnectionRepositoryTest : SysuiTestCase() {
job.cancel()
}
+ @Test
+ fun isAllowedDuringAirplaneMode_alwaysTrue() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isAllowedDuringAirplaneMode)
+
+ assertThat(latest).isTrue()
+ }
+
private companion object {
const val SUB_ID = 123
const val NET_ID = 456
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
index b701fbd66937..3dd2eaff7bce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
@@ -22,6 +22,7 @@ import android.telephony.TelephonyCallback
import android.telephony.TelephonyManager
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
@@ -84,7 +85,11 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
@Before
fun setUp() {
mobileRepo = FakeMobileConnectionRepository(SUB_ID, tableLogBuffer)
- carrierMergedRepo = FakeMobileConnectionRepository(SUB_ID, tableLogBuffer)
+ carrierMergedRepo =
+ FakeMobileConnectionRepository(SUB_ID, tableLogBuffer).apply {
+ // Mimicks the real carrier merged repository
+ this.isAllowedDuringAirplaneMode.value = true
+ }
whenever(
mobileFactory.build(
@@ -300,6 +305,24 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {
}
@Test
+ fun isAllowedDuringAirplaneMode_updatesWhenCarrierMergedUpdates() =
+ testScope.runTest {
+ initializeRepo(startingIsCarrierMerged = false)
+
+ val latest by collectLastValue(underTest.isAllowedDuringAirplaneMode)
+
+ assertThat(latest).isFalse()
+
+ underTest.setIsCarrierMerged(true)
+
+ assertThat(latest).isTrue()
+
+ underTest.setIsCarrierMerged(false)
+
+ assertThat(latest).isFalse()
+ }
+
+ @Test
fun factory_reusesLogBuffersForSameConnection() =
testScope.runTest {
val realLoggerFactory =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index cf832b4ab059..1ff737bfc137 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -53,6 +53,7 @@ import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
import androidx.test.filters.SmallTest
import com.android.settingslib.mobile.MobileMappings
import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
@@ -812,6 +813,14 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {
job.cancel()
}
+ @Test
+ fun isAllowedDuringAirplaneMode_alwaysFalse() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isAllowedDuringAirplaneMode)
+
+ assertThat(latest).isFalse()
+ }
+
private inline fun <reified T> getTelephonyCallbackForType(): T {
return MobileTelephonyHelpers.getTelephonyCallbackForType(telephonyManager)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
index c4e419366759..8d1da69d6877 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
@@ -77,6 +77,8 @@ class FakeMobileIconInteractor(
override val isForceHidden = MutableStateFlow(false)
+ override val isAllowedDuringAirplaneMode = MutableStateFlow(false)
+
fun setIsEmergencyOnly(emergency: Boolean) {
_isEmergencyOnly.value = emergency
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
index c2768654809b..58d3804b7155 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
@@ -23,6 +23,7 @@ import com.android.settingslib.mobile.MobileIconCarrierIdOverrides
import com.android.settingslib.mobile.MobileIconCarrierIdOverridesImpl
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.CarrierMergedNetworkType
@@ -473,6 +474,18 @@ class MobileIconInteractorTest : SysuiTestCase() {
job.cancel()
}
+ @Test
+ fun isAllowedDuringAirplaneMode_matchesRepo() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isAllowedDuringAirplaneMode)
+
+ connectionRepository.isAllowedDuringAirplaneMode.value = true
+ assertThat(latest).isTrue()
+
+ connectionRepository.isAllowedDuringAirplaneMode.value = false
+ assertThat(latest).isFalse()
+ }
+
private fun createInteractor(
overrides: MobileIconCarrierIdOverrides = MobileIconCarrierIdOverridesImpl()
) =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
index b5ab29d6217e..72feec78a979 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
@@ -116,12 +116,13 @@ class MobileIconViewModelTest : SysuiTestCase() {
}
@Test
- fun isVisible_airplane_false() =
+ fun isVisible_airplaneAndNotAllowed_false() =
testScope.runTest {
var latest: Boolean? = null
val job = underTest.isVisible.onEach { latest = it }.launchIn(this)
airplaneModeRepository.setIsAirplaneMode(true)
+ interactor.isAllowedDuringAirplaneMode.value = false
interactor.isForceHidden.value = false
assertThat(latest).isFalse()
@@ -129,6 +130,22 @@ class MobileIconViewModelTest : SysuiTestCase() {
job.cancel()
}
+ /** Regression test for b/291993542. */
+ @Test
+ fun isVisible_airplaneButAllowed_true() =
+ testScope.runTest {
+ var latest: Boolean? = null
+ val job = underTest.isVisible.onEach { latest = it }.launchIn(this)
+
+ airplaneModeRepository.setIsAirplaneMode(true)
+ interactor.isAllowedDuringAirplaneMode.value = true
+ interactor.isForceHidden.value = false
+
+ assertThat(latest).isTrue()
+
+ job.cancel()
+ }
+
@Test
fun isVisible_forceHidden_false() =
testScope.runTest {
@@ -157,7 +174,7 @@ class MobileIconViewModelTest : SysuiTestCase() {
airplaneModeRepository.setIsAirplaneMode(true)
assertThat(latest).isFalse()
- airplaneModeRepository.setIsAirplaneMode(false)
+ interactor.isAllowedDuringAirplaneMode.value = true
assertThat(latest).isTrue()
interactor.isForceHidden.value = true
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
index 1bf431b4ea13..1c8dac14b089 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.pipeline.wifi.data.repository
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
-import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.ACTIVITY_DEFAULT
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryHelper.ACTIVITY_DEFAULT
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
index fef042be65a8..2dbeb7aa7e90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
@@ -489,6 +489,26 @@ class WifiRepositoryImplTest : SysuiTestCase() {
}
@Test
+ fun wifiNetwork_neverHasHotspot() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.wifiNetwork)
+
+ val wifiInfo =
+ mock<WifiInfo>().apply {
+ whenever(this.ssid).thenReturn(SSID)
+ whenever(this.isPrimary).thenReturn(true)
+ }
+ val network = mock<Network>().apply { whenever(this.getNetId()).thenReturn(NETWORK_ID) }
+
+ getNetworkCallback()
+ .onCapabilitiesChanged(network, createWifiNetworkCapabilities(wifiInfo))
+
+ assertThat(latest is WifiNetworkModel.Active).isTrue()
+ assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
+ .isEqualTo(WifiNetworkModel.HotspotDeviceType.NONE)
+ }
+
+ @Test
fun wifiNetwork_isCarrierMerged_flowHasCarrierMerged() =
testScope.runTest {
val latest by collectLastValue(underTest.wifiNetwork)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLibTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLibTest.kt
index 7002cbb6ab21..9959e00fd3f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLibTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLibTest.kt
@@ -18,13 +18,18 @@ package com.android.systemui.statusbar.pipeline.wifi.data.repository.prod
import android.net.wifi.WifiManager
import android.net.wifi.WifiManager.UNKNOWN_SSID
+import android.net.wifi.sharedconnectivity.app.NetworkProviderInfo
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import com.android.systemui.util.concurrency.FakeExecutor
@@ -34,8 +39,13 @@ import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
+import com.android.wifitrackerlib.HotspotNetworkEntry
+import com.android.wifitrackerlib.HotspotNetworkEntry.DeviceType
import com.android.wifitrackerlib.MergedCarrierEntry
import com.android.wifitrackerlib.WifiEntry
+import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MAX
+import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MIN
+import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_UNREACHABLE
import com.android.wifitrackerlib.WifiPickerTracker
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -45,6 +55,7 @@ import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
+import org.mockito.Mockito.verify
/**
* Note: Most of these tests are duplicates of [WifiRepositoryImplTest] tests.
@@ -57,10 +68,25 @@ import org.junit.Test
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
- private lateinit var underTest: WifiRepositoryViaTrackerLib
+ // Using lazy means that the class will only be constructed once it's fetched. Because the
+ // repository internally sets some values on construction, we need to set up some test
+ // parameters (like feature flags) *before* construction. Using lazy allows us to do that setup
+ // inside each test case without needing to manually recreate the repository.
+ private val underTest: WifiRepositoryViaTrackerLib by lazy {
+ WifiRepositoryViaTrackerLib(
+ featureFlags,
+ testScope.backgroundScope,
+ executor,
+ wifiPickerTrackerFactory,
+ wifiManager,
+ logger,
+ tableLogger,
+ )
+ }
private val executor = FakeExecutor(FakeSystemClock())
private val logger = LogBuffer("name", maxSize = 100, logcatEchoTracker = mock())
+ private val featureFlags = FakeFeatureFlags()
private val tableLogger = mock<TableLogBuffer>()
private val wifiManager =
mock<WifiManager>().apply { whenever(this.maxSignalLevel).thenReturn(10) }
@@ -74,12 +100,21 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
@Before
fun setUp() {
+ featureFlags.set(Flags.INSTANT_TETHER, false)
whenever(wifiPickerTrackerFactory.create(any(), capture(callbackCaptor)))
.thenReturn(wifiPickerTracker)
- underTest = createRepo()
}
@Test
+ fun wifiPickerTrackerCreation_scansDisabled() =
+ testScope.runTest {
+ collectLastValue(underTest.wifiNetwork)
+ testScope.runCurrent()
+
+ verify(wifiPickerTracker).disableScanning()
+ }
+
+ @Test
fun isWifiEnabled_enabled_true() =
testScope.runTest {
val latest by collectLastValue(underTest.isWifiEnabled)
@@ -238,7 +273,7 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.level).thenReturn(3)
- whenever(this.ssid).thenReturn(SSID)
+ whenever(this.title).thenReturn(TITLE)
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
@@ -246,7 +281,240 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
assertThat(latest is WifiNetworkModel.Active).isTrue()
val latestActive = latest as WifiNetworkModel.Active
assertThat(latestActive.level).isEqualTo(3)
- assertThat(latestActive.ssid).isEqualTo(SSID)
+ assertThat(latestActive.ssid).isEqualTo(TITLE)
+ }
+
+ @Test
+ fun accessPointInfo_alwaysFalse() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.wifiNetwork)
+
+ val wifiEntry =
+ mock<WifiEntry>().apply {
+ whenever(this.isPrimaryNetwork).thenReturn(true)
+ whenever(this.level).thenReturn(3)
+ whenever(this.title).thenReturn(TITLE)
+ }
+ whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
+ getCallback().onWifiEntriesChanged()
+
+ assertThat(latest is WifiNetworkModel.Active).isTrue()
+ val latestActive = latest as WifiNetworkModel.Active
+ assertThat(latestActive.isPasspointAccessPoint).isFalse()
+ assertThat(latestActive.isOnlineSignUpForPasspointAccessPoint).isFalse()
+ assertThat(latestActive.passpointProviderFriendlyName).isNull()
+ }
+
+ @Test
+ fun wifiNetwork_unreachableLevel_inactiveNetwork() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.wifiNetwork)
+
+ val wifiEntry =
+ mock<WifiEntry>().apply {
+ whenever(this.isPrimaryNetwork).thenReturn(true)
+ whenever(this.level).thenReturn(WIFI_LEVEL_UNREACHABLE)
+ }
+ whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
+ getCallback().onWifiEntriesChanged()
+
+ assertThat(latest).isEqualTo(WifiNetworkModel.Inactive)
+ }
+
+ @Test
+ fun wifiNetwork_levelTooHigh_inactiveNetwork() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.wifiNetwork)
+
+ val wifiEntry =
+ mock<WifiEntry>().apply {
+ whenever(this.isPrimaryNetwork).thenReturn(true)
+ whenever(this.level).thenReturn(WIFI_LEVEL_MAX + 1)
+ }
+ whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
+ getCallback().onWifiEntriesChanged()
+
+ assertThat(latest).isEqualTo(WifiNetworkModel.Inactive)
+ }
+
+ @Test
+ fun wifiNetwork_levelTooLow_inactiveNetwork() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.wifiNetwork)
+
+ val wifiEntry =
+ mock<WifiEntry>().apply {
+ whenever(this.isPrimaryNetwork).thenReturn(true)
+ whenever(this.level).thenReturn(WIFI_LEVEL_MIN - 1)
+ }
+ whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
+ getCallback().onWifiEntriesChanged()
+
+ assertThat(latest).isEqualTo(WifiNetworkModel.Inactive)
+ }
+
+ @Test
+ fun wifiNetwork_levelIsMax_activeNetworkWithMaxLevel() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.wifiNetwork)
+
+ val wifiEntry =
+ mock<WifiEntry>().apply {
+ whenever(this.isPrimaryNetwork).thenReturn(true)
+ whenever(this.level).thenReturn(WIFI_LEVEL_MAX)
+ }
+ whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
+ getCallback().onWifiEntriesChanged()
+
+ assertThat(latest).isInstanceOf(WifiNetworkModel.Active::class.java)
+ assertThat((latest as WifiNetworkModel.Active).level).isEqualTo(WIFI_LEVEL_MAX)
+ }
+
+ @Test
+ fun wifiNetwork_levelIsMin_activeNetworkWithMinLevel() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.wifiNetwork)
+
+ val wifiEntry =
+ mock<WifiEntry>().apply {
+ whenever(this.isPrimaryNetwork).thenReturn(true)
+ whenever(this.level).thenReturn(WIFI_LEVEL_MIN)
+ }
+ whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
+ getCallback().onWifiEntriesChanged()
+
+ assertThat(latest).isInstanceOf(WifiNetworkModel.Active::class.java)
+ assertThat((latest as WifiNetworkModel.Active).level).isEqualTo(WIFI_LEVEL_MIN)
+ }
+
+ @Test
+ fun wifiNetwork_notHotspot_none() =
+ testScope.runTest {
+ featureFlags.set(Flags.INSTANT_TETHER, true)
+ val latest by collectLastValue(underTest.wifiNetwork)
+
+ val wifiEntry =
+ mock<WifiEntry>().apply { whenever(this.isPrimaryNetwork).thenReturn(true) }
+ whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
+ getCallback().onWifiEntriesChanged()
+
+ assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
+ .isEqualTo(WifiNetworkModel.HotspotDeviceType.NONE)
+ }
+
+ @Test
+ fun wifiNetwork_hotspot_unknown() =
+ testScope.runTest {
+ featureFlags.set(Flags.INSTANT_TETHER, true)
+ val latest by collectLastValue(underTest.wifiNetwork)
+
+ val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_UNKNOWN)
+ whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
+ getCallback().onWifiEntriesChanged()
+
+ assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
+ .isEqualTo(WifiNetworkModel.HotspotDeviceType.UNKNOWN)
+ }
+
+ @Test
+ fun wifiNetwork_hotspot_phone() =
+ testScope.runTest {
+ featureFlags.set(Flags.INSTANT_TETHER, true)
+ val latest by collectLastValue(underTest.wifiNetwork)
+
+ val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_PHONE)
+ whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
+ getCallback().onWifiEntriesChanged()
+
+ assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
+ .isEqualTo(WifiNetworkModel.HotspotDeviceType.PHONE)
+ }
+
+ @Test
+ fun wifiNetwork_hotspot_tablet() =
+ testScope.runTest {
+ featureFlags.set(Flags.INSTANT_TETHER, true)
+ val latest by collectLastValue(underTest.wifiNetwork)
+
+ val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_TABLET)
+ whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
+ getCallback().onWifiEntriesChanged()
+
+ assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
+ .isEqualTo(WifiNetworkModel.HotspotDeviceType.TABLET)
+ }
+
+ @Test
+ fun wifiNetwork_hotspot_laptop() =
+ testScope.runTest {
+ featureFlags.set(Flags.INSTANT_TETHER, true)
+ val latest by collectLastValue(underTest.wifiNetwork)
+
+ val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_LAPTOP)
+ whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
+ getCallback().onWifiEntriesChanged()
+
+ assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
+ .isEqualTo(WifiNetworkModel.HotspotDeviceType.LAPTOP)
+ }
+
+ @Test
+ fun wifiNetwork_hotspot_watch() =
+ testScope.runTest {
+ featureFlags.set(Flags.INSTANT_TETHER, true)
+ val latest by collectLastValue(underTest.wifiNetwork)
+
+ val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_WATCH)
+ whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
+ getCallback().onWifiEntriesChanged()
+
+ assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
+ .isEqualTo(WifiNetworkModel.HotspotDeviceType.WATCH)
+ }
+
+ @Test
+ fun wifiNetwork_hotspot_auto() =
+ testScope.runTest {
+ featureFlags.set(Flags.INSTANT_TETHER, true)
+ val latest by collectLastValue(underTest.wifiNetwork)
+
+ val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_AUTO)
+ whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
+ getCallback().onWifiEntriesChanged()
+
+ assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
+ .isEqualTo(WifiNetworkModel.HotspotDeviceType.AUTO)
+ }
+
+ @Test
+ fun wifiNetwork_hotspot_invalid() =
+ testScope.runTest {
+ featureFlags.set(Flags.INSTANT_TETHER, true)
+ val latest by collectLastValue(underTest.wifiNetwork)
+
+ val wifiEntry = createHotspotWithType(1234)
+ whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
+ getCallback().onWifiEntriesChanged()
+
+ assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
+ .isEqualTo(WifiNetworkModel.HotspotDeviceType.INVALID)
+ }
+
+ @Test
+ fun wifiNetwork_hotspot_flagOff_valueNotUsed() =
+ testScope.runTest {
+ // WHEN the flag is off
+ featureFlags.set(Flags.INSTANT_TETHER, false)
+
+ val latest by collectLastValue(underTest.wifiNetwork)
+
+ val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_WATCH)
+ whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
+ getCallback().onWifiEntriesChanged()
+
+ // THEN NONE is always used, even if the wifi entry does have a hotspot device type
+ assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
+ .isEqualTo(WifiNetworkModel.HotspotDeviceType.NONE)
}
@Test
@@ -258,6 +526,7 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
mock<MergedCarrierEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.level).thenReturn(3)
+ whenever(this.subscriptionId).thenReturn(567)
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
@@ -265,7 +534,7 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
assertThat(latest is WifiNetworkModel.CarrierMerged).isTrue()
val latestMerged = latest as WifiNetworkModel.CarrierMerged
assertThat(latestMerged.level).isEqualTo(3)
- // numberOfLevels = maxSignalLevel + 1
+ assertThat(latestMerged.subscriptionId).isEqualTo(567)
}
@Test
@@ -288,30 +557,23 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
assertThat(latestMerged.numberOfLevels).isEqualTo(6)
}
- /* TODO(b/292534484): Re-enable this test once WifiTrackerLib gives us the subscription ID.
@Test
fun wifiNetwork_carrierMergedButInvalidSubId_flowHasInvalid() =
testScope.runTest {
val latest by collectLastValue(underTest.wifiNetwork)
- val wifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.isPrimary).thenReturn(true)
- whenever(this.isCarrierMerged).thenReturn(true)
+ val wifiEntry =
+ mock<MergedCarrierEntry>().apply {
+ whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.subscriptionId).thenReturn(INVALID_SUBSCRIPTION_ID)
}
+ whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
- getNetworkCallback()
- .onCapabilitiesChanged(
- NETWORK,
- createWifiNetworkCapabilities(wifiInfo),
- )
+ getCallback().onWifiEntriesChanged()
assertThat(latest).isInstanceOf(WifiNetworkModel.Invalid::class.java)
}
- */
-
@Test
fun wifiNetwork_notValidated_networkNotValidated() =
testScope.runTest {
@@ -382,7 +644,7 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.level).thenReturn(3)
- whenever(this.ssid).thenReturn("AB")
+ whenever(this.title).thenReturn("AB")
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
@@ -397,7 +659,7 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.level).thenReturn(4)
- whenever(this.ssid).thenReturn("CD")
+ whenever(this.title).thenReturn("CD")
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(newWifiEntry)
getCallback().onWifiEntriesChanged()
@@ -430,12 +692,12 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
val wifiEntry =
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
- whenever(this.ssid).thenReturn(SSID)
+ whenever(this.title).thenReturn(TITLE)
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
- assertThat((latest as WifiNetworkModel.Active).ssid).isEqualTo(SSID)
+ assertThat((latest as WifiNetworkModel.Active).ssid).isEqualTo(TITLE)
// WHEN we lose our current network
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(null)
@@ -480,7 +742,7 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
whenever(this.level).thenReturn(1)
- whenever(this.ssid).thenReturn(SSID)
+ whenever(this.title).thenReturn(TITLE)
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
@@ -488,7 +750,7 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
assertThat(latest1 is WifiNetworkModel.Active).isTrue()
val latest1Active = latest1 as WifiNetworkModel.Active
assertThat(latest1Active.level).isEqualTo(1)
- assertThat(latest1Active.ssid).isEqualTo(SSID)
+ assertThat(latest1Active.ssid).isEqualTo(TITLE)
// WHEN we add a second subscriber after having already emitted a value
val latest2 by collectLastValue(underTest.wifiNetwork)
@@ -497,7 +759,7 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
assertThat(latest2 is WifiNetworkModel.Active).isTrue()
val latest2Active = latest2 as WifiNetworkModel.Active
assertThat(latest2Active.level).isEqualTo(1)
- assertThat(latest2Active.ssid).isEqualTo(SSID)
+ assertThat(latest2Active.ssid).isEqualTo(TITLE)
}
@Test
@@ -541,40 +803,32 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
}
- /* TODO(b/292534484): Re-enable this test once WifiTrackerLib gives us the subscription ID.
- @Test
- fun isWifiConnectedWithValidSsid_invalidNetwork_false() =
- testScope.runTest {
- collectLastValue(underTest.wifiNetwork)
-
- val wifiInfo =
- mock<WifiInfo>().apply {
- whenever(this.isPrimary).thenReturn(true)
- whenever(this.isCarrierMerged).thenReturn(true)
- whenever(this.subscriptionId).thenReturn(INVALID_SUBSCRIPTION_ID)
- }
-
- getNetworkCallback()
- .onCapabilitiesChanged(
- NETWORK,
- createWifiNetworkCapabilities(wifiInfo),
- )
- testScope.runCurrent()
+ @Test
+ fun isWifiConnectedWithValidSsid_invalidNetwork_false() =
+ testScope.runTest {
+ collectLastValue(underTest.wifiNetwork)
- assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
- }
+ val wifiEntry =
+ mock<MergedCarrierEntry>().apply {
+ whenever(this.isPrimaryNetwork).thenReturn(true)
+ whenever(this.subscriptionId).thenReturn(INVALID_SUBSCRIPTION_ID)
+ }
+ whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
+ getCallback().onWifiEntriesChanged()
+ testScope.runCurrent()
- */
+ assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
+ }
@Test
- fun isWifiConnectedWithValidSsid_activeNetwork_nullSsid_false() =
+ fun isWifiConnectedWithValidSsid_activeNetwork_nullTitle_false() =
testScope.runTest {
collectLastValue(underTest.wifiNetwork)
val wifiEntry =
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
- whenever(this.ssid).thenReturn(null)
+ whenever(this.title).thenReturn(null)
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
@@ -584,14 +838,14 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
}
@Test
- fun isWifiConnectedWithValidSsid_activeNetwork_unknownSsid_false() =
+ fun isWifiConnectedWithValidSsid_activeNetwork_unknownTitle_false() =
testScope.runTest {
collectLastValue(underTest.wifiNetwork)
val wifiEntry =
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
- whenever(this.ssid).thenReturn(UNKNOWN_SSID)
+ whenever(this.title).thenReturn(UNKNOWN_SSID)
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
@@ -601,14 +855,14 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
}
@Test
- fun isWifiConnectedWithValidSsid_activeNetwork_validSsid_true() =
+ fun isWifiConnectedWithValidSsid_activeNetwork_validTitle_true() =
testScope.runTest {
collectLastValue(underTest.wifiNetwork)
val wifiEntry =
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
- whenever(this.ssid).thenReturn("fakeSsid")
+ whenever(this.title).thenReturn("fakeSsid")
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
@@ -626,7 +880,7 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
val wifiEntry =
mock<WifiEntry>().apply {
whenever(this.isPrimaryNetwork).thenReturn(true)
- whenever(this.ssid).thenReturn("fakeSsid")
+ whenever(this.title).thenReturn("fakeSsid")
}
whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
getCallback().onWifiEntriesChanged()
@@ -643,23 +897,74 @@ class WifiRepositoryViaTrackerLibTest : SysuiTestCase() {
assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse()
}
+ @Test
+ fun wifiActivity_callbackGivesNone_activityFlowHasNone() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.wifiActivity)
+
+ getTrafficStateCallback()
+ .onStateChanged(WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE)
+
+ assertThat(latest)
+ .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
+ }
+
+ @Test
+ fun wifiActivity_callbackGivesIn_activityFlowHasIn() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.wifiActivity)
+
+ getTrafficStateCallback()
+ .onStateChanged(WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN)
+
+ assertThat(latest)
+ .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = false))
+ }
+
+ @Test
+ fun wifiActivity_callbackGivesOut_activityFlowHasOut() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.wifiActivity)
+
+ getTrafficStateCallback()
+ .onStateChanged(WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT)
+
+ assertThat(latest)
+ .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = true))
+ }
+
+ @Test
+ fun wifiActivity_callbackGivesInout_activityFlowHasInAndOut() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.wifiActivity)
+
+ getTrafficStateCallback()
+ .onStateChanged(WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT)
+
+ assertThat(latest)
+ .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = true))
+ }
+
private fun getCallback(): WifiPickerTracker.WifiPickerTrackerCallback {
testScope.runCurrent()
return callbackCaptor.value
}
- private fun createRepo(): WifiRepositoryViaTrackerLib {
- return WifiRepositoryViaTrackerLib(
- testScope.backgroundScope,
- executor,
- wifiPickerTrackerFactory,
- wifiManager,
- logger,
- tableLogger,
- )
+ private fun getTrafficStateCallback(): WifiManager.TrafficStateCallback {
+ testScope.runCurrent()
+ val callbackCaptor = argumentCaptor<WifiManager.TrafficStateCallback>()
+ verify(wifiManager).registerTrafficStateCallback(any(), callbackCaptor.capture())
+ return callbackCaptor.value!!
+ }
+
+ private fun createHotspotWithType(@DeviceType type: Int): HotspotNetworkEntry {
+ return mock<HotspotNetworkEntry>().apply {
+ whenever(this.isPrimaryNetwork).thenReturn(true)
+ whenever(this.deviceType).thenReturn(type)
+ }
}
private companion object {
- const val SSID = "AB"
+ const val TITLE = "AB"
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt
index 4e0c309512e8..ba035bec340c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt
@@ -136,7 +136,8 @@ class WifiNetworkModelTest : SysuiTestCase() {
networkId = 5,
isValidated = true,
level = 3,
- ssid = "Test SSID"
+ ssid = "Test SSID",
+ hotspotDeviceType = WifiNetworkModel.HotspotDeviceType.LAPTOP,
)
activeNetwork.logDiffs(prevVal = WifiNetworkModel.Inactive, logger)
@@ -146,6 +147,7 @@ class WifiNetworkModelTest : SysuiTestCase() {
assertThat(logger.changes).contains(Pair(COL_VALIDATED, "true"))
assertThat(logger.changes).contains(Pair(COL_LEVEL, "3"))
assertThat(logger.changes).contains(Pair(COL_SSID, "Test SSID"))
+ assertThat(logger.changes).contains(Pair(COL_HOTSPOT, "LAPTOP"))
}
@Test
fun logDiffs_activeToInactive_resetsAllActiveFields() {
@@ -165,6 +167,7 @@ class WifiNetworkModelTest : SysuiTestCase() {
assertThat(logger.changes).contains(Pair(COL_VALIDATED, "false"))
assertThat(logger.changes).contains(Pair(COL_LEVEL, LEVEL_DEFAULT.toString()))
assertThat(logger.changes).contains(Pair(COL_SSID, "null"))
+ assertThat(logger.changes).contains(Pair(COL_HOTSPOT, "null"))
}
@Test
@@ -175,7 +178,8 @@ class WifiNetworkModelTest : SysuiTestCase() {
networkId = 5,
isValidated = true,
level = 3,
- ssid = "Test SSID"
+ ssid = "Test SSID",
+ hotspotDeviceType = WifiNetworkModel.HotspotDeviceType.AUTO,
)
val prevVal =
WifiNetworkModel.CarrierMerged(
@@ -191,6 +195,7 @@ class WifiNetworkModelTest : SysuiTestCase() {
assertThat(logger.changes).contains(Pair(COL_VALIDATED, "true"))
assertThat(logger.changes).contains(Pair(COL_LEVEL, "3"))
assertThat(logger.changes).contains(Pair(COL_SSID, "Test SSID"))
+ assertThat(logger.changes).contains(Pair(COL_HOTSPOT, "AUTO"))
}
@Test
fun logDiffs_activeToCarrierMerged_logsAllFields() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java
index c886f9bee07e..cdeb59278851 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java
@@ -29,6 +29,9 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Intent;
+import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbPort;
+import android.hardware.usb.UsbPortStatus;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.PowerManager;
@@ -56,6 +59,9 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
+import java.util.ArrayList;
+import java.util.List;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -65,8 +71,10 @@ public class BatteryControllerTest extends SysuiTestCase {
@Mock private BroadcastDispatcher mBroadcastDispatcher;
@Mock private DemoModeController mDemoModeController;
@Mock private View mView;
+ @Mock private UsbPort mUsbPort;
+ @Mock private UsbManager mUsbManager;
+ @Mock private UsbPortStatus mUsbPortStatus;
private BatteryControllerImpl mBatteryController;
-
private MockitoSession mMockitoSession;
@Before
@@ -255,4 +263,38 @@ public class BatteryControllerTest extends SysuiTestCase {
Assert.assertFalse(mBatteryController.isBatteryDefender());
}
+
+ @Test
+ public void complianceChanged_complianceIncompatible_outputsTrue() {
+ mContext.addMockSystemService(UsbManager.class, mUsbManager);
+ setupIncompatibleCharging();
+ Intent intent = new Intent(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED);
+
+ mBatteryController.onReceive(getContext(), intent);
+
+ Assert.assertTrue(mBatteryController.isIncompatibleCharging());
+ }
+
+ @Test
+ public void complianceChanged_emptyComplianceWarnings_outputsFalse() {
+ mContext.addMockSystemService(UsbManager.class, mUsbManager);
+ setupIncompatibleCharging();
+ when(mUsbPortStatus.getComplianceWarnings()).thenReturn(new int[1]);
+ Intent intent = new Intent(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED);
+
+ mBatteryController.onReceive(getContext(), intent);
+
+ Assert.assertFalse(mBatteryController.isIncompatibleCharging());
+ }
+
+ private void setupIncompatibleCharging() {
+ final List<UsbPort> usbPorts = new ArrayList<>();
+ usbPorts.add(mUsbPort);
+ when(mUsbManager.getPorts()).thenReturn(usbPorts);
+ when(mUsbPort.getStatus()).thenReturn(mUsbPortStatus);
+ when(mUsbPort.supportsComplianceWarnings()).thenReturn(true);
+ when(mUsbPortStatus.isConnected()).thenReturn(true);
+ when(mUsbPortStatus.getComplianceWarnings())
+ .thenReturn(new int[]{UsbPortStatus.COMPLIANCE_WARNING_OTHER});
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index 7c285b8aa1a9..ef39ff8ed521 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -62,7 +62,6 @@ import android.window.OnBackInvokedDispatcher;
import android.window.WindowOnBackInvokedDispatcher;
import androidx.annotation.NonNull;
-import androidx.core.animation.AnimatorTestRule;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
@@ -70,6 +69,7 @@ import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.AnimatorTestRule;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/VariableDateViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/VariableDateViewControllerTest.kt
index 871a48c503be..b698e70eb379 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/VariableDateViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/VariableDateViewControllerTest.kt
@@ -19,9 +19,11 @@ package com.android.systemui.statusbar.policy
import android.os.Handler
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import android.view.View
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.shade.ShadeExpansionStateManager
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.time.FakeSystemClock
@@ -59,6 +61,7 @@ class VariableDateViewControllerTest : SysuiTestCase() {
private var lastText: String? = null
+ private lateinit var shadeExpansionStateManager: ShadeExpansionStateManager
private lateinit var systemClock: FakeSystemClock
private lateinit var testableLooper: TestableLooper
private lateinit var testableHandler: Handler
@@ -76,6 +79,8 @@ class VariableDateViewControllerTest : SysuiTestCase() {
systemClock = FakeSystemClock()
systemClock.setCurrentTimeMillis(TIME_STAMP)
+ shadeExpansionStateManager = ShadeExpansionStateManager()
+
`when`(view.longerPattern).thenReturn(LONG_PATTERN)
`when`(view.shorterPattern).thenReturn(SHORT_PATTERN)
`when`(view.handler).thenReturn(testableHandler)
@@ -99,6 +104,7 @@ class VariableDateViewControllerTest : SysuiTestCase() {
controller = VariableDateViewController(
systemClock,
broadcastDispatcher,
+ shadeExpansionStateManager,
testableHandler,
view
)
@@ -121,7 +127,7 @@ class VariableDateViewControllerTest : SysuiTestCase() {
@Test
fun testLotsOfSpaceUseLongText() {
- onMeasureListenerCaptor.value.onMeasureAction(10000)
+ onMeasureListenerCaptor.value.onMeasureAction(10000, View.MeasureSpec.EXACTLY)
testableLooper.processAllMessages()
assertThat(lastText).isEqualTo(longText)
@@ -129,7 +135,7 @@ class VariableDateViewControllerTest : SysuiTestCase() {
@Test
fun testSmallSpaceUseEmpty() {
- onMeasureListenerCaptor.value.onMeasureAction(1)
+ onMeasureListenerCaptor.value.onMeasureAction(1, View.MeasureSpec.EXACTLY)
testableLooper.processAllMessages()
assertThat(lastText).isEmpty()
@@ -139,7 +145,7 @@ class VariableDateViewControllerTest : SysuiTestCase() {
fun testSpaceInBetweenUseShortText() {
val average = ((getTextLength(longText) + getTextLength(shortText)) / 2).toInt()
- onMeasureListenerCaptor.value.onMeasureAction(average)
+ onMeasureListenerCaptor.value.onMeasureAction(average, View.MeasureSpec.EXACTLY)
testableLooper.processAllMessages()
assertThat(lastText).isEqualTo(shortText)
@@ -147,10 +153,10 @@ class VariableDateViewControllerTest : SysuiTestCase() {
@Test
fun testSwitchBackToLonger() {
- onMeasureListenerCaptor.value.onMeasureAction(1)
+ onMeasureListenerCaptor.value.onMeasureAction(1, View.MeasureSpec.EXACTLY)
testableLooper.processAllMessages()
- onMeasureListenerCaptor.value.onMeasureAction(10000)
+ onMeasureListenerCaptor.value.onMeasureAction(10000, View.MeasureSpec.EXACTLY)
testableLooper.processAllMessages()
assertThat(lastText).isEqualTo(longText)
@@ -161,11 +167,41 @@ class VariableDateViewControllerTest : SysuiTestCase() {
`when`(view.freezeSwitching).thenReturn(true)
val average = ((getTextLength(longText) + getTextLength(shortText)) / 2).toInt()
- onMeasureListenerCaptor.value.onMeasureAction(average)
+ onMeasureListenerCaptor.value.onMeasureAction(average, View.MeasureSpec.EXACTLY)
testableLooper.processAllMessages()
assertThat(lastText).isEqualTo(longText)
- onMeasureListenerCaptor.value.onMeasureAction(1)
+ onMeasureListenerCaptor.value.onMeasureAction(1, View.MeasureSpec.EXACTLY)
+ testableLooper.processAllMessages()
+ assertThat(lastText).isEqualTo(longText)
+ }
+
+ @Test
+ fun testQsExpansionTrue_ignoreAtMostMeasureRequests() {
+ shadeExpansionStateManager.onQsExpansionFractionChanged(0f)
+
+ onMeasureListenerCaptor.value.onMeasureAction(
+ getTextLength(shortText).toInt(),
+ View.MeasureSpec.EXACTLY
+ )
+ testableLooper.processAllMessages()
+
+ onMeasureListenerCaptor.value.onMeasureAction(10000, View.MeasureSpec.AT_MOST)
+ testableLooper.processAllMessages()
+ assertThat(lastText).isEqualTo(shortText)
+ }
+
+ @Test
+ fun testQsExpansionFalse_acceptAtMostMeasureRequests() {
+ shadeExpansionStateManager.onQsExpansionFractionChanged(1f)
+
+ onMeasureListenerCaptor.value.onMeasureAction(
+ getTextLength(shortText).toInt(),
+ View.MeasureSpec.EXACTLY
+ )
+ testableLooper.processAllMessages()
+
+ onMeasureListenerCaptor.value.onMeasureAction(10000, View.MeasureSpec.AT_MOST)
testableLooper.processAllMessages()
assertThat(lastText).isEqualTo(longText)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/ListenerSetTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/ListenerSetTest.kt
index 2662da201460..1404a4fdbdae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/ListenerSetTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/ListenerSetTest.kt
@@ -16,43 +16,128 @@
package com.android.systemui.util
-import android.test.suitebuilder.annotation.SmallTest
-import androidx.test.runner.AndroidJUnit4
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
-class ListenerSetTest : SysuiTestCase() {
+open class ListenerSetTest : SysuiTestCase() {
- var runnableSet: ListenerSet<Runnable> = ListenerSet()
+ private val runnableSet: IListenerSet<Runnable> = makeRunnableListenerSet()
- @Before
- fun setup() {
- runnableSet = ListenerSet()
- }
+ open fun makeRunnableListenerSet(): IListenerSet<Runnable> = ListenerSet()
@Test
fun addIfAbsent_doesNotDoubleAdd() {
// setup & preconditions
val runnable1 = Runnable { }
val runnable2 = Runnable { }
- assertThat(runnableSet.toList()).isEmpty()
+ assertThat(runnableSet).isEmpty()
// Test that an element can be added
assertThat(runnableSet.addIfAbsent(runnable1)).isTrue()
- assertThat(runnableSet.toList()).containsExactly(runnable1)
+ assertThat(runnableSet).containsExactly(runnable1)
// Test that a second element can be added
assertThat(runnableSet.addIfAbsent(runnable2)).isTrue()
- assertThat(runnableSet.toList()).containsExactly(runnable1, runnable2)
+ assertThat(runnableSet).containsExactly(runnable1, runnable2)
// Test that re-adding the first element does nothing and returns false
assertThat(runnableSet.addIfAbsent(runnable1)).isFalse()
- assertThat(runnableSet.toList()).containsExactly(runnable1, runnable2)
+ assertThat(runnableSet).containsExactly(runnable1, runnable2)
+ }
+
+ @Test
+ fun isEmpty_changes() {
+ val runnable = Runnable { }
+ assertThat(runnableSet).isEmpty()
+ assertThat(runnableSet.isEmpty()).isTrue()
+ assertThat(runnableSet.isNotEmpty()).isFalse()
+
+ assertThat(runnableSet.addIfAbsent(runnable)).isTrue()
+ assertThat(runnableSet).isNotEmpty()
+ assertThat(runnableSet.isEmpty()).isFalse()
+ assertThat(runnableSet.isNotEmpty()).isTrue()
+
+ assertThat(runnableSet.remove(runnable)).isTrue()
+ assertThat(runnableSet).isEmpty()
+ assertThat(runnableSet.isEmpty()).isTrue()
+ assertThat(runnableSet.isNotEmpty()).isFalse()
+ }
+
+ @Test
+ fun size_changes() {
+ assertThat(runnableSet).isEmpty()
+ assertThat(runnableSet.size).isEqualTo(0)
+
+ assertThat(runnableSet.addIfAbsent(Runnable { })).isTrue()
+ assertThat(runnableSet.size).isEqualTo(1)
+
+ assertThat(runnableSet.addIfAbsent(Runnable { })).isTrue()
+ assertThat(runnableSet.size).isEqualTo(2)
+ }
+
+ @Test
+ fun contains_worksAsExpected() {
+ val runnable1 = Runnable { }
+ val runnable2 = Runnable { }
+ assertThat(runnableSet).isEmpty()
+ assertThat(runnable1 in runnableSet).isFalse()
+ assertThat(runnable2 in runnableSet).isFalse()
+ assertThat(runnableSet).doesNotContain(runnable1)
+ assertThat(runnableSet).doesNotContain(runnable2)
+
+ assertThat(runnableSet.addIfAbsent(runnable1)).isTrue()
+ assertThat(runnable1 in runnableSet).isTrue()
+ assertThat(runnable2 in runnableSet).isFalse()
+ assertThat(runnableSet).contains(runnable1)
+ assertThat(runnableSet).doesNotContain(runnable2)
+
+ assertThat(runnableSet.addIfAbsent(runnable2)).isTrue()
+ assertThat(runnable1 in runnableSet).isTrue()
+ assertThat(runnable2 in runnableSet).isTrue()
+ assertThat(runnableSet).contains(runnable1)
+ assertThat(runnableSet).contains(runnable2)
+
+ assertThat(runnableSet.remove(runnable1)).isTrue()
+ assertThat(runnable1 in runnableSet).isFalse()
+ assertThat(runnable2 in runnableSet).isTrue()
+ assertThat(runnableSet).doesNotContain(runnable1)
+ assertThat(runnableSet).contains(runnable2)
+ }
+
+ @Test
+ fun containsAll_worksAsExpected() {
+ val runnable1 = Runnable { }
+ val runnable2 = Runnable { }
+
+ assertThat(runnableSet).isEmpty()
+ assertThat(runnableSet.containsAll(listOf())).isTrue()
+ assertThat(runnableSet.containsAll(listOf(runnable1))).isFalse()
+ assertThat(runnableSet.containsAll(listOf(runnable2))).isFalse()
+ assertThat(runnableSet.containsAll(listOf(runnable1, runnable2))).isFalse()
+
+ assertThat(runnableSet.addIfAbsent(runnable1)).isTrue()
+ assertThat(runnableSet.containsAll(listOf())).isTrue()
+ assertThat(runnableSet.containsAll(listOf(runnable1))).isTrue()
+ assertThat(runnableSet.containsAll(listOf(runnable2))).isFalse()
+ assertThat(runnableSet.containsAll(listOf(runnable1, runnable2))).isFalse()
+
+ assertThat(runnableSet.addIfAbsent(runnable2)).isTrue()
+ assertThat(runnableSet.containsAll(listOf())).isTrue()
+ assertThat(runnableSet.containsAll(listOf(runnable1))).isTrue()
+ assertThat(runnableSet.containsAll(listOf(runnable2))).isTrue()
+ assertThat(runnableSet.containsAll(listOf(runnable1, runnable2))).isTrue()
+
+ assertThat(runnableSet.remove(runnable1)).isTrue()
+ assertThat(runnableSet.containsAll(listOf())).isTrue()
+ assertThat(runnableSet.containsAll(listOf(runnable1))).isFalse()
+ assertThat(runnableSet.containsAll(listOf(runnable2))).isTrue()
+ assertThat(runnableSet.containsAll(listOf(runnable1, runnable2))).isFalse()
}
@Test
@@ -60,22 +145,22 @@ class ListenerSetTest : SysuiTestCase() {
// setup and preconditions
val runnable1 = Runnable { }
val runnable2 = Runnable { }
- assertThat(runnableSet.toList()).isEmpty()
+ assertThat(runnableSet).isEmpty()
runnableSet.addIfAbsent(runnable1)
runnableSet.addIfAbsent(runnable2)
- assertThat(runnableSet.toList()).containsExactly(runnable1, runnable2)
+ assertThat(runnableSet).containsExactly(runnable1, runnable2)
// Test that removing the first runnable only removes that one runnable
assertThat(runnableSet.remove(runnable1)).isTrue()
- assertThat(runnableSet.toList()).containsExactly(runnable2)
+ assertThat(runnableSet).containsExactly(runnable2)
// Test that removing a non-present runnable does not error
assertThat(runnableSet.remove(runnable1)).isFalse()
- assertThat(runnableSet.toList()).containsExactly(runnable2)
+ assertThat(runnableSet).containsExactly(runnable2)
// Test that removing the other runnable succeeds
assertThat(runnableSet.remove(runnable2)).isTrue()
- assertThat(runnableSet.toList()).isEmpty()
+ assertThat(runnableSet).isEmpty()
}
@Test
@@ -92,17 +177,17 @@ class ListenerSetTest : SysuiTestCase() {
val runnable2 = Runnable {
runnablesCalled.add(2)
}
- assertThat(runnableSet.toList()).isEmpty()
+ assertThat(runnableSet).isEmpty()
runnableSet.addIfAbsent(runnable1)
runnableSet.addIfAbsent(runnable2)
- assertThat(runnableSet.toList()).containsExactly(runnable1, runnable2)
+ assertThat(runnableSet).containsExactly(runnable1, runnable2)
// Test that both runnables are called and 1 was removed
for (runnable in runnableSet) {
runnable.run()
}
assertThat(runnablesCalled).containsExactly(1, 2)
- assertThat(runnableSet.toList()).containsExactly(runnable2)
+ assertThat(runnableSet).containsExactly(runnable2)
}
@Test
@@ -120,16 +205,16 @@ class ListenerSetTest : SysuiTestCase() {
val runnable2 = Runnable {
runnablesCalled.add(2)
}
- assertThat(runnableSet.toList()).isEmpty()
+ assertThat(runnableSet).isEmpty()
runnableSet.addIfAbsent(runnable1)
runnableSet.addIfAbsent(runnable2)
- assertThat(runnableSet.toList()).containsExactly(runnable1, runnable2)
+ assertThat(runnableSet).containsExactly(runnable1, runnable2)
// Test that both original runnables are called and 99 was added but not called
for (runnable in runnableSet) {
runnable.run()
}
assertThat(runnablesCalled).containsExactly(1, 2)
- assertThat(runnableSet.toList()).containsExactly(runnable1, runnable2, runnable99)
+ assertThat(runnableSet).containsExactly(runnable1, runnable2, runnable99)
}
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/NamedListenerSetTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/NamedListenerSetTest.kt
new file mode 100644
index 000000000000..c89e317a6ad9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/NamedListenerSetTest.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class NamedListenerSetTest : ListenerSetTest() {
+ override fun makeRunnableListenerSet(): IListenerSet<Runnable> = NamedListenerSet()
+
+ private val runnableSet = NamedListenerSet(NamedRunnable::name)
+
+ class NamedRunnable(val name: String, private val block: () -> Unit = {}) : Runnable {
+ override fun run() = block()
+ }
+
+ @Test
+ fun addIfAbsent_addsMultipleWithSameName_onlyIfInstanceIsAbsent() {
+ // setup & preconditions
+ val runnable1 = NamedRunnable("A")
+ val runnable2 = NamedRunnable("A")
+ assertThat(runnableSet).isEmpty()
+
+ // Test that an element can be added
+ assertThat(runnableSet.addIfAbsent(runnable1)).isTrue()
+ assertThat(runnableSet).containsExactly(runnable1)
+
+ // Test that a second element can be added, even with the same name
+ assertThat(runnableSet.addIfAbsent(runnable2)).isTrue()
+ assertThat(runnableSet).containsExactly(runnable1, runnable2)
+
+ // Test that re-adding the first element does nothing and returns false
+ assertThat(runnableSet.addIfAbsent(runnable1)).isFalse()
+ assertThat(runnableSet).containsExactly(runnable1, runnable2)
+ }
+
+ @Test
+ fun forEachNamed_includesCorrectNames() {
+ val runnable1 = NamedRunnable("A")
+ val runnable2 = NamedRunnable("X")
+ val runnable3 = NamedRunnable("X")
+ assertThat(runnableSet).isEmpty()
+
+ assertThat(runnableSet.addIfAbsent(runnable1)).isTrue()
+ assertThat(runnableSet.toNamedPairs())
+ .containsExactly(
+ "A" to runnable1,
+ )
+
+ assertThat(runnableSet.addIfAbsent(runnable2)).isTrue()
+ assertThat(runnableSet.toNamedPairs())
+ .containsExactly(
+ "A" to runnable1,
+ "X" to runnable2,
+ )
+
+ assertThat(runnableSet.addIfAbsent(runnable3)).isTrue()
+ assertThat(runnableSet.toNamedPairs())
+ .containsExactly(
+ "A" to runnable1,
+ "X" to runnable2,
+ "X" to runnable3,
+ )
+
+ assertThat(runnableSet.remove(runnable1)).isTrue()
+ assertThat(runnableSet.toNamedPairs())
+ .containsExactly(
+ "X" to runnable2,
+ "X" to runnable3,
+ )
+
+ assertThat(runnableSet.remove(runnable2)).isTrue()
+ assertThat(runnableSet.toNamedPairs())
+ .containsExactly(
+ "X" to runnable3,
+ )
+ }
+
+ /**
+ * This private method uses [NamedListenerSet.forEachNamed] to produce a list of pairs in order
+ * to validate that method.
+ */
+ private fun <T : Any> NamedListenerSet<T>.toNamedPairs() =
+ sequence { forEachNamed { name, listener -> yield(name to listener) } }.toList()
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index ee11cb63a375..fa18e575220c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -38,6 +38,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.animation.AnimatorTestRule;
import android.app.KeyguardManager;
import android.content.res.Configuration;
import android.media.AudioManager;
@@ -84,6 +85,7 @@ import java.util.function.Predicate;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class VolumeDialogImplTest extends SysuiTestCase {
+ private static final AnimatorTestRule sAnimatorTestRule = new AnimatorTestRule();
VolumeDialogImpl mDialog;
View mActiveRinger;
@@ -126,6 +128,7 @@ public class VolumeDialogImplTest extends SysuiTestCase {
};
private FakeFeatureFlags mFeatureFlags;
+ private int mLongestHideShowAnimationDuration = 250;
@Before
public void setup() throws Exception {
@@ -138,6 +141,13 @@ public class VolumeDialogImplTest extends SysuiTestCase {
when(mPostureController.getDevicePosture())
.thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED);
+ int hideDialogDuration = mContext.getResources()
+ .getInteger(R.integer.config_dialogHideAnimationDurationMs);
+ int showDialogDuration = mContext.getResources()
+ .getInteger(R.integer.config_dialogShowAnimationDurationMs);
+
+ mLongestHideShowAnimationDuration = Math.max(hideDialogDuration, showDialogDuration);
+
mOriginalOrientation = mContext.getResources().getConfiguration().orientation;
mConfigurationController = new FakeConfigurationController();
@@ -717,6 +727,8 @@ public class VolumeDialogImplTest extends SysuiTestCase {
public void teardown() {
cleanUp(mDialog);
setOrientation(mOriginalOrientation);
+ sAnimatorTestRule.advanceTimeBy(mLongestHideShowAnimationDuration);
+ mTestableLooper.moveTimeForward(mLongestHideShowAnimationDuration);
mTestableLooper.processAllMessages();
reset(mPostureController);
}
diff --git a/packages/SystemUI/tests/utils/src/android/animation/AnimatorTestRule.java b/packages/SystemUI/tests/utils/src/android/animation/AnimatorTestRule.java
index 6535f333f428..19c68e86e5dc 100644
--- a/packages/SystemUI/tests/utils/src/android/animation/AnimatorTestRule.java
+++ b/packages/SystemUI/tests/utils/src/android/animation/AnimatorTestRule.java
@@ -18,6 +18,7 @@ package android.animation;
import android.animation.AnimationHandler.AnimationFrameCallback;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Looper;
import android.os.SystemClock;
import android.util.AndroidRuntimeException;
@@ -31,6 +32,7 @@ import org.junit.runners.model.Statement;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
/**
* JUnit {@link TestRule} that can be used to run {@link Animator}s without actually waiting for the
@@ -125,14 +127,40 @@ public final class AnimatorTestRule implements TestRule {
* @param timeDelta the amount of milliseconds to advance
*/
public void advanceTimeBy(long timeDelta) {
+ advanceTimeBy(timeDelta, null);
+ }
+
+ /**
+ * Advances the animation clock by the given amount of delta in milliseconds. This call will
+ * produce an animation frame to all the ongoing animations. This method needs to be
+ * called on the same thread as {@link Animator#start()}.
+ * <p>
+ * This method is not for test authors, but for rule authors to ensure that multiple animators
+ * can be advanced in sync.
+ *
+ * @param timeDelta the amount of milliseconds to advance
+ * @param preFrameAction a consumer to be passed the timeDelta following the time advancement
+ * but prior to the frame production.
+ */
+ public void advanceTimeBy(long timeDelta, @Nullable Consumer<Long> preFrameAction) {
Preconditions.checkArgumentNonnegative(timeDelta, "timeDelta must not be negative");
requireLooper("AnimationTestRule#advanceTimeBy(long)");
- // before advancing time, start new animators with the current time
- initNewAnimators();
+ if (timeDelta == 0) {
+ // If time is not being advanced, all animators will get a tick; don't double tick these
+ mTestHandler.mNewCallbacks.clear();
+ } else {
+ // before advancing time, start new animators with the current time
+ initNewAnimators();
+ }
synchronized (mLock) {
// advance time
mTotalTimeDelta += timeDelta;
}
+ if (preFrameAction != null) {
+ preFrameAction.accept(timeDelta);
+ // After letting other code run, clear any new callbacks to avoid double-ticking them
+ mTestHandler.mNewCallbacks.clear();
+ }
// produce a frame
mTestHandler.doFrame();
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/AnimatorTestRule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/AnimatorTestRule.kt
new file mode 100644
index 000000000000..0ced19e3d5f3
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/AnimatorTestRule.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.animation
+
+import java.util.function.Consumer
+import org.junit.rules.RuleChain
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/**
+ * A rule that wraps both [androidx.core.animation.AnimatorTestRule] and
+ * [android.animation.AnimatorTestRule] such that the clocks of the two animation handlers can be
+ * advanced together.
+ */
+class AnimatorTestRule : TestRule {
+ private val androidxRule = androidx.core.animation.AnimatorTestRule()
+ private val platformRule = android.animation.AnimatorTestRule()
+ private val advanceAndroidXTimeBy =
+ Consumer<Long> { timeDelta -> androidxRule.advanceTimeBy(timeDelta) }
+
+ /**
+ * Chain is for simplicity not to force a particular order; order should not matter, because
+ * each rule affects a different AnimationHandler classes, and no callbacks to code under test
+ * should be triggered by these rules
+ */
+ private val ruleChain = RuleChain.emptyRuleChain().around(androidxRule).around(platformRule)
+
+ override fun apply(base: Statement, description: Description): Statement =
+ ruleChain.apply(base, description)
+
+ /**
+ * Advances the animation clock by the given amount of delta in milliseconds. This call will
+ * produce an animation frame to all the ongoing animations.
+ *
+ * @param timeDelta the amount of milliseconds to advance
+ */
+ fun advanceTimeBy(timeDelta: Long) {
+ // NOTE: To avoid errors with order, we have to ensure that we advance the time within both
+ // rules before either rule does its frame output. Failing to do this could cause the
+ // animation from one to start later than the other.
+ platformRule.advanceTimeBy(timeDelta, advanceAndroidXTimeBy)
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
index c2e1ac70af80..7c98df6c6317 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
@@ -20,7 +20,8 @@ import com.android.internal.widget.LockPatternUtils
import com.android.internal.widget.LockPatternView
import com.android.internal.widget.LockscreenCredential
import com.android.keyguard.KeyguardSecurityModel.SecurityMode
-import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.authentication.data.model.AuthenticationMethodModel
+import com.android.systemui.authentication.shared.model.AuthenticationPatternCoordinate
import com.android.systemui.authentication.shared.model.AuthenticationResultModel
import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
import kotlinx.coroutines.flow.MutableStateFlow
@@ -47,7 +48,7 @@ class FakeAuthenticationRepository(
private val _authenticationMethod =
MutableStateFlow<AuthenticationMethodModel>(DEFAULT_AUTHENTICATION_METHOD)
- val authenticationMethod: StateFlow<AuthenticationMethodModel> =
+ override val authenticationMethod: StateFlow<AuthenticationMethodModel> =
_authenticationMethod.asStateFlow()
private var isLockscreenEnabled = true
@@ -154,13 +155,13 @@ class FakeAuthenticationRepository(
val DEFAULT_AUTHENTICATION_METHOD = AuthenticationMethodModel.Pin
val PATTERN =
listOf(
- AuthenticationMethodModel.Pattern.PatternCoordinate(2, 0),
- AuthenticationMethodModel.Pattern.PatternCoordinate(2, 1),
- AuthenticationMethodModel.Pattern.PatternCoordinate(2, 2),
- AuthenticationMethodModel.Pattern.PatternCoordinate(1, 1),
- AuthenticationMethodModel.Pattern.PatternCoordinate(0, 0),
- AuthenticationMethodModel.Pattern.PatternCoordinate(0, 1),
- AuthenticationMethodModel.Pattern.PatternCoordinate(0, 2),
+ AuthenticationPatternCoordinate(2, 0),
+ AuthenticationPatternCoordinate(2, 1),
+ AuthenticationPatternCoordinate(2, 2),
+ AuthenticationPatternCoordinate(1, 1),
+ AuthenticationPatternCoordinate(0, 0),
+ AuthenticationPatternCoordinate(0, 1),
+ AuthenticationPatternCoordinate(0, 2),
)
const val MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING = 5
const val THROTTLE_DURATION_MS = 30000
@@ -172,7 +173,6 @@ class FakeAuthenticationRepository(
is AuthenticationMethodModel.Pin -> SecurityMode.PIN
is AuthenticationMethodModel.Password -> SecurityMode.Password
is AuthenticationMethodModel.Pattern -> SecurityMode.Pattern
- is AuthenticationMethodModel.Swipe,
is AuthenticationMethodModel.None -> SecurityMode.None
}
}
@@ -208,8 +208,7 @@ class FakeAuthenticationRepository(
}
}
- private fun List<AuthenticationMethodModel.Pattern.PatternCoordinate>.toCells():
- List<LockPatternView.Cell> {
+ private fun List<AuthenticationPatternCoordinate>.toCells(): List<LockPatternView.Cell> {
return map { coordinate -> LockPatternView.Cell.of(coordinate.y, coordinate.x) }
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
index 36fa7e65d8ec..013dbb458c22 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
@@ -19,45 +19,45 @@ package com.android.systemui.flags
import java.io.PrintWriter
class FakeFeatureFlags : FeatureFlags {
- private val booleanFlags = mutableMapOf<Int, Boolean>()
- private val stringFlags = mutableMapOf<Int, String>()
- private val intFlags = mutableMapOf<Int, Int>()
- private val knownFlagNames = mutableMapOf<Int, String>()
- private val flagListeners = mutableMapOf<Int, MutableSet<FlagListenable.Listener>>()
- private val listenerFlagIds = mutableMapOf<FlagListenable.Listener, MutableSet<Int>>()
+ private val booleanFlags = mutableMapOf<String, Boolean>()
+ private val stringFlags = mutableMapOf<String, String>()
+ private val intFlags = mutableMapOf<String, Int>()
+ private val knownFlagNames = mutableMapOf<String, String>()
+ private val flagListeners = mutableMapOf<String, MutableSet<FlagListenable.Listener>>()
+ private val listenerflagNames = mutableMapOf<FlagListenable.Listener, MutableSet<String>>()
init {
FlagsFactory.knownFlags.forEach { entry: Map.Entry<String, Flag<*>> ->
- knownFlagNames[entry.value.id] = entry.key
+ knownFlagNames[entry.value.name] = entry.key
}
}
fun set(flag: BooleanFlag, value: Boolean) {
- if (booleanFlags.put(flag.id, value)?.let { value != it } != false) {
+ if (booleanFlags.put(flag.name, value)?.let { value != it } != false) {
notifyFlagChanged(flag)
}
}
fun set(flag: ResourceBooleanFlag, value: Boolean) {
- if (booleanFlags.put(flag.id, value)?.let { value != it } != false) {
+ if (booleanFlags.put(flag.name, value)?.let { value != it } != false) {
notifyFlagChanged(flag)
}
}
fun set(flag: SysPropBooleanFlag, value: Boolean) {
- if (booleanFlags.put(flag.id, value)?.let { value != it } != false) {
+ if (booleanFlags.put(flag.name, value)?.let { value != it } != false) {
notifyFlagChanged(flag)
}
}
fun set(flag: StringFlag, value: String) {
- if (stringFlags.put(flag.id, value)?.let { value != it } == null) {
+ if (stringFlags.put(flag.name, value)?.let { value != it } == null) {
notifyFlagChanged(flag)
}
}
fun set(flag: ResourceStringFlag, value: String) {
- if (stringFlags.put(flag.id, value)?.let { value != it } == null) {
+ if (stringFlags.put(flag.name, value)?.let { value != it } == null) {
notifyFlagChanged(flag)
}
}
@@ -73,7 +73,7 @@ class FakeFeatureFlags : FeatureFlags {
* and the flag value *does* matter, you'll notice when the flag is flipped and tests
* start failing.
*/
- fun setDefault(flag: BooleanFlag) = booleanFlags.putIfAbsent(flag.id, flag.default)
+ fun setDefault(flag: BooleanFlag) = booleanFlags.putIfAbsent(flag.name, flag.default)
/**
* Set the given flag's default value if no other value has been set.
@@ -86,10 +86,10 @@ class FakeFeatureFlags : FeatureFlags {
* and the flag value *does* matter, you'll notice when the flag is flipped and tests
* start failing.
*/
- fun setDefault(flag: SysPropBooleanFlag) = booleanFlags.putIfAbsent(flag.id, flag.default)
+ fun setDefault(flag: SysPropBooleanFlag) = booleanFlags.putIfAbsent(flag.name, flag.default)
private fun notifyFlagChanged(flag: Flag<*>) {
- flagListeners[flag.id]?.let { listeners ->
+ flagListeners[flag.name]?.let { listeners ->
listeners.forEach { listener ->
listener.onFlagChanged(
object : FlagListenable.FlagEvent {
@@ -101,30 +101,30 @@ class FakeFeatureFlags : FeatureFlags {
}
}
- override fun isEnabled(flag: UnreleasedFlag): Boolean = requireBooleanValue(flag.id)
+ override fun isEnabled(flag: UnreleasedFlag): Boolean = requireBooleanValue(flag.name)
- override fun isEnabled(flag: ReleasedFlag): Boolean = requireBooleanValue(flag.id)
+ override fun isEnabled(flag: ReleasedFlag): Boolean = requireBooleanValue(flag.name)
- override fun isEnabled(flag: ResourceBooleanFlag): Boolean = requireBooleanValue(flag.id)
+ override fun isEnabled(flag: ResourceBooleanFlag): Boolean = requireBooleanValue(flag.name)
- override fun isEnabled(flag: SysPropBooleanFlag): Boolean = requireBooleanValue(flag.id)
+ override fun isEnabled(flag: SysPropBooleanFlag): Boolean = requireBooleanValue(flag.name)
- override fun getString(flag: StringFlag): String = requireStringValue(flag.id)
+ override fun getString(flag: StringFlag): String = requireStringValue(flag.name)
- override fun getString(flag: ResourceStringFlag): String = requireStringValue(flag.id)
+ override fun getString(flag: ResourceStringFlag): String = requireStringValue(flag.name)
- override fun getInt(flag: IntFlag): Int = requireIntValue(flag.id)
+ override fun getInt(flag: IntFlag): Int = requireIntValue(flag.name)
- override fun getInt(flag: ResourceIntFlag): Int = requireIntValue(flag.id)
+ override fun getInt(flag: ResourceIntFlag): Int = requireIntValue(flag.name)
override fun addListener(flag: Flag<*>, listener: FlagListenable.Listener) {
- flagListeners.getOrPut(flag.id) { mutableSetOf() }.add(listener)
- listenerFlagIds.getOrPut(listener) { mutableSetOf() }.add(flag.id)
+ flagListeners.getOrPut(flag.name) { mutableSetOf() }.add(listener)
+ listenerflagNames.getOrPut(listener) { mutableSetOf() }.add(flag.name)
}
override fun removeListener(listener: FlagListenable.Listener) {
- listenerFlagIds.remove(listener)?.let {
- flagIds -> flagIds.forEach {
+ listenerflagNames.remove(listener)?.let {
+ flagNames -> flagNames.forEach {
id -> flagListeners[id]?.remove(listener)
}
}
@@ -134,22 +134,22 @@ class FakeFeatureFlags : FeatureFlags {
// no-op
}
- private fun flagName(flagId: Int): String {
- return knownFlagNames[flagId] ?: "UNKNOWN(id=$flagId)"
+ private fun flagName(flagName: String): String {
+ return knownFlagNames[flagName] ?: "UNKNOWN($flagName)"
}
- private fun requireBooleanValue(flagId: Int): Boolean {
- return booleanFlags[flagId]
- ?: error("Flag ${flagName(flagId)} was accessed as boolean but not specified.")
+ private fun requireBooleanValue(flagName: String): Boolean {
+ return booleanFlags[flagName]
+ ?: error("Flag ${flagName(flagName)} was accessed as boolean but not specified.")
}
- private fun requireStringValue(flagId: Int): String {
- return stringFlags[flagId]
- ?: error("Flag ${flagName(flagId)} was accessed as string but not specified.")
+ private fun requireStringValue(flagName: String): String {
+ return stringFlags[flagName]
+ ?: error("Flag ${flagName(flagName)} was accessed as string but not specified.")
}
- private fun requireIntValue(flagId: Int): Int {
- return intFlags[flagId]
- ?: error("Flag ${flagName(flagId)} was accessed as int but not specified.")
+ private fun requireIntValue(flagName: String): Int {
+ return intFlags[flagName]
+ ?: error("Flag ${flagName(flagName)} was accessed as int but not specified.")
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 15ce055bcc63..faebcaac1be3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -146,7 +146,6 @@ class FakeKeyguardRepository : KeyguardRepository {
_animateBottomAreaDozingTransitions.tryEmit(animate)
}
-
@Deprecated("Deprecated as part of b/278057014")
override fun setBottomAreaAlpha(alpha: Float) {
_bottomAreaAlpha.value = alpha
@@ -257,8 +256,11 @@ class FakeKeyguardRepository : KeyguardRepository {
goingToFullShade: Boolean,
occlusionTransitionRunning: Boolean
) {
- _keyguardRootViewVisibility.value = KeyguardRootViewVisibilityState(
- statusBarState, goingToFullShade, occlusionTransitionRunning
- )
+ _keyguardRootViewVisibility.value =
+ KeyguardRootViewVisibilityState(
+ statusBarState,
+ goingToFullShade,
+ occlusionTransitionRunning
+ )
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index 6cffb669d466..507267e2d185 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -32,7 +32,6 @@ import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
import com.android.systemui.keyguard.shared.model.WakeSleepReason
import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.keyguard.shared.model.WakefulnessState
@@ -98,7 +97,7 @@ class SceneTestUtils(
fun fakeSceneContainerRepository(
containerConfig: SceneContainerConfig = fakeSceneContainerConfig(),
): SceneContainerRepository {
- return SceneContainerRepository(containerConfig)
+ return SceneContainerRepository(applicationScope(), containerConfig)
}
fun fakeSceneKeys(): List<SceneKey> {
@@ -176,23 +175,14 @@ class SceneTestUtils(
fun bouncerViewModel(
bouncerInteractor: BouncerInteractor,
+ authenticationInteractor: AuthenticationInteractor,
): BouncerViewModel {
return BouncerViewModel(
applicationContext = context,
applicationScope = applicationScope(),
- interactor = bouncerInteractor,
- featureFlags = featureFlags,
- )
- }
-
- fun lockScreenSceneInteractor(
- authenticationInteractor: AuthenticationInteractor,
- bouncerInteractor: BouncerInteractor,
- ): LockscreenSceneInteractor {
- return LockscreenSceneInteractor(
- applicationScope = applicationScope(),
- authenticationInteractor = authenticationInteractor,
bouncerInteractor = bouncerInteractor,
+ authenticationInteractor = authenticationInteractor,
+ featureFlags = featureFlags,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeDisplayTracker.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeDisplayTracker.kt
index 1403cea1c625..3fd11a1db96f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeDisplayTracker.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeDisplayTracker.kt
@@ -26,7 +26,7 @@ class FakeDisplayTracker constructor(val context: Context) : DisplayTracker {
override var defaultDisplayId: Int = Display.DEFAULT_DISPLAY
override var allDisplays: Array<Display> = displayManager.displays
- private val displayCallbacks: MutableList<DisplayTracker.Callback> = ArrayList()
+ val displayCallbacks: MutableList<DisplayTracker.Callback> = ArrayList()
private val brightnessCallbacks: MutableList<DisplayTracker.Callback> = ArrayList()
override fun addDisplayChangeCallback(callback: DisplayTracker.Callback, executor: Executor) {
displayCallbacks.add(callback)
@@ -43,12 +43,12 @@ class FakeDisplayTracker constructor(val context: Context) : DisplayTracker {
brightnessCallbacks.remove(callback)
}
- fun setDefaultDisplay(displayId: Int) {
- defaultDisplayId = displayId
+ override fun getDisplay(displayId: Int): Display {
+ return allDisplays.filter { display -> display.displayId == displayId }[0]
}
- fun setDisplays(displays: Array<Display>) {
- allDisplays = displays
+ fun setDefaultDisplay(displayId: Int) {
+ defaultDisplayId = displayId
}
fun triggerOnDisplayAdded(displayId: Int) {
diff --git a/services/Android.bp b/services/Android.bp
index 53dc06805f14..9264172974e1 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -115,7 +115,6 @@ filegroup {
":services.profcollect-sources",
":services.restrictions-sources",
":services.searchui-sources",
- ":services.selectiontoolbar-sources",
":services.smartspace-sources",
":services.soundtrigger-sources",
":services.systemcaptions-sources",
@@ -174,7 +173,6 @@ java_library {
"services.profcollect",
"services.restrictions",
"services.searchui",
- "services.selectiontoolbar",
"services.smartspace",
"services.soundtrigger",
"services.systemcaptions",
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 37abe1b1aee3..061b4221ecf7 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -4204,7 +4204,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
// We don't send an empty response to IME so that it doesn't cause UI flicker
// on the IME side if it arrives before the input view is finished on the IME.
mInlineSessionController.resetInlineFillUiLocked();
- mCurrentViewId = null;
+
+ if ((viewState.getState() &
+ ViewState.STATE_PENDING_CREATE_INLINE_REQUEST) != 0) {
+ // View was exited before Inline Request sent back, do not set it to
+ // null yet to let onHandleAssistData finish processing
+ } else {
+ mCurrentViewId = null;
+ }
+
mPresentationStatsEventLogger.maybeSetNoPresentationEventReason(
NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED);
diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
index 631b4531b9b9..fd45d2423227 100644
--- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
@@ -281,9 +281,9 @@ class AssociationRequestsProcessor {
final long timestamp = System.currentTimeMillis();
final AssociationInfo association = new AssociationInfo(id, userId, packageName,
- macAddress, displayName, deviceProfile, associatedDevice, selfManaged,
- /* notifyOnDeviceNearby */ false, /* revoked */ false, timestamp, Long.MAX_VALUE,
- /* systemDataSyncFlags */ 0);
+ /* tag */ null, macAddress, displayName, deviceProfile, associatedDevice,
+ selfManaged, /* notifyOnDeviceNearby */ false, /* revoked */ false,
+ timestamp, Long.MAX_VALUE, /* systemDataSyncFlags */ 0);
if (deviceProfile != null) {
// If the "Device Profile" is specified, make the companion application a holder of the
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index c5501f1d3e0d..e80cba7946df 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -668,7 +668,6 @@ public class CompanionDeviceManagerService extends SystemService {
addOnAssociationsChangedListener_enforcePermission();
enforceCallerIsSystemOrCanInteractWithUserId(getContext(), userId);
-
mListeners.register(listener, userId);
}
@@ -1015,6 +1014,18 @@ public class CompanionDeviceManagerService extends SystemService {
}
@Override
+ public void setAssociationTag(int associationId, String tag) {
+ AssociationInfo association = getAssociationWithCallerChecks(associationId);
+ association = AssociationInfo.builder(association).setTag(tag).build();
+ mAssociationStore.updateAssociation(association);
+ }
+
+ @Override
+ public void clearAssociationTag(int associationId) {
+ setAssociationTag(associationId, null);
+ }
+
+ @Override
public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
String[] args, ShellCallback callback, ResultReceiver resultReceiver)
throws RemoteException {
diff --git a/services/companion/java/com/android/server/companion/PersistentDataStore.java b/services/companion/java/com/android/server/companion/PersistentDataStore.java
index 54798f4f7fcc..b4b93793d549 100644
--- a/services/companion/java/com/android/server/companion/PersistentDataStore.java
+++ b/services/companion/java/com/android/server/companion/PersistentDataStore.java
@@ -171,6 +171,7 @@ final class PersistentDataStore {
private static final String XML_TAG_ASSOCIATION = "association";
private static final String XML_TAG_PREVIOUSLY_USED_IDS = "previously-used-ids";
private static final String XML_TAG_PACKAGE = "package";
+ private static final String XML_TAG_TAG = "tag";
private static final String XML_TAG_ID = "id";
private static final String XML_ATTR_PERSISTENCE_VERSION = "persistence-version";
@@ -421,6 +422,7 @@ final class PersistentDataStore {
requireStartOfTag(parser, XML_TAG_ASSOCIATION);
final String appPackage = readStringAttribute(parser, XML_ATTR_PACKAGE);
+ final String tag = readStringAttribute(parser, XML_TAG_TAG);
final String deviceAddress = readStringAttribute(parser, LEGACY_XML_ATTR_DEVICE);
if (appPackage == null || deviceAddress == null) return;
@@ -429,7 +431,7 @@ final class PersistentDataStore {
final boolean notify = readBooleanAttribute(parser, XML_ATTR_NOTIFY_DEVICE_NEARBY);
final long timeApproved = readLongAttribute(parser, XML_ATTR_TIME_APPROVED, 0L);
- out.add(new AssociationInfo(associationId, userId, appPackage,
+ out.add(new AssociationInfo(associationId, userId, appPackage, tag,
MacAddress.fromString(deviceAddress), null, profile, null,
/* managedByCompanionApp */ false, notify, /* revoked */ false, timeApproved,
Long.MAX_VALUE, /* systemDataSyncFlags */ 0));
@@ -456,6 +458,7 @@ final class PersistentDataStore {
final int associationId = readIntAttribute(parser, XML_ATTR_ID);
final String profile = readStringAttribute(parser, XML_ATTR_PROFILE);
final String appPackage = readStringAttribute(parser, XML_ATTR_PACKAGE);
+ final String tag = readStringAttribute(parser, XML_TAG_TAG);
final MacAddress macAddress = stringToMacAddress(
readStringAttribute(parser, XML_ATTR_MAC_ADDRESS));
final String displayName = readStringAttribute(parser, XML_ATTR_DISPLAY_NAME);
@@ -469,7 +472,7 @@ final class PersistentDataStore {
XML_ATTR_SYSTEM_DATA_SYNC_FLAGS, 0);
final AssociationInfo associationInfo = createAssociationInfoNoThrow(associationId, userId,
- appPackage, macAddress, displayName, profile, selfManaged, notify, revoked,
+ appPackage, tag, macAddress, displayName, profile, selfManaged, notify, revoked,
timeApproved, lastTimeConnected, systemDataSyncFlags);
if (associationInfo != null) {
out.add(associationInfo);
@@ -518,6 +521,7 @@ final class PersistentDataStore {
writeIntAttribute(serializer, XML_ATTR_ID, a.getId());
writeStringAttribute(serializer, XML_ATTR_PROFILE, a.getDeviceProfile());
writeStringAttribute(serializer, XML_ATTR_PACKAGE, a.getPackageName());
+ writeStringAttribute(serializer, XML_TAG_TAG, a.getTag());
writeStringAttribute(serializer, XML_ATTR_MAC_ADDRESS, a.getDeviceMacAddressAsString());
writeStringAttribute(serializer, XML_ATTR_DISPLAY_NAME, a.getDisplayName());
writeBooleanAttribute(serializer, XML_ATTR_SELF_MANAGED, a.isSelfManaged());
@@ -565,17 +569,17 @@ final class PersistentDataStore {
}
private static AssociationInfo createAssociationInfoNoThrow(int associationId,
- @UserIdInt int userId, @NonNull String appPackage, @Nullable MacAddress macAddress,
- @Nullable CharSequence displayName, @Nullable String profile, boolean selfManaged,
- boolean notify, boolean revoked, long timeApproved, long lastTimeConnected,
- int systemDataSyncFlags) {
+ @UserIdInt int userId, @NonNull String appPackage, @Nullable String tag,
+ @Nullable MacAddress macAddress, @Nullable CharSequence displayName,
+ @Nullable String profile, boolean selfManaged, boolean notify, boolean revoked,
+ long timeApproved, long lastTimeConnected, int systemDataSyncFlags) {
AssociationInfo associationInfo = null;
try {
// We do not persist AssociatedDevice, which means that AssociationInfo retrieved from
// datastore is not guaranteed to be identical to the one from initial association.
- associationInfo = new AssociationInfo(associationId, userId, appPackage, macAddress,
- displayName, profile, null, selfManaged, notify, revoked,
- timeApproved, lastTimeConnected, systemDataSyncFlags);
+ associationInfo = new AssociationInfo(associationId, userId, appPackage, tag,
+ macAddress, displayName, profile, null, selfManaged, notify,
+ revoked, timeApproved, lastTimeConnected, systemDataSyncFlags);
} catch (Exception e) {
if (DEBUG) Log.w(TAG, "Could not create AssociationInfo", e);
}
diff --git a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
index f45a1c42e14f..8fea078c3183 100644
--- a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
+++ b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
@@ -281,43 +281,30 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange
case DEVICE_EVENT_BLE_APPEARED:
case DEVICE_EVENT_BT_CONNECTED:
case DEVICE_EVENT_SELF_MANAGED_APPEARED:
- final boolean alreadyPresent = isDevicePresent(associationId);
final boolean added = presentDevicesForSource.add(associationId);
+
if (!added) {
Slog.w(TAG, "Association with id "
+ associationId + " is ALREADY reported as "
+ "present by this source, event=" + event);
- return;
- }
- // For backward compatibility, do not send the onDeviceAppeared() callback
- // if it already reported BLE device status.
- if (event == DEVICE_EVENT_BT_CONNECTED && alreadyPresent) {
- Slog.i(TAG, "Ignore sending onDeviceAppeared callback, "
- + "device id (" + associationId + ") already present.");
- } else {
- mCallback.onDeviceAppeared(associationId);
}
+ mCallback.onDeviceAppeared(associationId);
+
break;
case DEVICE_EVENT_BLE_DISAPPEARED:
case DEVICE_EVENT_BT_DISCONNECTED:
case DEVICE_EVENT_SELF_MANAGED_DISAPPEARED:
final boolean removed = presentDevicesForSource.remove(associationId);
+
if (!removed) {
- Log.w(TAG, "Association with id " + associationId + " was NOT reported "
+ Slog.w(TAG, "Association with id " + associationId + " was NOT reported "
+ "as present by this source, event= " + event);
return;
}
- final boolean stillPresent = isDevicePresent(associationId);
- // For backward compatibility, do not send the onDeviceDisappeared()
- // callback when ble scan still presenting.
- if (stillPresent) {
- Slog.i(TAG, "Ignore sending onDeviceDisappeared callback, "
- + "device id (" + associationId + ") is still present.");
- } else {
- mCallback.onDeviceDisappeared(associationId);
- }
+
+ mCallback.onDeviceDisappeared(associationId);
break;
default:
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 402fbb812812..b61e62310e1a 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -106,10 +106,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
private static final String TAG = "VirtualDeviceImpl";
private static final int DEFAULT_VIRTUAL_DISPLAY_FLAGS =
- DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
- | DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT
- | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
- | DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL
+ DisplayManager.VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED
| DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH
| DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS;
@@ -286,6 +283,10 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
if (mParams.getLockState() == VirtualDeviceParams.LOCK_STATE_ALWAYS_UNLOCKED) {
flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED;
}
+ if (mParams.getDevicePolicy(VirtualDeviceParams.POLICY_TYPE_RECENTS)
+ == VirtualDeviceParams.DEVICE_POLICY_CUSTOM) {
+ flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL;
+ }
return flags;
}
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 846283c38327..fc51e2ec0954 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -1369,6 +1369,13 @@ public abstract class PackageManagerInternal {
public abstract void setPackageStoppedState(@NonNull String packageName, boolean stopped,
@UserIdInt int userId);
+ /**
+ * Tells PackageManager when a component (except BroadcastReceivers) of the package is used
+ * and the package should get out of stopped state and be enabled.
+ */
+ public abstract void notifyComponentUsed(@NonNull String packageName,
+ @UserIdInt int userId, @NonNull String recentCallingPackage);
+
/** @deprecated For legacy shell command only. */
@Deprecated
public abstract void legacyDumpProfiles(@NonNull String packageName,
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index 41cca4968f2c..03022b06dfe1 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -1,7 +1,13 @@
{
"presubmit": [
{
- "name": "CtsLocationFineTestCases"
+ "name": "CtsLocationFineTestCases",
+ "options": [
+ {
+ // TODO: Wait for test to deflake - b/293934372
+ "exclude-filter":"android.location.cts.fine.ScanningSettingsTest"
+ }
+ ]
},
{
"name": "CtsLocationCoarseTestCases"
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 73e827249569..36ef9b7ecc03 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -5069,7 +5069,7 @@ public final class ActiveServices {
boolean whileRestarting, boolean permissionsReviewRequired, boolean packageFrozen,
boolean enqueueOomAdj)
throws TransactionTooLargeException {
- if (r.app != null && r.app.getThread() != null) {
+ if (r.app != null && r.app.isThreadReady()) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
@@ -5116,10 +5116,9 @@ public final class ActiveServices {
r.packageName, r.userId, UsageEvents.Event.APP_COMPONENT_USED);
}
- // Service is now being launched, its package can't be stopped.
try {
- mAm.mPackageManagerInt.setPackageStoppedState(
- r.packageName, false, r.userId);
+ mAm.mPackageManagerInt.notifyComponentUsed(
+ r.packageName, r.userId, r.mRecentCallingPackage);
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ r.packageName + ": " + e);
@@ -5141,7 +5140,7 @@ public final class ActiveServices {
final IApplicationThread thread = app.getThread();
final int pid = app.getPid();
final UidRecord uidRecord = app.getUidRecord();
- if (thread != null) {
+ if (app.isThreadReady()) {
try {
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
@@ -5173,7 +5172,7 @@ public final class ActiveServices {
final int pid = app.getPid();
final UidRecord uidRecord = app.getUidRecord();
r.isolationHostProc = app;
- if (thread != null) {
+ if (app.isThreadReady()) {
try {
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
@@ -5573,7 +5572,7 @@ public final class ActiveServices {
boolean oomAdjusted = false;
// Tell the service that it has been unbound.
- if (r.app != null && r.app.getThread() != null) {
+ if (r.app != null && r.app.isThreadReady()) {
for (int i = r.bindings.size() - 1; i >= 0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing down binding " + ibr
@@ -5715,7 +5714,7 @@ public final class ActiveServices {
mAm.mBatteryStatsService.noteServiceStopLaunch(r.appInfo.uid, r.name.getPackageName(),
r.name.getClassName());
stopServiceAndUpdateAllowlistManagerLocked(r);
- if (r.app.getThread() != null) {
+ if (r.app.isThreadReady()) {
// Bump the process to the top of LRU list
mAm.updateLruProcessLocked(r.app, false, null);
updateServiceForegroundLocked(r.app.mServices, false);
@@ -5879,7 +5878,7 @@ public final class ActiveServices {
if (!c.serviceDead) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Disconnecting binding " + b.intent
+ ": shouldUnbind=" + b.intent.hasBound);
- if (s.app != null && s.app.getThread() != null && b.intent.apps.size() == 0
+ if (s.app != null && s.app.isThreadReady() && b.intent.apps.size() == 0
&& b.intent.hasBound) {
try {
bumpServiceExecutingLocked(s, false, "unbind", OOM_ADJ_REASON_UNBIND_SERVICE);
@@ -6381,7 +6380,7 @@ public final class ActiveServices {
sr.pendingStarts.add(new ServiceRecord.StartItem(sr, true,
sr.getLastStartId(), baseIntent, null, 0, null, null,
ActivityManager.PROCESS_STATE_UNKNOWN));
- if (sr.app != null && sr.app.getThread() != null) {
+ if (sr.app != null && sr.app.isThreadReady()) {
// We always run in the foreground, since this is called as
// part of the "remove task" UI operation.
try {
@@ -6434,6 +6433,7 @@ public final class ActiveServices {
}
updateServiceConnectionActivitiesLocked(psr);
psr.removeAllConnections();
+ psr.removeAllSdkSandboxConnections();
psr.mAllowlistManager = false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 2058b4cff740..3fd7d7e6db46 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -22,6 +22,7 @@ import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_NONE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_BACKGROUND_RESTRICTED_ONLY;
import static com.android.server.am.BroadcastConstants.DEFER_BOOT_COMPLETED_BROADCAST_TARGET_T_ONLY;
+import static com.android.server.am.BroadcastConstants.getDeviceConfigBoolean;
import android.annotation.NonNull;
import android.app.ActivityThread;
@@ -154,6 +155,11 @@ final class ActivityManagerConstants extends ContentObserver {
static final String KEY_TIERED_CACHED_ADJ_DECAY_TIME = "tiered_cached_adj_decay_time";
static final String KEY_USE_MODERN_TRIM = "use_modern_trim";
+ /**
+ * Whether or not to enable the new oom adjuster implementation.
+ */
+ static final String KEY_ENABLE_NEW_OOMADJ = "enable_new_oom_adj";
+
private static final int DEFAULT_MAX_CACHED_PROCESSES = 1024;
private static final boolean DEFAULT_PRIORITIZE_ALARM_BROADCASTS = true;
private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000;
@@ -217,6 +223,11 @@ final class ActivityManagerConstants extends ContentObserver {
private static final boolean DEFAULT_USE_MODERN_TRIM = true;
/**
+ * The default value to {@link #KEY_ENABLE_NEW_OOMADJ}.
+ */
+ private static final boolean DEFAULT_ENABLE_NEW_OOM_ADJ = false;
+
+ /**
* Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED}
*/
private static final int
@@ -1052,6 +1063,9 @@ final class ActivityManagerConstants extends ContentObserver {
/** @see #KEY_USE_MODERN_TRIM */
public boolean USE_MODERN_TRIM = DEFAULT_USE_MODERN_TRIM;
+ /** @see #KEY_ENABLE_NEW_OOMADJ */
+ public boolean ENABLE_NEW_OOMADJ = DEFAULT_ENABLE_NEW_OOM_ADJ;
+
/**
* Indicates whether PSS profiling in AppProfiler is disabled or not.
*/
@@ -1321,6 +1335,7 @@ final class ActivityManagerConstants extends ContentObserver {
CUR_TRIM_EMPTY_PROCESSES = rawMaxEmptyProcesses / 2;
CUR_TRIM_CACHED_PROCESSES = (Integer.min(CUR_MAX_CACHED_PROCESSES, MAX_CACHED_PROCESSES)
- rawMaxEmptyProcesses) / 3;
+ loadNativeBootDeviceConfigConstants();
mDefaultDisableAppProfilerPssProfiling = context.getResources().getBoolean(
R.bool.config_am_disablePssProfiling);
APP_PROFILER_PSS_PROFILING_DISABLED = mDefaultDisableAppProfilerPssProfiling;
@@ -1363,6 +1378,11 @@ final class ActivityManagerConstants extends ContentObserver {
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_COMPONENT_ALIAS));
}
+ private void loadNativeBootDeviceConfigConstants() {
+ ENABLE_NEW_OOMADJ = getDeviceConfigBoolean(KEY_ENABLE_NEW_OOMADJ,
+ DEFAULT_ENABLE_NEW_OOM_ADJ);
+ }
+
public void setOverrideMaxCachedProcesses(int value) {
mOverrideMaxCachedProcesses = value;
updateMaxCachedProcesses();
@@ -2013,6 +2033,13 @@ final class ActivityManagerConstants extends ContentObserver {
DEFAULT_USE_MODERN_TRIM);
}
+ private void updateEnableNewOomAdj() {
+ ENABLE_NEW_OOMADJ = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+ KEY_ENABLE_NEW_OOMADJ,
+ DEFAULT_ENABLE_NEW_OOM_ADJ);
+ }
+
private void updateFGSPermissionEnforcementFlagsIfNecessary(@NonNull String name) {
ForegroundServiceTypePolicy.getDefaultPolicy()
.updatePermissionEnforcementFlagIfNecessary(name);
@@ -2209,6 +2236,9 @@ final class ActivityManagerConstants extends ContentObserver {
pw.print(" "); pw.print(KEY_TIERED_CACHED_ADJ_DECAY_TIME);
pw.print("="); pw.println(TIERED_CACHED_ADJ_DECAY_TIME);
+ pw.print(" "); pw.print(KEY_ENABLE_NEW_OOMADJ);
+ pw.print("="); pw.println(ENABLE_NEW_OOMADJ);
+
pw.print(" "); pw.print(KEY_DISABLE_APP_PROFILER_PSS_PROFILING);
pw.print("="); pw.println(APP_PROFILER_PSS_PROFILING_DISABLED);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a0fae26fcac1..a53c2fb44873 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2029,6 +2029,7 @@ public class ActivityManagerService extends IActivityManager.Stub
app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
app.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_SYSTEM);
addPidLocked(app);
+ mOomAdjuster.onProcessBeginLocked(app);
updateLruProcessLocked(app, false, null);
updateOomAdjLocked(OOM_ADJ_REASON_SYSTEM_INIT);
}
@@ -2422,7 +2423,9 @@ public class ActivityManagerService extends IActivityManager.Stub
mProcessList.init(this, activeUids, mPlatformCompat);
mAppProfiler = new AppProfiler(this, BackgroundThread.getHandler().getLooper(), null);
mPhantomProcessList = new PhantomProcessList(this);
- mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids, handlerThread);
+ mOomAdjuster = mConstants.ENABLE_NEW_OOMADJ
+ ? new OomAdjusterModernImpl(this, mProcessList, activeUids, handlerThread)
+ : new OomAdjuster(this, mProcessList, activeUids, handlerThread);
mIntentFirewall = null;
mProcessStats = new ProcessStatsService(this, mContext.getCacheDir());
@@ -2483,7 +2486,9 @@ public class ActivityManagerService extends IActivityManager.Stub
mAppProfiler = new AppProfiler(this, BackgroundThread.getHandler().getLooper(),
new LowMemDetector(this));
mPhantomProcessList = new PhantomProcessList(this);
- mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids);
+ mOomAdjuster = mConstants.ENABLE_NEW_OOMADJ
+ ? new OomAdjusterModernImpl(this, mProcessList, activeUids)
+ : new OomAdjuster(this, mProcessList, activeUids);
// Broadcast policy parameters
final BroadcastConstants foreConstants = new BroadcastConstants(
@@ -3090,6 +3095,22 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ /**
+ * Enforces that the uid of the caller matches the uid of the package.
+ *
+ * @param packageName the name of the package to match uid against.
+ * @param callingUid the uid of the caller.
+ * @throws SecurityException if the calling uid doesn't match uid of the package.
+ */
+ private void enforceCallingPackage(String packageName, int callingUid) {
+ final int userId = UserHandle.getUserId(callingUid);
+ final int packageUid = getPackageManagerInternal().getPackageUid(packageName,
+ /*flags=*/ 0, userId);
+ if (packageUid != callingUid) {
+ throw new SecurityException(packageName + " does not belong to uid " + callingUid);
+ }
+ }
+
@Override
public void setPackageScreenCompatMode(String packageName, int mode) {
mActivityTaskManager.setPackageScreenCompatMode(packageName, mode);
@@ -4595,6 +4616,7 @@ public class ActivityManagerService extends IActivityManager.Stub
EventLogTags.writeAmProcBound(app.userId, pid, app.processName);
synchronized (mProcLock) {
+ mOomAdjuster.onProcessBeginLocked(app);
mOomAdjuster.setAttachingProcessStatesLSP(app);
clearProcessForegroundLocked(app);
app.setDebugging(false);
@@ -6980,6 +7002,7 @@ public class ActivityManagerService extends IActivityManager.Stub
sdkSandboxClientAppPackage,
new HostingRecord(HostingRecord.HOSTING_TYPE_ADDED_APPLICATION,
customProcess != null ? customProcess : info.processName));
+ mOomAdjuster.onProcessBeginLocked(app);
updateLruProcessLocked(app, false, null);
updateOomAdjLocked(app, OOM_ADJ_REASON_PROCESS_BEGIN);
}
@@ -13697,13 +13720,16 @@ public class ActivityManagerService extends IActivityManager.Stub
// A backup agent has just come up
@Override
public void backupAgentCreated(String agentPackageName, IBinder agent, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ enforceCallingPackage(agentPackageName, callingUid);
+
// Resolve the target user id and enforce permissions.
- userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+ userId = mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid,
userId, /* allowAll */ false, ALLOW_FULL_ONLY, "backupAgentCreated", null);
if (DEBUG_BACKUP) {
Slog.v(TAG_BACKUP, "backupAgentCreated: " + agentPackageName + " = " + agent
+ " callingUserId = " + UserHandle.getCallingUserId() + " userId = " + userId
- + " callingUid = " + Binder.getCallingUid() + " uid = " + Process.myUid());
+ + " callingUid = " + callingUid + " uid = " + Process.myUid());
}
synchronized(this) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index b7fc4844413f..04ebb2b14af6 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -84,6 +84,7 @@ import android.power.PowerStatsInternal;
import android.provider.Settings;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ModemActivityInfo;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.util.IndentingPrintWriter;
@@ -1587,7 +1588,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub
@Override
@EnforcePermission(UPDATE_DEVICE_STATS)
public void notePhoneDataConnectionState(final int dataType, final boolean hasData,
- final int serviceType, final int nrFrequency) {
+ final int serviceType, @NetworkRegistrationInfo.NRState final int nrState,
+ final int nrFrequency) {
super.notePhoneDataConnectionState_enforcePermission();
synchronized (mLock) {
@@ -1596,7 +1598,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
mHandler.post(() -> {
synchronized (mStats) {
mStats.notePhoneDataConnectionStateLocked(dataType, hasData, serviceType,
- nrFrequency, elapsedRealtime, uptime);
+ nrState, nrFrequency, elapsedRealtime, uptime);
}
});
}
diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java
index 8c1fd516028e..2fff79b3fb26 100644
--- a/services/core/java/com/android/server/am/BroadcastConstants.java
+++ b/services/core/java/com/android/server/am/BroadcastConstants.java
@@ -373,7 +373,7 @@ public class BroadcastConstants {
* Return the {@link SystemProperty} name for the given key in our
* {@link DeviceConfig} namespace.
*/
- private @NonNull String propertyFor(@NonNull String key) {
+ private static @NonNull String propertyFor(@NonNull String key) {
return "persist.device_config." + NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT + "." + key;
}
@@ -382,11 +382,11 @@ public class BroadcastConstants {
* {@link DeviceConfig} namespace, but with a different prefix that can be
* used to locally override the {@link DeviceConfig} value.
*/
- private @NonNull String propertyOverrideFor(@NonNull String key) {
+ private static @NonNull String propertyOverrideFor(@NonNull String key) {
return "persist.sys." + NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT + "." + key;
}
- private boolean getDeviceConfigBoolean(@NonNull String key, boolean def) {
+ static boolean getDeviceConfigBoolean(@NonNull String key, boolean def) {
return SystemProperties.getBoolean(propertyOverrideFor(key),
SystemProperties.getBoolean(propertyFor(key), def));
}
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index e26ee9c9d747..65fd54afbbfb 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -505,12 +505,11 @@ public class ContentProviderHelper {
cpr.appInfo.packageName, userId, Event.APP_COMPONENT_USED);
}
- // Content provider is now in use, its package can't be stopped.
try {
checkTime(startTime,
"getContentProviderImpl: before set stopped state");
- mService.mPackageManagerInt.setPackageStoppedState(
- cpr.appInfo.packageName, false, userId);
+ mService.mPackageManagerInt.notifyComponentUsed(
+ cpr.appInfo.packageName, userId, callingPackage);
checkTime(startTime, "getContentProviderImpl: after set stopped state");
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
diff --git a/services/core/java/com/android/server/am/DataConnectionStats.java b/services/core/java/com/android/server/am/DataConnectionStats.java
index f0910dcb0da2..e25dd0599b6c 100644
--- a/services/core/java/com/android/server/am/DataConnectionStats.java
+++ b/services/core/java/com/android/server/am/DataConnectionStats.java
@@ -98,18 +98,13 @@ public class DataConnectionStats extends BroadcastReceiver {
mServiceState.getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN);
int networkType = regInfo == null ? TelephonyManager.NETWORK_TYPE_UNKNOWN
: regInfo.getAccessNetworkTechnology();
- // If the device is in NSA NR connection the networkType will report as LTE.
- // For cell dwell rate metrics, this should report NR instead.
- if (mNrState == NetworkRegistrationInfo.NR_STATE_CONNECTED) {
- networkType = TelephonyManager.NETWORK_TYPE_NR;
- }
if (DEBUG) {
Log.d(TAG, String.format("Noting data connection for network type %s: %svisible",
networkType, visible ? "" : "not "));
}
try {
mBatteryStats.notePhoneDataConnectionState(networkType, visible,
- mServiceState.getState(), mServiceState.getNrFrequencyRange());
+ mServiceState.getState(), mNrState, mServiceState.getNrFrequencyRange());
} catch (RemoteException e) {
Log.w(TAG, "Error noting data connection state", e);
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 459c6ff3504a..d3176ee46464 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -41,6 +41,7 @@ import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ACTIVITY;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ALLOWLIST;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_BACKUP;
@@ -124,6 +125,7 @@ import static com.android.server.am.ProcessList.UNKNOWN_ADJ;
import static com.android.server.am.ProcessList.VISIBLE_APP_ADJ;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal.OomAdjReason;
@@ -369,20 +371,21 @@ public class OomAdjuster {
*/
private final Handler mProcessGroupHandler;
- private final int[] mTmpSchedGroup = new int[1];
+ protected final int[] mTmpSchedGroup = new int[1];
- private final ActivityManagerService mService;
- private final ProcessList mProcessList;
- private final ActivityManagerGlobalLock mProcLock;
+ final ActivityManagerService mService;
+ final ProcessList mProcessList;
+ final ActivityManagerGlobalLock mProcLock;
private final int mNumSlots;
- private final ArrayList<ProcessRecord> mTmpProcessList = new ArrayList<ProcessRecord>();
- private final ArrayList<UidRecord> mTmpBecameIdle = new ArrayList<UidRecord>();
- private final ActiveUids mTmpUidRecords;
- private final ArrayDeque<ProcessRecord> mTmpQueue;
- private final ArraySet<ProcessRecord> mTmpProcessSet = new ArraySet<>();
- private final ArraySet<ProcessRecord> mPendingProcessSet = new ArraySet<>();
- private final ArraySet<ProcessRecord> mProcessesInCycle = new ArraySet<>();
+ protected final ArrayList<ProcessRecord> mTmpProcessList = new ArrayList<ProcessRecord>();
+ protected final ArrayList<ProcessRecord> mTmpProcessList2 = new ArrayList<ProcessRecord>();
+ protected final ArrayList<UidRecord> mTmpBecameIdle = new ArrayList<UidRecord>();
+ protected final ActiveUids mTmpUidRecords;
+ protected final ArrayDeque<ProcessRecord> mTmpQueue;
+ protected final ArraySet<ProcessRecord> mTmpProcessSet = new ArraySet<>();
+ protected final ArraySet<ProcessRecord> mPendingProcessSet = new ArraySet<>();
+ protected final ArraySet<ProcessRecord> mProcessesInCycle = new ArraySet<>();
/**
* Flag to mark if there is an ongoing oomAdjUpdate: potentially the oomAdjUpdate
@@ -412,7 +415,7 @@ public class OomAdjuster {
this(service, processList, activeUids, createAdjusterThread());
}
- private static ServiceThread createAdjusterThread() {
+ static ServiceThread createAdjusterThread() {
// The process group is usually critical to the response time of foreground app, so the
// setter should apply it as soon as possible.
final ServiceThread adjusterThread =
@@ -532,7 +535,7 @@ public class OomAdjuster {
mPendingProcessSet.remove(app);
mProcessesInCycle.clear();
- computeOomAdjLSP(app, cachedAdj, topApp, false, now, false, true);
+ computeOomAdjLSP(app, cachedAdj, topApp, false, now, false, true, oomAdjReason, true);
if (!mProcessesInCycle.isEmpty()) {
// We can't use the score here if there is a cycle, abort.
for (int i = mProcessesInCycle.size() - 1; i >= 0; i--) {
@@ -550,7 +553,7 @@ public class OomAdjuster {
&& (uidRec.getSetProcState() != uidRec.getCurProcState()
|| uidRec.getSetCapability() != uidRec.getCurCapability()
|| uidRec.isSetAllowListed() != uidRec.isCurAllowListed())) {
- ActiveUids uids = mTmpUidRecords;
+ final ActiveUids uids = mTmpUidRecords;
uids.clear();
uids.put(uidRec.getUid(), uidRec);
updateUidsLSP(uids, SystemClock.elapsedRealtime());
@@ -633,19 +636,20 @@ public class OomAdjuster {
}
@GuardedBy({"mService", "mProcLock"})
- private boolean performUpdateOomAdjLSP(ProcessRecord app, @OomAdjReason int oomAdjReason) {
+ protected boolean performUpdateOomAdjLSP(ProcessRecord app, @OomAdjReason int oomAdjReason) {
final ProcessRecord topApp = mService.getTopApp();
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason));
mService.mOomAdjProfiler.oomAdjStarted();
mAdjSeq++;
- // Firstly, try to see if the importance of itself gets changed
final ProcessStateRecord state = app.mState;
final boolean wasCached = state.isCached();
final int oldAdj = state.getCurRawAdj();
final int cachedAdj = oldAdj >= CACHED_APP_MIN_ADJ
? oldAdj : UNKNOWN_ADJ;
+
+ // Firstly, try to see if the importance of itself gets changed
final boolean wasBackground = ActivityManager.isProcStateBackground(
state.getSetProcState());
final int oldCap = state.getSetCapability();
@@ -693,8 +697,6 @@ public class OomAdjuster {
mPendingProcessSet.clear();
if (!containsCycle) {
- // Reset the flag
- state.setReachable(false);
// Remove this app from the return list because we've done the computation on it.
processes.remove(app);
}
@@ -718,8 +720,13 @@ public class OomAdjuster {
return true;
}
+ /**
+ * Collect the reachable processes from the given {@code apps}, the result will be
+ * returned in the given {@code processes}, which will include the processes from
+ * the given {@code apps}.
+ */
@GuardedBy("mService")
- private boolean collectReachableProcessesLocked(ArraySet<ProcessRecord> apps,
+ protected boolean collectReachableProcessesLocked(ArraySet<ProcessRecord> apps,
ArrayList<ProcessRecord> processes, ActiveUids uids) {
final ArrayDeque<ProcessRecord> queue = mTmpQueue;
queue.clear();
@@ -824,11 +831,15 @@ public class OomAdjuster {
if (size > 0) {
// Reverse the process list, since the updateOomAdjInnerLSP scans from the end of it.
for (int l = 0, r = size - 1; l < r; l++, r--) {
- ProcessRecord t = processes.get(l);
- processes.set(l, processes.get(r));
+ final ProcessRecord t = processes.get(l);
+ final ProcessRecord u = processes.get(r);
+ t.mState.setReachable(false);
+ u.mState.setReachable(false);
+ processes.set(l, u);
processes.set(r, t);
}
}
+
return containsCycle;
}
@@ -928,24 +939,18 @@ public class OomAdjuster {
* Update OomAdj for all processes within the given list (could be partial), or the whole LRU
* list if the given list is null; when it's partial update, each process's client proc won't
* get evaluated recursively here.
+ *
+ * <p>Note: If the given {@code processes} is not null, the expectation to it is, the caller
+ * must have called {@link collectReachableProcessesLocked} on it.
*/
@GuardedBy({"mService", "mProcLock"})
- private void updateOomAdjInnerLSP(@OomAdjReason int oomAdjReason, final ProcessRecord topApp,
+ protected void updateOomAdjInnerLSP(@OomAdjReason int oomAdjReason, final ProcessRecord topApp,
ArrayList<ProcessRecord> processes, ActiveUids uids, boolean potentialCycles,
boolean startProfiling) {
- if (startProfiling) {
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason));
- mService.mOomAdjProfiler.oomAdjStarted();
- }
- final long now = SystemClock.uptimeMillis();
- final long nowElapsed = SystemClock.elapsedRealtime();
- final long oldTime = now - mConstants.mMaxEmptyTimeMillis;
final boolean fullUpdate = processes == null;
+ final ArrayList<ProcessRecord> activeProcesses = fullUpdate
+ ? mProcessList.getLruProcessesLOSP() : processes;
ActiveUids activeUids = uids;
- ArrayList<ProcessRecord> activeProcesses = fullUpdate ? mProcessList.getLruProcessesLOSP()
- : processes;
- final int numProc = activeProcesses.size();
-
if (activeUids == null) {
final int numUids = mActiveUids.size();
activeUids = mTmpUidRecords;
@@ -956,14 +961,14 @@ public class OomAdjuster {
}
}
- // Reset state in all uid records.
- for (int i = activeUids.size() - 1; i >= 0; i--) {
- final UidRecord uidRec = activeUids.valueAt(i);
- if (DEBUG_UID_OBSERVERS) {
- Slog.i(TAG_UID_OBSERVERS, "Starting update of " + uidRec);
- }
- uidRec.reset();
+ if (startProfiling) {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason));
+ mService.mOomAdjProfiler.oomAdjStarted();
}
+ final long now = SystemClock.uptimeMillis();
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ final long oldTime = now - mConstants.mMaxEmptyTimeMillis;
+ final int numProc = activeProcesses.size();
mAdjSeq++;
if (fullUpdate) {
@@ -971,6 +976,9 @@ public class OomAdjuster {
mNewNumAServiceProcs = 0;
}
+ // Reset state in all uid records.
+ resetUidRecordsLsp(activeUids);
+
boolean retryCycles = false;
boolean computeClients = fullUpdate || potentialCycles;
@@ -996,8 +1004,9 @@ public class OomAdjuster {
if (!app.isKilledByAm() && app.getThread() != null) {
state.setProcStateChanged(false);
app.mOptRecord.setLastOomAdjChangeReason(oomAdjReason);
+ // It won't enter cycle if not computing clients.
computeOomAdjLSP(app, UNKNOWN_ADJ, topApp, fullUpdate, now, false,
- computeClients); // It won't enter cycle if not computing clients.
+ computeClients, oomAdjReason, true);
// if any app encountered a cycle, we need to perform an additional loop later
retryCycles |= state.containsCycle();
// Keep the completedAdjSeq to up to date.
@@ -1034,7 +1043,7 @@ public class OomAdjuster {
final ProcessStateRecord state = app.mState;
if (!app.isKilledByAm() && app.getThread() != null && state.containsCycle()) {
if (computeOomAdjLSP(app, UNKNOWN_ADJ, topApp, true, now,
- true, true)) {
+ true, true, oomAdjReason, true)) {
retryCycles = true;
}
}
@@ -1045,10 +1054,33 @@ public class OomAdjuster {
assignCachedAdjIfNecessary(mProcessList.getLruProcessesLOSP());
+ postUpdateOomAdjInnerLSP(oomAdjReason, activeUids, now, nowElapsed, oldTime);
+
+ if (startProfiling) {
+ mService.mOomAdjProfiler.oomAdjEnded();
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ private void resetUidRecordsLsp(@NonNull ActiveUids activeUids) {
+ // Reset state in all uid records.
+ for (int i = activeUids.size() - 1; i >= 0; i--) {
+ final UidRecord uidRec = activeUids.valueAt(i);
+ if (DEBUG_UID_OBSERVERS) {
+ Slog.i(TAG_UID_OBSERVERS, "Starting update of " + uidRec);
+ }
+ uidRec.reset();
+ }
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ protected void postUpdateOomAdjInnerLSP(@OomAdjReason int oomAdjReason, ActiveUids activeUids,
+ long now, long nowElapsed, long oldTime) {
mNumNonCachedProcs = 0;
mNumCachedHiddenProcs = 0;
- boolean allChanged = updateAndTrimProcessLSP(now, nowElapsed, oldTime, activeUids,
+ final boolean allChanged = updateAndTrimProcessLSP(now, nowElapsed, oldTime, activeUids,
oomAdjReason);
mNumServiceProcs = mNewNumServiceProcs;
@@ -1085,14 +1117,10 @@ public class OomAdjuster {
Slog.d(TAG_OOM_ADJ, "Did OOM ADJ in " + duration + "ms");
}
}
- if (startProfiling) {
- mService.mOomAdjProfiler.oomAdjEnded();
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- }
}
@GuardedBy({"mService", "mProcLock"})
- private void assignCachedAdjIfNecessary(ArrayList<ProcessRecord> lruList) {
+ protected void assignCachedAdjIfNecessary(ArrayList<ProcessRecord> lruList) {
final int numLru = lruList.size();
if (mConstants.USE_TIERED_CACHED_ADJ) {
final long now = SystemClock.uptimeMillis();
@@ -1413,7 +1441,7 @@ public class OomAdjuster {
}
@GuardedBy({"mService", "mProcLock"})
- private void updateAppUidRecIfNecessaryLSP(final ProcessRecord app) {
+ protected void updateAppUidRecIfNecessaryLSP(final ProcessRecord app) {
if (!app.isKilledByAm() && app.getThread() != null) {
if (app.isolated && app.mServices.numberOfRunningServices() <= 0
&& app.getIsolatedEntryPoint() == null) {
@@ -1442,7 +1470,7 @@ public class OomAdjuster {
}
@GuardedBy({"mService", "mProcLock"})
- private void updateUidsLSP(ActiveUids activeUids, final long nowElapsed) {
+ protected void updateUidsLSP(ActiveUids activeUids, final long nowElapsed) {
// This compares previously set procstate to the current procstate in regards to whether
// or not the app's network access will be blocked. So, this needs to be called before
// we update the UidRecord's procstate by calling {@link UidRecord#setSetProcState}.
@@ -1580,7 +1608,7 @@ public class OomAdjuster {
return true;
}
- private final ComputeOomAdjWindowCallback mTmpComputeOomAdjWindowCallback =
+ protected final ComputeOomAdjWindowCallback mTmpComputeOomAdjWindowCallback =
new ComputeOomAdjWindowCallback();
/** These methods are called inline during computeOomAdjLSP(), on the same thread */
@@ -1719,24 +1747,30 @@ public class OomAdjuster {
}
@GuardedBy({"mService", "mProcLock"})
- private boolean computeOomAdjLSP(ProcessRecord app, int cachedAdj,
+ protected boolean computeOomAdjLSP(ProcessRecord app, int cachedAdj,
ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
- boolean computeClients) {
+ boolean computeClients, int oomAdjReason, boolean couldRecurse) {
final ProcessStateRecord state = app.mState;
- if (mAdjSeq == state.getAdjSeq()) {
- if (state.getAdjSeq() == state.getCompletedAdjSeq()) {
- // This adjustment has already been computed successfully.
- return false;
- } else {
- // The process is being computed, so there is a cycle. We cannot
- // rely on this process's state.
- state.setContainsCycle(true);
- mProcessesInCycle.add(app);
+ if (couldRecurse) {
+ if (mAdjSeq == state.getAdjSeq()) {
+ if (state.getAdjSeq() == state.getCompletedAdjSeq()) {
+ // This adjustment has already been computed successfully.
+ return false;
+ } else {
+ // The process is being computed, so there is a cycle. We cannot
+ // rely on this process's state.
+ state.setContainsCycle(true);
+ mProcessesInCycle.add(app);
- return false;
+ return false;
+ }
}
}
+ int prevAppAdj = getInitialAdj(app);
+ int prevProcState = getInitialProcState(app);
+ int prevCapability = getInitialCapability(app);
+
if (app.getThread() == null) {
state.setAdjSeq(mAdjSeq);
state.setCurrentSchedulingGroup(SCHED_GROUP_BACKGROUND);
@@ -1745,6 +1779,8 @@ public class OomAdjuster {
state.setCurRawAdj(CACHED_APP_MAX_ADJ);
state.setCompletedAdjSeq(state.getAdjSeq());
state.setCurCapability(PROCESS_CAPABILITY_NONE);
+ onProcessStateChanged(app, prevProcState);
+ onProcessOomAdjChanged(app, prevAppAdj);
return false;
}
@@ -1753,7 +1789,7 @@ public class OomAdjuster {
state.setAdjTarget(null);
state.setEmpty(false);
state.setCached(false);
- if (!cycleReEval) {
+ if (!couldRecurse || !cycleReEval) {
// Don't reset this flag when doing cycles re-evaluation.
state.setNoKillOnBgRestrictedAndIdle(false);
// If this UID is currently allowlisted, it should not be frozen.
@@ -1764,9 +1800,6 @@ public class OomAdjuster {
final int appUid = app.info.uid;
final int logUid = mService.mCurOomAdjUid;
- int prevAppAdj = state.getCurAdj();
- int prevProcState = state.getCurProcState();
- int prevCapability = state.getCurCapability();
final ProcessServiceRecord psr = app.mServices;
if (state.getMaxAdj() <= FOREGROUND_APP_ADJ) {
@@ -1812,6 +1845,8 @@ public class OomAdjuster {
state.setCurRawProcState(state.getCurProcState());
state.setCurAdj(state.getMaxAdj());
state.setCompletedAdjSeq(state.getAdjSeq());
+ onProcessStateChanged(app, prevProcState);
+ onProcessOomAdjChanged(app, prevAppAdj);
// if curAdj is less than prevAppAdj, then this process was promoted
return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState;
}
@@ -1825,7 +1860,7 @@ public class OomAdjuster {
int adj;
int schedGroup;
int procState;
- int capability = cycleReEval ? app.mState.getCurCapability() : 0;
+ int capability = cycleReEval ? getInitialCapability(app) : 0;
boolean foregroundActivities = false;
boolean hasVisibleActivities = false;
@@ -1904,7 +1939,7 @@ public class OomAdjuster {
// value that the caller wants us to.
adj = cachedAdj;
procState = PROCESS_STATE_CACHED_EMPTY;
- if (!state.containsCycle()) {
+ if (!couldRecurse || !state.containsCycle()) {
state.setCached(true);
state.setEmpty(true);
state.setAdjType("cch-empty");
@@ -2169,8 +2204,10 @@ public class OomAdjuster {
}
}
- boolean boundByNonBgRestricted = state.isCurBoundByNonBgRestrictedApp();
- boolean scheduleLikeTopApp = false;
+ state.setCurBoundByNonBgRestrictedApp(getInitialIsCurBoundByNonBgRestrictedApp(app));
+
+ state.setScheduleLikeTopApp(false);
+
for (int is = psr.numberOfRunningServices() - 1;
is >= 0 && (adj > FOREGROUND_APP_ADJ
|| schedGroup == SCHED_GROUP_BACKGROUND
@@ -2243,6 +2280,18 @@ public class OomAdjuster {
}
}
+ if (!couldRecurse) {
+ // We're entering recursive functions below, if we're told it's not a recursive
+ // loop, abort here.
+ continue;
+ }
+
+
+ state.setCurRawAdj(adj);
+ state.setCurRawProcState(procState);
+ state.setCurrentSchedulingGroup(schedGroup);
+ state.setCurCapability(capability);
+
ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections = s.getConnections();
for (int conni = serviceConnections.size() - 1;
conni >= 0 && (adj > FOREGROUND_APP_ADJ
@@ -2263,335 +2312,13 @@ public class OomAdjuster {
continue;
}
- boolean trackedProcState = false;
-
- ProcessRecord client = cr.binding.client;
- if (app.isSdkSandbox && cr.binding.attributedClient != null) {
- // For SDK sandboxes, use the attributed client (eg the app that
- // requested the sandbox)
- client = cr.binding.attributedClient;
- }
- final ProcessStateRecord cstate = client.mState;
- if (computeClients) {
- computeOomAdjLSP(client, cachedAdj, topApp, doingAll, now,
- cycleReEval, true);
- } else {
- cstate.setCurRawAdj(cstate.getCurAdj());
- cstate.setCurRawProcState(cstate.getCurProcState());
- }
-
- int clientAdj = cstate.getCurRawAdj();
- int clientProcState = cstate.getCurRawProcState();
-
- final boolean clientIsSystem = clientProcState < PROCESS_STATE_TOP;
-
- boundByNonBgRestricted |= cstate.isCurBoundByNonBgRestrictedApp()
- || clientProcState <= PROCESS_STATE_BOUND_TOP
- || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE
- && !cstate.isBackgroundRestricted());
-
- if (client.mOptRecord.shouldNotFreeze()) {
- // Propagate the shouldNotFreeze flag down the bindings.
- app.mOptRecord.setShouldNotFreeze(true);
- }
-
- // We always propagate PROCESS_CAPABILITY_BFSL over bindings here,
- // but, right before actually setting it to the process,
- // we check the final procstate, and remove it if the procsate is below BFGS.
- capability |= getBfslCapabilityFromClient(client);
-
- if (cr.notHasFlag(Context.BIND_WAIVE_PRIORITY)) {
- if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
- capability |= cstate.getCurCapability();
- }
-
- // If an app has network capability by default
- // (by having procstate <= BFGS), then the apps it binds to will get
- // elevated to a high enough procstate anyway to get network unless they
- // request otherwise, so don't propagate the network capability by default
- // in this case unless they explicitly request it.
- if ((cstate.getCurCapability()
- & PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0) {
- if (clientProcState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
- // This is used to grant network access to Expedited Jobs.
- if (cr.hasFlag(Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS)) {
- capability |= PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
- }
- } else {
- capability |= PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
- }
- }
- if ((cstate.getCurCapability()
- & PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK) != 0) {
- if (clientProcState <= PROCESS_STATE_IMPORTANT_FOREGROUND) {
- // This is used to grant network access to User Initiated Jobs.
- if (cr.hasFlag(Context.BIND_BYPASS_USER_NETWORK_RESTRICTIONS)) {
- capability |= PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
- }
- }
- }
-
- if (shouldSkipDueToCycle(app, cstate, procState, adj, cycleReEval)) {
- continue;
- }
-
- if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
- // If the other app is cached for any reason, for purposes here
- // we are going to consider it empty. The specific cached state
- // doesn't propagate except under certain conditions.
- clientProcState = PROCESS_STATE_CACHED_EMPTY;
- }
- String adjType = null;
- if (cr.hasFlag(Context.BIND_ALLOW_OOM_MANAGEMENT)) {
- // Similar to BIND_WAIVE_PRIORITY, keep it unfrozen.
- if (clientAdj < CACHED_APP_MIN_ADJ) {
- app.mOptRecord.setShouldNotFreeze(true);
- }
- // Not doing bind OOM management, so treat
- // this guy more like a started service.
- if (state.hasShownUi() && !state.getCachedIsHomeProcess()) {
- // If this process has shown some UI, let it immediately
- // go to the LRU list because it may be pretty heavy with
- // UI stuff. We'll tag it with a label just to help
- // debug and understand what is going on.
- if (adj > clientAdj) {
- adjType = "cch-bound-ui-services";
- }
- state.setCached(false);
- clientAdj = adj;
- clientProcState = procState;
- } else {
- if (now >= (s.lastActivity
- + mConstants.MAX_SERVICE_INACTIVITY)) {
- // This service has not seen activity within
- // recent memory, so allow it to drop to the
- // LRU list if there is no other reason to keep
- // it around. We'll also tag it with a label just
- // to help debug and undertand what is going on.
- if (adj > clientAdj) {
- adjType = "cch-bound-services";
- }
- clientAdj = adj;
- }
- }
- }
- if (adj > clientAdj) {
- // If this process has recently shown UI, and
- // the process that is binding to it is less
- // important than being visible, then we don't
- // care about the binding as much as we care
- // about letting this process get into the LRU
- // list to be killed and restarted if needed for
- // memory.
- if (state.hasShownUi() && !state.getCachedIsHomeProcess()
- && clientAdj > PERCEPTIBLE_APP_ADJ) {
- if (adj >= CACHED_APP_MIN_ADJ) {
- adjType = "cch-bound-ui-services";
- }
- } else {
- int newAdj;
- int lbAdj = VISIBLE_APP_ADJ; // lower bound of adj.
- if (cr.hasFlag(Context.BIND_ABOVE_CLIENT
- | Context.BIND_IMPORTANT)) {
- if (clientAdj >= PERSISTENT_SERVICE_ADJ) {
- newAdj = clientAdj;
- } else {
- // make this service persistent
- newAdj = PERSISTENT_SERVICE_ADJ;
- schedGroup = SCHED_GROUP_DEFAULT;
- procState = ActivityManager.PROCESS_STATE_PERSISTENT;
- cr.trackProcState(procState, mAdjSeq);
- trackedProcState = true;
- }
- } else if (cr.hasFlag(Context.BIND_NOT_PERCEPTIBLE)
- && clientAdj <= PERCEPTIBLE_APP_ADJ
- && adj >= (lbAdj = PERCEPTIBLE_LOW_APP_ADJ)) {
- newAdj = PERCEPTIBLE_LOW_APP_ADJ;
- } else if (cr.hasFlag(Context.BIND_ALMOST_PERCEPTIBLE)
- && cr.notHasFlag(Context.BIND_NOT_FOREGROUND)
- && clientAdj < PERCEPTIBLE_APP_ADJ
- && adj >= (lbAdj = PERCEPTIBLE_APP_ADJ)) {
- // This is for user-initiated jobs.
- // We use APP_ADJ + 1 here, so we can tell them apart from FGS.
- newAdj = PERCEPTIBLE_APP_ADJ + 1;
- } else if (cr.hasFlag(Context.BIND_ALMOST_PERCEPTIBLE)
- && cr.hasFlag(Context.BIND_NOT_FOREGROUND)
- && clientAdj < PERCEPTIBLE_APP_ADJ
- && adj >= (lbAdj = (PERCEPTIBLE_MEDIUM_APP_ADJ + 2))) {
- // This is for expedited jobs.
- // We use MEDIUM_APP_ADJ + 2 here, so we can tell apart
- // EJ and short-FGS.
- newAdj = PERCEPTIBLE_MEDIUM_APP_ADJ + 2;
- } else if (cr.hasFlag(Context.BIND_NOT_VISIBLE)
- && clientAdj < PERCEPTIBLE_APP_ADJ
- && adj >= (lbAdj = PERCEPTIBLE_APP_ADJ)) {
- newAdj = PERCEPTIBLE_APP_ADJ;
- } else if (clientAdj >= PERCEPTIBLE_APP_ADJ) {
- newAdj = clientAdj;
- } else if (cr.hasFlag(BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE)
- && clientAdj <= VISIBLE_APP_ADJ
- && adj > VISIBLE_APP_ADJ) {
- newAdj = VISIBLE_APP_ADJ;
- } else {
- if (adj > VISIBLE_APP_ADJ) {
- // TODO: Is this too limiting for apps bound from TOP?
- newAdj = Math.max(clientAdj, lbAdj);
- } else {
- newAdj = adj;
- }
- }
- if (!cstate.isCached()) {
- state.setCached(false);
- }
- if (adj > newAdj) {
- adj = newAdj;
- state.setCurRawAdj(adj);
- adjType = "service";
- }
- }
- }
- if (cr.notHasFlag(Context.BIND_NOT_FOREGROUND
- | Context.BIND_IMPORTANT_BACKGROUND)) {
- // This will treat important bound services identically to
- // the top app, which may behave differently than generic
- // foreground work.
- final int curSchedGroup = cstate.getCurrentSchedulingGroup();
- if (curSchedGroup > schedGroup) {
- if (cr.hasFlag(Context.BIND_IMPORTANT)) {
- schedGroup = curSchedGroup;
- } else {
- schedGroup = SCHED_GROUP_DEFAULT;
- }
- }
- if (clientProcState < PROCESS_STATE_TOP) {
- // Special handling for above-top states (persistent
- // processes). These should not bring the current process
- // into the top state, since they are not on top. Instead
- // give them the best bound state after that.
- if (cr.hasFlag(BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE)) {
- clientProcState = PROCESS_STATE_FOREGROUND_SERVICE;
- } else if (cr.hasFlag(Context.BIND_FOREGROUND_SERVICE)) {
- clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
- } else if (mService.mWakefulness.get()
- == PowerManagerInternal.WAKEFULNESS_AWAKE
- && cr.hasFlag(Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE))
- {
- clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
- } else {
- clientProcState =
- PROCESS_STATE_IMPORTANT_FOREGROUND;
- }
- } else if (clientProcState == PROCESS_STATE_TOP) {
- // Go at most to BOUND_TOP, unless requested to elevate
- // to client's state.
- clientProcState = PROCESS_STATE_BOUND_TOP;
- final boolean enabled = cstate.getCachedCompatChange(
- CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY);
- if (enabled) {
- if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
- // TOP process passes all capabilities to the service.
- capability |= cstate.getCurCapability();
- } else {
- // TOP process passes no capability to the service.
- }
- } else {
- // TOP process passes all capabilities to the service.
- capability |= cstate.getCurCapability();
- }
- }
- } else if (cr.notHasFlag(Context.BIND_IMPORTANT_BACKGROUND)) {
- if (clientProcState <
- PROCESS_STATE_TRANSIENT_BACKGROUND) {
- clientProcState =
- PROCESS_STATE_TRANSIENT_BACKGROUND;
- }
- } else {
- if (clientProcState <
- PROCESS_STATE_IMPORTANT_BACKGROUND) {
- clientProcState =
- PROCESS_STATE_IMPORTANT_BACKGROUND;
- }
- }
-
- if (schedGroup < SCHED_GROUP_TOP_APP
- && cr.hasFlag(Context.BIND_SCHEDULE_LIKE_TOP_APP)
- && clientIsSystem) {
- schedGroup = SCHED_GROUP_TOP_APP;
- scheduleLikeTopApp = true;
- }
+ computeServiceHostOomAdjLSP(cr, app, cr.binding.client, now, topApp, doingAll,
+ cycleReEval, computeClients, oomAdjReason, cachedAdj, true);
- if (!trackedProcState) {
- cr.trackProcState(clientProcState, mAdjSeq);
- }
-
- if (procState > clientProcState) {
- procState = clientProcState;
- state.setCurRawProcState(procState);
- if (adjType == null) {
- adjType = "service";
- }
- }
- if (procState < PROCESS_STATE_IMPORTANT_BACKGROUND
- && cr.hasFlag(Context.BIND_SHOWING_UI)) {
- app.setPendingUiClean(true);
- }
- if (adjType != null) {
- state.setAdjType(adjType);
- state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
- .REASON_SERVICE_IN_USE);
- state.setAdjSource(client);
- state.setAdjSourceProcState(clientProcState);
- state.setAdjTarget(s.instanceName);
- if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
- reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType
- + ": " + app + ", due to " + client
- + " adj=" + adj + " procState="
- + ProcessList.makeProcStateString(procState));
- }
- }
- } else { // BIND_WAIVE_PRIORITY == true
- // BIND_WAIVE_PRIORITY bindings are special when it comes to the
- // freezer. Processes bound via WPRI are expected to be running,
- // but they are not promoted in the LRU list to keep them out of
- // cached. As a result, they can freeze based on oom_adj alone.
- // Normally, bindToDeath would fire when a cached app would die
- // in the background, but nothing will fire when a running process
- // pings a frozen process. Accordingly, any cached app that is
- // bound by an unfrozen app via a WPRI binding has to remain
- // unfrozen.
- if (clientAdj < CACHED_APP_MIN_ADJ) {
- app.mOptRecord.setShouldNotFreeze(true);
- }
- }
- if (cr.hasFlag(Context.BIND_TREAT_LIKE_ACTIVITY)) {
- psr.setTreatLikeActivity(true);
- }
- final ActivityServiceConnectionsHolder a = cr.activity;
- if (cr.hasFlag(Context.BIND_ADJUST_WITH_ACTIVITY)) {
- if (a != null && adj > FOREGROUND_APP_ADJ
- && a.isActivityVisible()) {
- adj = FOREGROUND_APP_ADJ;
- state.setCurRawAdj(adj);
- if (cr.notHasFlag(Context.BIND_NOT_FOREGROUND)) {
- if (cr.hasFlag(Context.BIND_IMPORTANT)) {
- schedGroup = SCHED_GROUP_TOP_APP_BOUND;
- } else {
- schedGroup = SCHED_GROUP_DEFAULT;
- }
- }
- state.setCached(false);
- state.setAdjType("service");
- state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
- .REASON_SERVICE_IN_USE);
- state.setAdjSource(a);
- state.setAdjSourceProcState(procState);
- state.setAdjTarget(s.instanceName);
- if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
- reportOomAdjMessageLocked(TAG_OOM_ADJ,
- "Raise to service w/activity: " + app);
- }
- }
- }
+ adj = state.getCurRawAdj();
+ procState = state.getCurRawProcState();
+ schedGroup = state.getCurrentSchedulingGroup();
+ capability = state.getCurCapability();
}
}
}
@@ -2603,97 +2330,27 @@ public class OomAdjuster {
|| procState > PROCESS_STATE_TOP);
provi--) {
ContentProviderRecord cpr = ppr.getProviderAt(provi);
- for (int i = cpr.connections.size() - 1;
- i >= 0 && (adj > FOREGROUND_APP_ADJ
- || schedGroup == SCHED_GROUP_BACKGROUND
- || procState > PROCESS_STATE_TOP);
- i--) {
- ContentProviderConnection conn = cpr.connections.get(i);
- ProcessRecord client = conn.client;
- final ProcessStateRecord cstate = client.mState;
- if (client == app) {
- // Being our own client is not interesting.
- continue;
- }
- if (computeClients) {
- computeOomAdjLSP(client, cachedAdj, topApp, doingAll, now, cycleReEval, true);
- } else {
- cstate.setCurRawAdj(cstate.getCurAdj());
- cstate.setCurRawProcState(cstate.getCurProcState());
- }
-
- if (shouldSkipDueToCycle(app, cstate, procState, adj, cycleReEval)) {
- continue;
- }
-
- int clientAdj = cstate.getCurRawAdj();
- int clientProcState = cstate.getCurRawProcState();
-
- // We always propagate PROCESS_CAPABILITY_BFSL to providers here,
- // but, right before actually setting it to the process,
- // we check the final procstate, and remove it if the procsate is below BFGS.
- capability |= getBfslCapabilityFromClient(client);
-
- if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
- // If the other app is cached for any reason, for purposes here
- // we are going to consider it empty.
- clientProcState = PROCESS_STATE_CACHED_EMPTY;
- }
- if (client.mOptRecord.shouldNotFreeze()) {
- // Propagate the shouldNotFreeze flag down the bindings.
- app.mOptRecord.setShouldNotFreeze(true);
- }
-
- boundByNonBgRestricted |= cstate.isCurBoundByNonBgRestrictedApp()
- || clientProcState <= PROCESS_STATE_BOUND_TOP
- || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE
- && !cstate.isBackgroundRestricted());
-
- String adjType = null;
- if (adj > clientAdj) {
- if (state.hasShownUi() && !state.getCachedIsHomeProcess()
- && clientAdj > PERCEPTIBLE_APP_ADJ) {
- adjType = "cch-ui-provider";
- } else {
- adj = Math.max(clientAdj, FOREGROUND_APP_ADJ);
- state.setCurRawAdj(adj);
- adjType = "provider";
- }
- state.setCached(state.isCached() & cstate.isCached());
- }
-
- if (clientProcState <= PROCESS_STATE_FOREGROUND_SERVICE) {
- if (adjType == null) {
- adjType = "provider";
- }
- if (clientProcState == PROCESS_STATE_TOP) {
- clientProcState = PROCESS_STATE_BOUND_TOP;
- } else {
- clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
- }
- }
+ if (couldRecurse) {
+ // We're entering recursive functions below.
+ state.setCurRawAdj(adj);
+ state.setCurRawProcState(procState);
+ state.setCurrentSchedulingGroup(schedGroup);
+ state.setCurCapability(capability);
+
+ for (int i = cpr.connections.size() - 1;
+ i >= 0 && (adj > FOREGROUND_APP_ADJ
+ || schedGroup == SCHED_GROUP_BACKGROUND
+ || procState > PROCESS_STATE_TOP);
+ i--) {
+ ContentProviderConnection conn = cpr.connections.get(i);
+ ProcessRecord client = conn.client;
+ computeProviderHostOomAdjLSP(conn, app, client, now, topApp, doingAll,
+ cycleReEval, computeClients, oomAdjReason, cachedAdj, true);
- conn.trackProcState(clientProcState, mAdjSeq);
- if (procState > clientProcState) {
- procState = clientProcState;
- state.setCurRawProcState(procState);
- }
- if (cstate.getCurrentSchedulingGroup() > schedGroup) {
- schedGroup = SCHED_GROUP_DEFAULT;
- }
- if (adjType != null) {
- state.setAdjType(adjType);
- state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
- .REASON_PROVIDER_IN_USE);
- state.setAdjSource(client);
- state.setAdjSourceProcState(clientProcState);
- state.setAdjTarget(cpr.name);
- if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
- reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType
- + ": " + app + ", due to " + client
- + " adj=" + adj + " procState="
- + ProcessList.makeProcStateString(procState));
- }
+ adj = state.getCurRawAdj();
+ procState = state.getCurRawProcState();
+ schedGroup = state.getCurrentSchedulingGroup();
+ capability = state.getCurCapability();
}
}
// If the provider has external (non-framework) process
@@ -2799,7 +2456,7 @@ public class OomAdjuster {
// restrictions on screen off
if (procState >= PROCESS_STATE_BOUND_FOREGROUND_SERVICE
&& mService.mWakefulness.get() != PowerManagerInternal.WAKEFULNESS_AWAKE
- && !scheduleLikeTopApp) {
+ && !state.shouldScheduleLikeTopApp()) {
if (schedGroup > SCHED_GROUP_RESTRICTED) {
schedGroup = SCHED_GROUP_RESTRICTED;
}
@@ -2817,7 +2474,6 @@ public class OomAdjuster {
capability &= ~PROCESS_CAPABILITY_BFSL;
}
-
if (app.isPendingFinishAttach()) {
// If the app is still starting up. We reset the computations to the
// hardcoded values in setAttachingProcessStatesLSP. This ensures that the app keeps
@@ -2834,22 +2490,581 @@ public class OomAdjuster {
// it when computing the final cached adj later. Note that we don't need to
// worry about this for max adj above, since max adj will always be used to
// keep it out of the cached vaues.
- state.setCurAdj(adj);
state.setCurCapability(capability);
- state.setCurrentSchedulingGroup(schedGroup);
- state.setCurProcState(procState);
- state.setCurRawProcState(procState);
state.updateLastInvisibleTime(hasVisibleActivities);
state.setHasForegroundActivities(foregroundActivities);
state.setCompletedAdjSeq(mAdjSeq);
- state.setCurBoundByNonBgRestrictedApp(boundByNonBgRestricted);
+
+ schedGroup = setIntermediateAdjLSP(app, adj, prevAppAdj, schedGroup);
+ setIntermediateProcStateLSP(app, procState, prevProcState);
+ setIntermediateSchedGroupLSP(state, schedGroup);
// if curAdj or curProcState improved, then this process was promoted
return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState
|| state.getCurCapability() != prevCapability;
}
- private int getDefaultCapability(ProcessRecord app, int procState) {
+ /**
+ * @return The proposed change to the schedGroup.
+ */
+ @GuardedBy({"mService", "mProcLock"})
+ protected int setIntermediateAdjLSP(ProcessRecord app, int adj, int prevRawAppAdj,
+ int schedGroup) {
+ final ProcessStateRecord state = app.mState;
+ state.setCurRawAdj(adj);
+
+ adj = app.mServices.modifyRawOomAdj(adj);
+ if (adj > state.getMaxAdj()) {
+ adj = state.getMaxAdj();
+ if (adj <= PERCEPTIBLE_LOW_APP_ADJ) {
+ schedGroup = SCHED_GROUP_DEFAULT;
+ }
+ }
+
+ state.setCurAdj(adj);
+
+ return schedGroup;
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ protected void setIntermediateProcStateLSP(ProcessRecord app, int procState,
+ int prevProcState) {
+ final ProcessStateRecord state = app.mState;
+ state.setCurProcState(procState);
+ state.setCurRawProcState(procState);
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ protected void setIntermediateSchedGroupLSP(ProcessStateRecord state, int schedGroup) {
+ // Put bound foreground services in a special sched group for additional
+ // restrictions on screen off
+ if (state.getCurProcState() >= PROCESS_STATE_BOUND_FOREGROUND_SERVICE
+ && mService.mWakefulness.get() != PowerManagerInternal.WAKEFULNESS_AWAKE
+ && !state.shouldScheduleLikeTopApp()) {
+ if (schedGroup > SCHED_GROUP_RESTRICTED) {
+ schedGroup = SCHED_GROUP_RESTRICTED;
+ }
+ }
+
+ state.setCurrentSchedulingGroup(schedGroup);
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ protected void computeServiceHostOomAdjLSP(ConnectionRecord cr, ProcessRecord app,
+ ProcessRecord client, long now, ProcessRecord topApp, boolean doingAll,
+ boolean cycleReEval, boolean computeClients, int oomAdjReason, int cachedAdj,
+ boolean couldRecurse) {
+ if (app.isPendingFinishAttach()) {
+ // We've set the attaching process state in the computeInitialOomAdjLSP. Skip it here.
+ return;
+ }
+
+ final ProcessStateRecord state = app.mState;
+ ProcessStateRecord cstate = client.mState;
+
+ if (couldRecurse) {
+ if (app.isSdkSandbox && cr.binding.attributedClient != null) {
+ // For SDK sandboxes, use the attributed client (eg the app that
+ // requested the sandbox)
+ client = cr.binding.attributedClient;
+ cstate = client.mState;
+ }
+ if (computeClients) {
+ computeOomAdjLSP(client, cachedAdj, topApp, doingAll, now, cycleReEval, true,
+ oomAdjReason, true);
+ } else {
+ cstate.setCurRawAdj(cstate.getCurAdj());
+ cstate.setCurRawProcState(cstate.getCurProcState());
+ }
+ }
+
+ int clientAdj = cstate.getCurRawAdj();
+ int clientProcState = cstate.getCurRawProcState();
+
+ final boolean clientIsSystem = clientProcState < PROCESS_STATE_TOP;
+
+ int adj = state.getCurRawAdj();
+ int procState = state.getCurRawProcState();
+ int schedGroup = state.getCurrentSchedulingGroup();
+ int capability = state.getCurCapability();
+
+ final int prevRawAdj = adj;
+ final int prevProcState = procState;
+ final int prevSchedGroup = schedGroup;
+
+ final int appUid = app.info.uid;
+ final int logUid = mService.mCurOomAdjUid;
+
+ state.setCurBoundByNonBgRestrictedApp(state.isCurBoundByNonBgRestrictedApp()
+ || cstate.isCurBoundByNonBgRestrictedApp()
+ || clientProcState <= PROCESS_STATE_BOUND_TOP
+ || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE
+ && !cstate.isBackgroundRestricted()));
+
+ if (client.mOptRecord.shouldNotFreeze()) {
+ // Propagate the shouldNotFreeze flag down the bindings.
+ app.mOptRecord.setShouldNotFreeze(true);
+ }
+
+ boolean trackedProcState = false;
+
+ // We always propagate PROCESS_CAPABILITY_BFSL over bindings here,
+ // but, right before actually setting it to the process,
+ // we check the final procstate, and remove it if the procsate is below BFGS.
+ capability |= getBfslCapabilityFromClient(client);
+
+ if (cr.notHasFlag(Context.BIND_WAIVE_PRIORITY)) {
+ if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
+ capability |= cstate.getCurCapability();
+ }
+
+ // If an app has network capability by default
+ // (by having procstate <= BFGS), then the apps it binds to will get
+ // elevated to a high enough procstate anyway to get network unless they
+ // request otherwise, so don't propagate the network capability by default
+ // in this case unless they explicitly request it.
+ if ((cstate.getCurCapability()
+ & PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) != 0) {
+ if (clientProcState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+ // This is used to grant network access to Expedited Jobs.
+ if (cr.hasFlag(Context.BIND_BYPASS_POWER_NETWORK_RESTRICTIONS)) {
+ capability |= PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
+ }
+ } else {
+ capability |= PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
+ }
+ }
+ if ((cstate.getCurCapability()
+ & PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK) != 0) {
+ if (clientProcState <= PROCESS_STATE_IMPORTANT_FOREGROUND) {
+ // This is used to grant network access to User Initiated Jobs.
+ if (cr.hasFlag(Context.BIND_BYPASS_USER_NETWORK_RESTRICTIONS)) {
+ capability |= PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
+ }
+ }
+ }
+
+ if (couldRecurse && shouldSkipDueToCycle(app, cstate, procState, adj, cycleReEval)) {
+ return;
+ }
+
+ if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
+ // If the other app is cached for any reason, for purposes here
+ // we are going to consider it empty. The specific cached state
+ // doesn't propagate except under certain conditions.
+ clientProcState = PROCESS_STATE_CACHED_EMPTY;
+ }
+ String adjType = null;
+ if (cr.hasFlag(Context.BIND_ALLOW_OOM_MANAGEMENT)) {
+ // Similar to BIND_WAIVE_PRIORITY, keep it unfrozen.
+ if (clientAdj < CACHED_APP_MIN_ADJ) {
+ app.mOptRecord.setShouldNotFreeze(true);
+ }
+ // Not doing bind OOM management, so treat
+ // this guy more like a started service.
+ if (state.hasShownUi() && !state.getCachedIsHomeProcess()) {
+ // If this process has shown some UI, let it immediately
+ // go to the LRU list because it may be pretty heavy with
+ // UI stuff. We'll tag it with a label just to help
+ // debug and understand what is going on.
+ if (adj > clientAdj) {
+ adjType = "cch-bound-ui-services";
+ }
+ state.setCached(false);
+ clientAdj = adj;
+ clientProcState = procState;
+ } else {
+ if (now >= (cr.binding.service.lastActivity
+ + mConstants.MAX_SERVICE_INACTIVITY)) {
+ // This service has not seen activity within
+ // recent memory, so allow it to drop to the
+ // LRU list if there is no other reason to keep
+ // it around. We'll also tag it with a label just
+ // to help debug and undertand what is going on.
+ if (adj > clientAdj) {
+ adjType = "cch-bound-services";
+ }
+ clientAdj = adj;
+ }
+ }
+ }
+ if (adj > clientAdj) {
+ // If this process has recently shown UI, and
+ // the process that is binding to it is less
+ // important than being visible, then we don't
+ // care about the binding as much as we care
+ // about letting this process get into the LRU
+ // list to be killed and restarted if needed for
+ // memory.
+ if (state.hasShownUi() && !state.getCachedIsHomeProcess()
+ && clientAdj > PERCEPTIBLE_APP_ADJ) {
+ if (adj >= CACHED_APP_MIN_ADJ) {
+ adjType = "cch-bound-ui-services";
+ }
+ } else {
+ int newAdj;
+ int lbAdj = VISIBLE_APP_ADJ; // lower bound of adj.
+ if (cr.hasFlag(Context.BIND_ABOVE_CLIENT
+ | Context.BIND_IMPORTANT)) {
+ if (clientAdj >= PERSISTENT_SERVICE_ADJ) {
+ newAdj = clientAdj;
+ } else {
+ // make this service persistent
+ newAdj = PERSISTENT_SERVICE_ADJ;
+ schedGroup = SCHED_GROUP_DEFAULT;
+ procState = ActivityManager.PROCESS_STATE_PERSISTENT;
+ cr.trackProcState(procState, mAdjSeq);
+ trackedProcState = true;
+ }
+ } else if (cr.hasFlag(Context.BIND_NOT_PERCEPTIBLE)
+ && clientAdj <= PERCEPTIBLE_APP_ADJ
+ && adj >= (lbAdj = PERCEPTIBLE_LOW_APP_ADJ)) {
+ newAdj = PERCEPTIBLE_LOW_APP_ADJ;
+ } else if (cr.hasFlag(Context.BIND_ALMOST_PERCEPTIBLE)
+ && cr.notHasFlag(Context.BIND_NOT_FOREGROUND)
+ && clientAdj < PERCEPTIBLE_APP_ADJ
+ && adj >= (lbAdj = PERCEPTIBLE_APP_ADJ)) {
+ // This is for user-initiated jobs.
+ // We use APP_ADJ + 1 here, so we can tell them apart from FGS.
+ newAdj = PERCEPTIBLE_APP_ADJ + 1;
+ } else if (cr.hasFlag(Context.BIND_ALMOST_PERCEPTIBLE)
+ && cr.hasFlag(Context.BIND_NOT_FOREGROUND)
+ && clientAdj < PERCEPTIBLE_APP_ADJ
+ && adj >= (lbAdj = (PERCEPTIBLE_MEDIUM_APP_ADJ + 2))) {
+ // This is for expedited jobs.
+ // We use MEDIUM_APP_ADJ + 2 here, so we can tell apart
+ // EJ and short-FGS.
+ newAdj = PERCEPTIBLE_MEDIUM_APP_ADJ + 2;
+ } else if (cr.hasFlag(Context.BIND_NOT_VISIBLE)
+ && clientAdj < PERCEPTIBLE_APP_ADJ
+ && adj >= (lbAdj = PERCEPTIBLE_APP_ADJ)) {
+ newAdj = PERCEPTIBLE_APP_ADJ;
+ } else if (clientAdj >= PERCEPTIBLE_APP_ADJ) {
+ newAdj = clientAdj;
+ } else if (cr.hasFlag(BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE)
+ && clientAdj <= VISIBLE_APP_ADJ
+ && adj > VISIBLE_APP_ADJ) {
+ newAdj = VISIBLE_APP_ADJ;
+ } else {
+ if (adj > VISIBLE_APP_ADJ) {
+ // TODO: Is this too limiting for apps bound from TOP?
+ newAdj = Math.max(clientAdj, lbAdj);
+ } else {
+ newAdj = adj;
+ }
+ }
+ if (!cstate.isCached()) {
+ state.setCached(false);
+ }
+ if (adj > newAdj) {
+ adj = newAdj;
+ state.setCurRawAdj(adj);
+ adjType = "service";
+ }
+ }
+ }
+ if (cr.notHasFlag(Context.BIND_NOT_FOREGROUND
+ | Context.BIND_IMPORTANT_BACKGROUND)) {
+ // This will treat important bound services identically to
+ // the top app, which may behave differently than generic
+ // foreground work.
+ final int curSchedGroup = cstate.getCurrentSchedulingGroup();
+ if (curSchedGroup > schedGroup) {
+ if (cr.hasFlag(Context.BIND_IMPORTANT)) {
+ schedGroup = curSchedGroup;
+ } else {
+ schedGroup = SCHED_GROUP_DEFAULT;
+ }
+ }
+ if (clientProcState < PROCESS_STATE_TOP) {
+ // Special handling for above-top states (persistent
+ // processes). These should not bring the current process
+ // into the top state, since they are not on top. Instead
+ // give them the best bound state after that.
+ if (cr.hasFlag(BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE)) {
+ clientProcState = PROCESS_STATE_FOREGROUND_SERVICE;
+ } else if (cr.hasFlag(Context.BIND_FOREGROUND_SERVICE)) {
+ clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ } else if (mService.mWakefulness.get()
+ == PowerManagerInternal.WAKEFULNESS_AWAKE
+ && cr.hasFlag(Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)) {
+ clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ } else {
+ clientProcState =
+ PROCESS_STATE_IMPORTANT_FOREGROUND;
+ }
+ } else if (clientProcState == PROCESS_STATE_TOP) {
+ // Go at most to BOUND_TOP, unless requested to elevate
+ // to client's state.
+ clientProcState = PROCESS_STATE_BOUND_TOP;
+ final boolean enabled = cstate.getCachedCompatChange(
+ CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY);
+ if (enabled) {
+ if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
+ // TOP process passes all capabilities to the service.
+ capability |= cstate.getCurCapability();
+ } else {
+ // TOP process passes no capability to the service.
+ }
+ } else {
+ // TOP process passes all capabilities to the service.
+ capability |= cstate.getCurCapability();
+ }
+ }
+ } else if (cr.notHasFlag(Context.BIND_IMPORTANT_BACKGROUND)) {
+ if (clientProcState < PROCESS_STATE_TRANSIENT_BACKGROUND) {
+ clientProcState =
+ PROCESS_STATE_TRANSIENT_BACKGROUND;
+ }
+ } else {
+ if (clientProcState < PROCESS_STATE_IMPORTANT_BACKGROUND) {
+ clientProcState =
+ PROCESS_STATE_IMPORTANT_BACKGROUND;
+ }
+ }
+
+ if (schedGroup < SCHED_GROUP_TOP_APP
+ && cr.hasFlag(Context.BIND_SCHEDULE_LIKE_TOP_APP)
+ && clientIsSystem) {
+ schedGroup = SCHED_GROUP_TOP_APP;
+ state.setScheduleLikeTopApp(true);
+ }
+
+ if (!trackedProcState) {
+ cr.trackProcState(clientProcState, mAdjSeq);
+ }
+
+ if (procState > clientProcState) {
+ procState = clientProcState;
+ state.setCurRawProcState(procState);
+ if (adjType == null) {
+ adjType = "service";
+ }
+ }
+ if (procState < PROCESS_STATE_IMPORTANT_BACKGROUND
+ && cr.hasFlag(Context.BIND_SHOWING_UI)) {
+ app.setPendingUiClean(true);
+ }
+ if (adjType != null) {
+ state.setAdjType(adjType);
+ state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
+ .REASON_SERVICE_IN_USE);
+ state.setAdjSource(client);
+ state.setAdjSourceProcState(clientProcState);
+ state.setAdjTarget(cr.binding.service.instanceName);
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType
+ + ": " + app + ", due to " + client
+ + " adj=" + adj + " procState="
+ + ProcessList.makeProcStateString(procState));
+ }
+ }
+ } else { // BIND_WAIVE_PRIORITY == true
+ // BIND_WAIVE_PRIORITY bindings are special when it comes to the
+ // freezer. Processes bound via WPRI are expected to be running,
+ // but they are not promoted in the LRU list to keep them out of
+ // cached. As a result, they can freeze based on oom_adj alone.
+ // Normally, bindToDeath would fire when a cached app would die
+ // in the background, but nothing will fire when a running process
+ // pings a frozen process. Accordingly, any cached app that is
+ // bound by an unfrozen app via a WPRI binding has to remain
+ // unfrozen.
+ if (clientAdj < CACHED_APP_MIN_ADJ) {
+ app.mOptRecord.setShouldNotFreeze(true);
+ }
+ }
+ if (cr.hasFlag(Context.BIND_TREAT_LIKE_ACTIVITY)) {
+ app.mServices.setTreatLikeActivity(true);
+ if (clientProcState <= PROCESS_STATE_CACHED_ACTIVITY
+ && procState > PROCESS_STATE_CACHED_ACTIVITY) {
+ // This is a cached process, but somebody wants us to treat it like it has
+ // an activity, okay!
+ procState = PROCESS_STATE_CACHED_ACTIVITY;
+ state.setAdjType("cch-as-act");
+ }
+ }
+ final ActivityServiceConnectionsHolder a = cr.activity;
+ if (cr.hasFlag(Context.BIND_ADJUST_WITH_ACTIVITY)) {
+ if (a != null && adj > FOREGROUND_APP_ADJ
+ && a.isActivityVisible()) {
+ adj = FOREGROUND_APP_ADJ;
+ state.setCurRawAdj(adj);
+ if (cr.notHasFlag(Context.BIND_NOT_FOREGROUND)) {
+ if (cr.hasFlag(Context.BIND_IMPORTANT)) {
+ schedGroup = SCHED_GROUP_TOP_APP_BOUND;
+ } else {
+ schedGroup = SCHED_GROUP_DEFAULT;
+ }
+ }
+ state.setCached(false);
+ state.setAdjType("service");
+ state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
+ .REASON_SERVICE_IN_USE);
+ state.setAdjSource(a);
+ state.setAdjSourceProcState(procState);
+ state.setAdjTarget(cr.binding.service.instanceName);
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise to service w/activity: " + app);
+ }
+ }
+ }
+
+ capability |= getDefaultCapability(app, procState);
+
+ // Procstates below BFGS should never have this capability.
+ if (procState > PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+ capability &= ~PROCESS_CAPABILITY_BFSL;
+ }
+
+ if (adj < prevRawAdj) {
+ schedGroup = setIntermediateAdjLSP(app, adj, prevRawAdj, schedGroup);
+ }
+ if (procState < prevProcState) {
+ setIntermediateProcStateLSP(app, procState, prevProcState);
+ }
+ if (schedGroup > prevSchedGroup) {
+ setIntermediateSchedGroupLSP(state, schedGroup);
+ }
+ state.setCurCapability(capability);
+
+ state.setEmpty(false);
+ }
+
+ protected void computeProviderHostOomAdjLSP(ContentProviderConnection conn, ProcessRecord app,
+ ProcessRecord client, long now, ProcessRecord topApp, boolean doingAll,
+ boolean cycleReEval, boolean computeClients, int oomAdjReason, int cachedAdj,
+ boolean couldRecurse) {
+ if (app.isPendingFinishAttach()) {
+ // We've set the attaching process state in the computeInitialOomAdjLSP. Skip it here.
+ return;
+ }
+
+ final ProcessStateRecord state = app.mState;
+ final ProcessStateRecord cstate = client.mState;
+
+ if (client == app) {
+ // Being our own client is not interesting.
+ return;
+ }
+ if (couldRecurse) {
+ if (computeClients) {
+ computeOomAdjLSP(client, cachedAdj, topApp, doingAll, now, cycleReEval, true,
+ oomAdjReason, true);
+ } else if (couldRecurse) {
+ cstate.setCurRawAdj(cstate.getCurAdj());
+ cstate.setCurRawProcState(cstate.getCurProcState());
+ }
+
+ if (shouldSkipDueToCycle(app, cstate, state.getCurRawProcState(), state.getCurRawAdj(),
+ cycleReEval)) {
+ return;
+ }
+ }
+
+ int clientAdj = cstate.getCurRawAdj();
+ int clientProcState = cstate.getCurRawProcState();
+
+ int adj = state.getCurRawAdj();
+ int procState = state.getCurRawProcState();
+ int schedGroup = state.getCurrentSchedulingGroup();
+ int capability = state.getCurCapability();
+
+ final int prevRawAdj = adj;
+ final int prevProcState = procState;
+ final int prevSchedGroup = schedGroup;
+
+ final int appUid = app.info.uid;
+ final int logUid = mService.mCurOomAdjUid;
+
+ // We always propagate PROCESS_CAPABILITY_BFSL to providers here,
+ // but, right before actually setting it to the process,
+ // we check the final procstate, and remove it if the procsate is below BFGS.
+ capability |= getBfslCapabilityFromClient(client);
+
+ if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
+ // If the other app is cached for any reason, for purposes here
+ // we are going to consider it empty.
+ clientProcState = PROCESS_STATE_CACHED_EMPTY;
+ }
+ if (client.mOptRecord.shouldNotFreeze()) {
+ // Propagate the shouldNotFreeze flag down the bindings.
+ app.mOptRecord.setShouldNotFreeze(true);
+ }
+
+ state.setCurBoundByNonBgRestrictedApp(state.isCurBoundByNonBgRestrictedApp()
+ || cstate.isCurBoundByNonBgRestrictedApp()
+ || clientProcState <= PROCESS_STATE_BOUND_TOP
+ || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE
+ && !cstate.isBackgroundRestricted()));
+
+ String adjType = null;
+ if (adj > clientAdj) {
+ if (state.hasShownUi() && !state.getCachedIsHomeProcess()
+ && clientAdj > PERCEPTIBLE_APP_ADJ) {
+ adjType = "cch-ui-provider";
+ } else {
+ adj = Math.max(clientAdj, FOREGROUND_APP_ADJ);
+ state.setCurRawAdj(adj);
+ adjType = "provider";
+ }
+ state.setCached(state.isCached() & cstate.isCached());
+ }
+
+ if (clientProcState <= PROCESS_STATE_FOREGROUND_SERVICE) {
+ if (adjType == null) {
+ adjType = "provider";
+ }
+ if (clientProcState == PROCESS_STATE_TOP) {
+ clientProcState = PROCESS_STATE_BOUND_TOP;
+ } else {
+ clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ }
+ }
+
+ conn.trackProcState(clientProcState, mAdjSeq);
+ if (procState > clientProcState) {
+ procState = clientProcState;
+ state.setCurRawProcState(procState);
+ }
+ if (cstate.getCurrentSchedulingGroup() > schedGroup) {
+ schedGroup = SCHED_GROUP_DEFAULT;
+ }
+ if (adjType != null) {
+ state.setAdjType(adjType);
+ state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
+ .REASON_PROVIDER_IN_USE);
+ state.setAdjSource(client);
+ state.setAdjSourceProcState(clientProcState);
+ state.setAdjTarget(conn.provider.name);
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to " + adjType
+ + ": " + app + ", due to " + client
+ + " adj=" + adj + " procState="
+ + ProcessList.makeProcStateString(procState));
+ }
+ }
+
+ // Procstates below BFGS should never have this capability.
+ if (procState > PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+ capability &= ~PROCESS_CAPABILITY_BFSL;
+ }
+
+ if (adj < prevRawAdj) {
+ schedGroup = setIntermediateAdjLSP(app, adj, prevRawAdj, schedGroup);
+ }
+ if (procState < prevProcState) {
+ setIntermediateProcStateLSP(app, procState, prevProcState);
+ }
+ if (schedGroup > prevSchedGroup) {
+ setIntermediateSchedGroupLSP(state, schedGroup);
+ }
+ state.setCurCapability(capability);
+
+ state.setEmpty(false);
+ }
+
+ protected int getDefaultCapability(ProcessRecord app, int procState) {
final int networkCapabilities =
NetworkPolicyManager.getDefaultProcessNetworkCapabilities(procState);
final int baseCapabilities;
@@ -2882,7 +3097,7 @@ public class OomAdjuster {
/**
* @return the BFSL capability from a client (of a service binding or provider).
*/
- int getBfslCapabilityFromClient(ProcessRecord client) {
+ protected int getBfslCapabilityFromClient(ProcessRecord client) {
// Procstates above FGS should always have this flag. We shouldn't need this logic,
// but let's do it just in case.
if (client.mState.getCurProcState() < PROCESS_STATE_FOREGROUND_SERVICE) {
@@ -2967,7 +3182,7 @@ public class OomAdjuster {
/** Inform the oomadj observer of changes to oomadj. Used by tests. */
@GuardedBy("mService")
- private void reportOomAdjMessageLocked(String tag, String msg) {
+ protected void reportOomAdjMessageLocked(String tag, String msg) {
Slog.d(tag, msg);
synchronized (mService.mOomAdjObserverLock) {
if (mService.mCurOomAdjObserver != null) {
@@ -2983,7 +3198,7 @@ public class OomAdjuster {
/** Applies the computed oomadj, procstate and sched group values and freezes them in set* */
@GuardedBy({"mService", "mProcLock"})
- private boolean applyOomAdjLSP(ProcessRecord app, boolean doingAll, long now,
+ protected boolean applyOomAdjLSP(ProcessRecord app, boolean doingAll, long now,
long nowElapsed, @OomAdjReason int oomAdjReson) {
boolean success = true;
final ProcessStateRecord state = app.mState;
@@ -3272,6 +3487,8 @@ public class OomAdjuster {
int initialCapability = PROCESS_CAPABILITY_NONE;
boolean initialCached = true;
final ProcessStateRecord state = app.mState;
+ final int prevProcState = PROCESS_STATE_UNKNOWN;
+ final int prevAdj = UNKNOWN_ADJ;
// If the process has been marked as foreground, it is starting as the top app (with
// Zygote#START_AS_TOP_APP_ARG), so boost the thread priority of its default UI thread.
if (state.hasForegroundActivities()) {
@@ -3306,6 +3523,9 @@ public class OomAdjuster {
state.setCurRawAdj(ProcessList.FOREGROUND_APP_ADJ);
state.setForcingToImportant(null);
state.setHasShownUi(false);
+
+ onProcessStateChanged(app, prevProcState);
+ onProcessOomAdjChanged(app, prevAdj);
}
// ONLY used for unit testing in OomAdjusterTests.java
@@ -3553,4 +3773,56 @@ public class OomAdjuster {
}
processes.clear();
}
+
+ @GuardedBy("mService")
+ void onProcessBeginLocked(@NonNull ProcessRecord app) {
+ // Empty, the OomAdjusterModernImpl will have an implementation.
+ }
+
+ @GuardedBy("mService")
+ void onProcessEndLocked(@NonNull ProcessRecord app) {
+ // Empty, the OomAdjusterModernImpl will have an implementation.
+ }
+
+ /**
+ * Called when the process state is changed outside of the OomAdjuster.
+ */
+ @GuardedBy("mService")
+ void onProcessStateChanged(@NonNull ProcessRecord app, int prevProcState) {
+ // Empty, the OomAdjusterModernImpl will have an implementation.
+ }
+
+ /**
+ * Called when the oom adj is changed outside of the OomAdjuster.
+ */
+ @GuardedBy("mService")
+ void onProcessOomAdjChanged(@NonNull ProcessRecord app, int prevAdj) {
+ // Empty, the OomAdjusterModernImpl will have an implementation.
+ }
+
+ @VisibleForTesting
+ void resetInternal() {
+ // Empty, the OomAdjusterModernImpl will have an implementation.
+ }
+
+ @GuardedBy("mService")
+ protected int getInitialAdj(@NonNull ProcessRecord app) {
+ return app.mState.getCurAdj();
+ }
+
+ @GuardedBy("mService")
+ protected int getInitialProcState(@NonNull ProcessRecord app) {
+ return app.mState.getCurProcState();
+ }
+
+ @GuardedBy("mService")
+ protected int getInitialCapability(@NonNull ProcessRecord app) {
+ return app.mState.getCurCapability();
+ }
+
+ @GuardedBy("mService")
+ protected boolean getInitialIsCurBoundByNonBgRestrictedApp(@NonNull ProcessRecord app) {
+ // The caller will set the initial value in this implementation.
+ return app.mState.isCurBoundByNonBgRestrictedApp();
+ }
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.md b/services/core/java/com/android/server/am/OomAdjuster.md
index 16091d1c162d..da5e12ef21fa 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.md
+++ b/services/core/java/com/android/server/am/OomAdjuster.md
@@ -130,3 +130,28 @@ The Oom Adjuster maintains a global sequence ID `mAdjSeq` to track the current O
* Iterate the processes from least important to most important ones.
* A maximum retries of 10 is enforced, while in practice, the maximum retries could reach only 2 to 3.
+## The Modern Implementation
+
+As aforementioned, the OomAdjuster makes the computation in a recursive way, while this is inefficient in dealing with the cycles. The overall code complexity should be around **O((1 + num(retries)) * num(procs) * num(binding connections))**. In addition, depending on the ordering of the input, the algorithm may produce different results and sometimes it's wrong.
+
+The new "Modern Implementation" is based on the rationale that, apps can't promote the service/provider it connects to, to a higher bucket than itself. We are introducing a bucket based, breadth first search algorithm, as illustrated below:
+
+```
+for all processes in the process list
+ compute the state of each process, but, excluding its clients
+ put each process to the corresponding bucket according to the state value
+done
+
+for each bucket, starting from the top most to the bottom most
+ for each process in the bucket
+ for each process it binds to
+ if the state of the bindee process could be elevated because of the binding; then
+ move the bindee process to the higher bucket
+ fi
+ done
+ done
+done
+```
+
+The overall code complexity should be around **O(num(procs) * num(binding connections))**, which saves the retry time from the existing algorithm.
+
diff --git a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
new file mode 100644
index 000000000000..b852ef56fceb
--- /dev/null
+++ b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
@@ -0,0 +1,1125 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import static android.app.ActivityManager.PROCESS_STATE_BACKUP;
+import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_RECENT;
+import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
+import static android.app.ActivityManager.PROCESS_STATE_HOME;
+import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT;
+import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
+import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
+import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_TOP;
+import static android.app.ActivityManager.PROCESS_STATE_TOP_SLEEPING;
+import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
+
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
+import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS;
+import static com.android.server.am.ProcessList.BACKUP_APP_ADJ;
+import static com.android.server.am.ProcessList.CACHED_APP_MIN_ADJ;
+import static com.android.server.am.ProcessList.FOREGROUND_APP_ADJ;
+import static com.android.server.am.ProcessList.HEAVY_WEIGHT_APP_ADJ;
+import static com.android.server.am.ProcessList.HOME_APP_ADJ;
+import static com.android.server.am.ProcessList.NATIVE_ADJ;
+import static com.android.server.am.ProcessList.PERCEPTIBLE_APP_ADJ;
+import static com.android.server.am.ProcessList.PERCEPTIBLE_LOW_APP_ADJ;
+import static com.android.server.am.ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ;
+import static com.android.server.am.ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ;
+import static com.android.server.am.ProcessList.PERSISTENT_PROC_ADJ;
+import static com.android.server.am.ProcessList.PERSISTENT_SERVICE_ADJ;
+import static com.android.server.am.ProcessList.PREVIOUS_APP_ADJ;
+import static com.android.server.am.ProcessList.SCHED_GROUP_BACKGROUND;
+import static com.android.server.am.ProcessList.SERVICE_ADJ;
+import static com.android.server.am.ProcessList.SERVICE_B_ADJ;
+import static com.android.server.am.ProcessList.SYSTEM_ADJ;
+import static com.android.server.am.ProcessList.UNKNOWN_ADJ;
+import static com.android.server.am.ProcessList.VISIBLE_APP_ADJ;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal.OomAdjReason;
+import android.content.pm.ServiceInfo;
+import android.os.IBinder;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.ServiceThread;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.function.Consumer;
+
+/**
+ * A modern implementation of the oom adjuster.
+ */
+public class OomAdjusterModernImpl extends OomAdjuster {
+ static final String TAG = "OomAdjusterModernImpl";
+
+ // The ADJ_SLOT_INVALID is NOT an actual slot.
+ static final int ADJ_SLOT_INVALID = -1;
+ static final int ADJ_SLOT_NATIVE = 0;
+ static final int ADJ_SLOT_SYSTEM = 1;
+ static final int ADJ_SLOT_PERSISTENT_PROC = 2;
+ static final int ADJ_SLOT_PERSISTENT_SERVICE = 3;
+ static final int ADJ_SLOT_FOREGROUND_APP = 4;
+ static final int ADJ_SLOT_PERCEPTIBLE_RECENT_FOREGROUND_APP = 5;
+ static final int ADJ_SLOT_VISIBLE_APP = 6;
+ static final int ADJ_SLOT_PERCEPTIBLE_APP = 7;
+ static final int ADJ_SLOT_PERCEPTIBLE_MEDIUM_APP = 8;
+ static final int ADJ_SLOT_PERCEPTIBLE_LOW_APP = 9;
+ static final int ADJ_SLOT_BACKUP_APP = 10;
+ static final int ADJ_SLOT_HEAVY_WEIGHT_APP = 11;
+ static final int ADJ_SLOT_SERVICE = 12;
+ static final int ADJ_SLOT_HOME_APP = 13;
+ static final int ADJ_SLOT_PREVIOUS_APP = 14;
+ static final int ADJ_SLOT_SERVICE_B = 15;
+ static final int ADJ_SLOT_CACHED_APP = 16;
+ static final int ADJ_SLOT_UNKNOWN = 17;
+
+ @IntDef(prefix = { "ADJ_SLOT_" }, value = {
+ ADJ_SLOT_INVALID,
+ ADJ_SLOT_NATIVE,
+ ADJ_SLOT_SYSTEM,
+ ADJ_SLOT_PERSISTENT_PROC,
+ ADJ_SLOT_PERSISTENT_SERVICE,
+ ADJ_SLOT_FOREGROUND_APP,
+ ADJ_SLOT_PERCEPTIBLE_RECENT_FOREGROUND_APP,
+ ADJ_SLOT_VISIBLE_APP,
+ ADJ_SLOT_PERCEPTIBLE_APP,
+ ADJ_SLOT_PERCEPTIBLE_MEDIUM_APP,
+ ADJ_SLOT_PERCEPTIBLE_LOW_APP,
+ ADJ_SLOT_BACKUP_APP,
+ ADJ_SLOT_HEAVY_WEIGHT_APP,
+ ADJ_SLOT_SERVICE,
+ ADJ_SLOT_HOME_APP,
+ ADJ_SLOT_PREVIOUS_APP,
+ ADJ_SLOT_SERVICE_B,
+ ADJ_SLOT_CACHED_APP,
+ ADJ_SLOT_UNKNOWN,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface AdjSlot{}
+
+ static final int[] ADJ_SLOT_VALUES = new int[] {
+ NATIVE_ADJ,
+ SYSTEM_ADJ,
+ PERSISTENT_PROC_ADJ,
+ PERSISTENT_SERVICE_ADJ,
+ FOREGROUND_APP_ADJ,
+ PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ,
+ VISIBLE_APP_ADJ,
+ PERCEPTIBLE_APP_ADJ,
+ PERCEPTIBLE_MEDIUM_APP_ADJ,
+ PERCEPTIBLE_LOW_APP_ADJ,
+ BACKUP_APP_ADJ,
+ HEAVY_WEIGHT_APP_ADJ,
+ SERVICE_ADJ,
+ HOME_APP_ADJ,
+ PREVIOUS_APP_ADJ,
+ SERVICE_B_ADJ,
+ CACHED_APP_MIN_ADJ,
+ UNKNOWN_ADJ,
+ };
+
+ /**
+ * Note: Always use the raw adj to call this API.
+ */
+ static @AdjSlot int adjToSlot(int adj) {
+ if (adj >= ADJ_SLOT_VALUES[0] && adj <= ADJ_SLOT_VALUES[ADJ_SLOT_VALUES.length - 1]) {
+ // Conduct a binary search, in most of the cases it'll get a hit.
+ final int index = Arrays.binarySearch(ADJ_SLOT_VALUES, adj);
+ if (index >= 0) {
+ return index;
+ }
+ // If not found, the returned index above should be (-(insertion point) - 1),
+ // let's return the first slot that's less than the adj value.
+ return -(index + 1) - 1;
+ }
+ return ADJ_SLOT_VALUES.length - 1;
+ }
+
+ static final int[] PROC_STATE_SLOTS = new int[] {
+ PROCESS_STATE_PERSISTENT, // 0
+ PROCESS_STATE_PERSISTENT_UI,
+ PROCESS_STATE_TOP,
+ PROCESS_STATE_BOUND_TOP,
+ PROCESS_STATE_FOREGROUND_SERVICE,
+ PROCESS_STATE_BOUND_FOREGROUND_SERVICE,
+ PROCESS_STATE_IMPORTANT_FOREGROUND,
+ PROCESS_STATE_IMPORTANT_BACKGROUND,
+ PROCESS_STATE_TRANSIENT_BACKGROUND,
+ PROCESS_STATE_BACKUP,
+ PROCESS_STATE_SERVICE,
+ PROCESS_STATE_RECEIVER,
+ PROCESS_STATE_TOP_SLEEPING,
+ PROCESS_STATE_HEAVY_WEIGHT,
+ PROCESS_STATE_HOME,
+ PROCESS_STATE_LAST_ACTIVITY,
+ PROCESS_STATE_CACHED_ACTIVITY,
+ PROCESS_STATE_CACHED_ACTIVITY_CLIENT,
+ PROCESS_STATE_CACHED_RECENT,
+ PROCESS_STATE_CACHED_EMPTY,
+ PROCESS_STATE_UNKNOWN, // -1
+ };
+
+ static int processStateToSlot(@ActivityManager.ProcessState int state) {
+ if (state >= PROCESS_STATE_PERSISTENT && state <= PROCESS_STATE_CACHED_EMPTY) {
+ return state;
+ }
+ return PROC_STATE_SLOTS.length - 1;
+ }
+
+ /**
+ * A container node in the {@link LinkedProcessRecordList},
+ * holding the references to {@link ProcessRecord}.
+ */
+ static class ProcessRecordNode {
+ static final int NODE_TYPE_PROC_STATE = 0;
+ static final int NODE_TYPE_ADJ = 1;
+
+ @IntDef(prefix = { "NODE_TYPE_" }, value = {
+ NODE_TYPE_PROC_STATE,
+ NODE_TYPE_ADJ,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface NodeType {}
+
+ static final int NUM_NODE_TYPE = NODE_TYPE_ADJ + 1;
+
+ @Nullable ProcessRecordNode mPrev;
+ @Nullable ProcessRecordNode mNext;
+ final @Nullable ProcessRecord mApp;
+
+ ProcessRecordNode(@Nullable ProcessRecord app) {
+ mApp = app;
+ }
+
+ void unlink() {
+ if (mPrev != null) {
+ mPrev.mNext = mNext;
+ }
+ if (mNext != null) {
+ mNext.mPrev = mPrev;
+ }
+ mPrev = mNext = null;
+ }
+
+ boolean isLinked() {
+ return mPrev != null && mNext != null;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("ProcessRecordNode{");
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(' ');
+ sb.append(mApp);
+ sb.append(' ');
+ sb.append(mApp != null ? mApp.mState.getCurProcState() : PROCESS_STATE_UNKNOWN);
+ sb.append(' ');
+ sb.append(mApp != null ? mApp.mState.getCurAdj() : UNKNOWN_ADJ);
+ sb.append(' ');
+ sb.append(Integer.toHexString(System.identityHashCode(mPrev)));
+ sb.append(' ');
+ sb.append(Integer.toHexString(System.identityHashCode(mNext)));
+ sb.append('}');
+ return sb.toString();
+ }
+ }
+
+ private class ProcessRecordNodes {
+ private final @ProcessRecordNode.NodeType int mType;
+
+ private final LinkedProcessRecordList[] mProcessRecordNodes;
+ // The last node besides the tail.
+ private final ProcessRecordNode[] mLastNode;
+
+ ProcessRecordNodes(@ProcessRecordNode.NodeType int type, int size) {
+ mType = type;
+ mProcessRecordNodes = new LinkedProcessRecordList[size];
+ for (int i = 0; i < size; i++) {
+ mProcessRecordNodes[i] = new LinkedProcessRecordList(type);
+ }
+ mLastNode = new ProcessRecordNode[size];
+ }
+
+ int size() {
+ return mProcessRecordNodes.length;
+ }
+
+ @VisibleForTesting
+ void reset() {
+ for (int i = 0; i < mProcessRecordNodes.length; i++) {
+ mProcessRecordNodes[i].reset();
+ mLastNode[i] = null;
+ }
+ }
+
+ void resetLastNodes() {
+ for (int i = 0; i < mProcessRecordNodes.length; i++) {
+ mLastNode[i] = mProcessRecordNodes[i].getLastNodeBeforeTail();
+ }
+ }
+
+ void setLastNodeToHead(int slot) {
+ mLastNode[slot] = mProcessRecordNodes[slot].HEAD;
+ }
+
+ void forEachNewNode(int slot, @NonNull Consumer<OomAdjusterArgs> callback) {
+ ProcessRecordNode node = mLastNode[slot].mNext;
+ final ProcessRecordNode tail = mProcessRecordNodes[slot].TAIL;
+ while (node != tail) {
+ mTmpOomAdjusterArgs.mApp = node.mApp;
+ // Save the next before calling callback, since that may change the node.mNext.
+ final ProcessRecordNode next = node.mNext;
+ callback.accept(mTmpOomAdjusterArgs);
+ // There are couple of cases:
+ // a) The current node is moved to another slot
+ // - for this case, we'd need to keep using the "next" node.
+ // b) There are one or more new nodes being appended to this slot
+ // - for this case, we'd need to make sure we scan the new node too.
+ // Based on the assumption that case a) is only possible with
+ // the computeInitialOomAdjLSP(), where the movings are for single node only,
+ // we may safely assume that, if the "next" used to be the "tail" here, and it's
+ // now a new tail somewhere else, that's case a); otherwise, it's case b);
+ node = next == tail && node.mNext != null && node.mNext.mNext != null
+ ? node.mNext : next;
+ }
+ }
+
+ int getNumberOfSlots() {
+ return mProcessRecordNodes.length;
+ }
+
+ void moveAppTo(@NonNull ProcessRecord app, int prevSlot, int newSlot) {
+ final ProcessRecordNode node = app.mLinkedNodes[mType];
+ if (prevSlot != ADJ_SLOT_INVALID) {
+ if (mLastNode[prevSlot] == node) {
+ mLastNode[prevSlot] = node.mPrev;
+ }
+ node.unlink();
+ }
+ mProcessRecordNodes[newSlot].append(node);
+ }
+
+ void moveAllNodesTo(int fromSlot, int toSlot) {
+ final LinkedProcessRecordList fromList = mProcessRecordNodes[fromSlot];
+ final LinkedProcessRecordList toList = mProcessRecordNodes[toSlot];
+ if (fromSlot != toSlot && fromList.HEAD.mNext != fromList.TAIL) {
+ fromList.moveTo(toList);
+ mLastNode[fromSlot] = fromList.getLastNodeBeforeTail();
+ }
+ }
+
+ void moveAppToTail(ProcessRecord app) {
+ final ProcessRecordNode node = app.mLinkedNodes[mType];
+ int slot;
+ switch (mType) {
+ case ProcessRecordNode.NODE_TYPE_PROC_STATE:
+ slot = processStateToSlot(app.mState.getCurProcState());
+ if (mLastNode[slot] == node) {
+ mLastNode[slot] = node.mPrev;
+ }
+ mProcessRecordNodes[slot].moveNodeToTail(node);
+ break;
+ case ProcessRecordNode.NODE_TYPE_ADJ:
+ slot = adjToSlot(app.mState.getCurRawAdj());
+ if (mLastNode[slot] == node) {
+ mLastNode[slot] = node.mPrev;
+ }
+ mProcessRecordNodes[slot].moveNodeToTail(node);
+ break;
+ default:
+ return;
+ }
+
+ }
+
+ void reset(int slot) {
+ mProcessRecordNodes[slot].reset();
+ }
+
+ void unlink(@NonNull ProcessRecord app) {
+ final ProcessRecordNode node = app.mLinkedNodes[mType];
+ final int slot = getCurrentSlot(app);
+ if (slot != ADJ_SLOT_INVALID) {
+ if (mLastNode[slot] == node) {
+ mLastNode[slot] = node.mPrev;
+ }
+ }
+ node.unlink();
+ }
+
+ void append(@NonNull ProcessRecord app) {
+ append(app, getCurrentSlot(app));
+ }
+
+ void append(@NonNull ProcessRecord app, int targetSlot) {
+ final ProcessRecordNode node = app.mLinkedNodes[mType];
+ mProcessRecordNodes[targetSlot].append(node);
+ }
+
+ private int getCurrentSlot(@NonNull ProcessRecord app) {
+ switch (mType) {
+ case ProcessRecordNode.NODE_TYPE_PROC_STATE:
+ return processStateToSlot(app.mState.getCurProcState());
+ case ProcessRecordNode.NODE_TYPE_ADJ:
+ return adjToSlot(app.mState.getCurRawAdj());
+ }
+ return ADJ_SLOT_INVALID;
+ }
+
+ String toString(int slot, int logUid) {
+ return "lastNode=" + mLastNode[slot] + " " + mProcessRecordNodes[slot].toString(logUid);
+ }
+
+ /**
+ * A simple version of {@link java.util.LinkedList}, as here we don't allocate new node
+ * while adding an object to it.
+ */
+ private static class LinkedProcessRecordList {
+ // Sentinel head/tail, to make bookkeeping work easier.
+ final ProcessRecordNode HEAD = new ProcessRecordNode(null);
+ final ProcessRecordNode TAIL = new ProcessRecordNode(null);
+ final @ProcessRecordNode.NodeType int mNodeType;
+
+ LinkedProcessRecordList(@ProcessRecordNode.NodeType int nodeType) {
+ HEAD.mNext = TAIL;
+ TAIL.mPrev = HEAD;
+ mNodeType = nodeType;
+ }
+
+ void append(@NonNull ProcessRecordNode node) {
+ node.mNext = TAIL;
+ node.mPrev = TAIL.mPrev;
+ TAIL.mPrev.mNext = node;
+ TAIL.mPrev = node;
+ }
+
+ void moveTo(@NonNull LinkedProcessRecordList toList) {
+ if (HEAD.mNext != TAIL) {
+ toList.TAIL.mPrev.mNext = HEAD.mNext;
+ HEAD.mNext.mPrev = toList.TAIL.mPrev;
+ toList.TAIL.mPrev = TAIL.mPrev;
+ TAIL.mPrev.mNext = toList.TAIL;
+ HEAD.mNext = TAIL;
+ TAIL.mPrev = HEAD;
+ }
+ }
+
+ void moveNodeToTail(@NonNull ProcessRecordNode node) {
+ node.unlink();
+ append(node);
+ }
+
+ @NonNull ProcessRecordNode getLastNodeBeforeTail() {
+ return TAIL.mPrev;
+ }
+
+ @VisibleForTesting
+ void reset() {
+ HEAD.mNext = TAIL;
+ TAIL.mPrev = HEAD;
+ }
+
+ String toString(int logUid) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("LinkedProcessRecordList{");
+ sb.append(HEAD);
+ sb.append(' ');
+ sb.append(TAIL);
+ sb.append('[');
+ ProcessRecordNode node = HEAD.mNext;
+ while (node != TAIL) {
+ if (node.mApp != null && node.mApp.uid == logUid) {
+ sb.append(node);
+ sb.append(',');
+ }
+ node = node.mNext;
+ }
+ sb.append(']');
+ sb.append('}');
+ return sb.toString();
+ }
+ }
+ }
+
+ /**
+ * A data class for holding the parameters in computing oom adj.
+ */
+ private class OomAdjusterArgs {
+ ProcessRecord mApp;
+ ProcessRecord mTopApp;
+ long mNow;
+ int mCachedAdj;
+ @OomAdjReason int mOomAdjReason;
+ @NonNull ActiveUids mUids;
+ boolean mFullUpdate;
+
+ void update(ProcessRecord topApp, long now, int cachedAdj,
+ @OomAdjReason int oomAdjReason, @NonNull ActiveUids uids, boolean fullUpdate) {
+ mTopApp = topApp;
+ mNow = now;
+ mCachedAdj = cachedAdj;
+ mOomAdjReason = oomAdjReason;
+ mUids = uids;
+ mFullUpdate = fullUpdate;
+ }
+ }
+
+ OomAdjusterModernImpl(ActivityManagerService service, ProcessList processList,
+ ActiveUids activeUids) {
+ this(service, processList, activeUids, createAdjusterThread());
+ }
+
+ OomAdjusterModernImpl(ActivityManagerService service, ProcessList processList,
+ ActiveUids activeUids, ServiceThread adjusterThread) {
+ super(service, processList, activeUids, adjusterThread);
+ }
+
+ private final ProcessRecordNodes mProcessRecordProcStateNodes = new ProcessRecordNodes(
+ ProcessRecordNode.NODE_TYPE_PROC_STATE, PROC_STATE_SLOTS.length);
+ private final ProcessRecordNodes mProcessRecordAdjNodes = new ProcessRecordNodes(
+ ProcessRecordNode.NODE_TYPE_ADJ, ADJ_SLOT_VALUES.length);
+ private final OomAdjusterArgs mTmpOomAdjusterArgs = new OomAdjusterArgs();
+
+ void linkProcessRecordToList(@NonNull ProcessRecord app) {
+ mProcessRecordProcStateNodes.append(app);
+ mProcessRecordAdjNodes.append(app);
+ }
+
+ void unlinkProcessRecordFromList(@NonNull ProcessRecord app) {
+ mProcessRecordProcStateNodes.unlink(app);
+ mProcessRecordAdjNodes.unlink(app);
+ }
+
+ @Override
+ @VisibleForTesting
+ void resetInternal() {
+ mProcessRecordProcStateNodes.reset();
+ mProcessRecordAdjNodes.reset();
+ }
+
+ @GuardedBy("mService")
+ @Override
+ void onProcessBeginLocked(@NonNull ProcessRecord app) {
+ // Check one type should be good enough.
+ if (app.mLinkedNodes[ProcessRecordNode.NODE_TYPE_PROC_STATE] == null) {
+ for (int i = 0; i < app.mLinkedNodes.length; i++) {
+ app.mLinkedNodes[i] = new ProcessRecordNode(app);
+ }
+ }
+ if (!app.mLinkedNodes[ProcessRecordNode.NODE_TYPE_PROC_STATE].isLinked()) {
+ linkProcessRecordToList(app);
+ }
+ }
+
+ @GuardedBy("mService")
+ @Override
+ void onProcessEndLocked(@NonNull ProcessRecord app) {
+ if (app.mLinkedNodes[ProcessRecordNode.NODE_TYPE_PROC_STATE] != null
+ && app.mLinkedNodes[ProcessRecordNode.NODE_TYPE_PROC_STATE].isLinked()) {
+ unlinkProcessRecordFromList(app);
+ }
+ }
+
+ @GuardedBy("mService")
+ @Override
+ void onProcessStateChanged(@NonNull ProcessRecord app, int prevProcState) {
+ updateProcStateSlotIfNecessary(app, prevProcState);
+ }
+
+ @GuardedBy("mService")
+ void onProcessOomAdjChanged(@NonNull ProcessRecord app, int prevAdj) {
+ updateAdjSlotIfNecessary(app, prevAdj);
+ }
+
+ @GuardedBy("mService")
+ @Override
+ protected int getInitialAdj(@NonNull ProcessRecord app) {
+ return UNKNOWN_ADJ;
+ }
+
+ @GuardedBy("mService")
+ @Override
+ protected int getInitialProcState(@NonNull ProcessRecord app) {
+ return PROCESS_STATE_UNKNOWN;
+ }
+
+ @GuardedBy("mService")
+ @Override
+ protected int getInitialCapability(@NonNull ProcessRecord app) {
+ return 0;
+ }
+
+ @GuardedBy("mService")
+ @Override
+ protected boolean getInitialIsCurBoundByNonBgRestrictedApp(@NonNull ProcessRecord app) {
+ return false;
+ }
+
+ private void updateAdjSlotIfNecessary(ProcessRecord app, int prevRawAdj) {
+ if (app.mState.getCurRawAdj() != prevRawAdj) {
+ final int slot = adjToSlot(app.mState.getCurRawAdj());
+ final int prevSlot = adjToSlot(prevRawAdj);
+ if (slot != prevSlot && slot != ADJ_SLOT_INVALID) {
+ mProcessRecordAdjNodes.moveAppTo(app, prevSlot, slot);
+ }
+ }
+ }
+
+ private void updateProcStateSlotIfNecessary(ProcessRecord app, int prevProcState) {
+ if (app.mState.getCurProcState() != prevProcState) {
+ final int slot = processStateToSlot(app.mState.getCurProcState());
+ final int prevSlot = processStateToSlot(prevProcState);
+ if (slot != prevSlot) {
+ mProcessRecordProcStateNodes.moveAppTo(app, prevSlot, slot);
+ }
+ }
+ }
+
+ @Override
+ protected boolean performUpdateOomAdjLSP(ProcessRecord app, @OomAdjReason int oomAdjReason) {
+ final ProcessRecord topApp = mService.getTopApp();
+
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason));
+ mService.mOomAdjProfiler.oomAdjStarted();
+ mAdjSeq++;
+
+ final ProcessStateRecord state = app.mState;
+ final int oldAdj = state.getCurRawAdj();
+ final int cachedAdj = oldAdj >= CACHED_APP_MIN_ADJ
+ ? oldAdj : UNKNOWN_ADJ;
+
+ final ActiveUids uids = mTmpUidRecords;
+ final ArraySet<ProcessRecord> targetProcesses = mTmpProcessSet;
+ final ArrayList<ProcessRecord> reachableProcesses = mTmpProcessList;
+ final long now = SystemClock.uptimeMillis();
+ final long nowElapsed = SystemClock.elapsedRealtime();
+
+ uids.clear();
+ targetProcesses.clear();
+ targetProcesses.add(app);
+ reachableProcesses.clear();
+
+ // Find out all reachable processes from this app.
+ collectReachableProcessesLocked(targetProcesses, reachableProcesses, uids);
+
+ // Copy all of the reachable processes into the target process set.
+ targetProcesses.addAll(reachableProcesses);
+ reachableProcesses.clear();
+
+ final boolean result = performNewUpdateOomAdjLSP(oomAdjReason,
+ topApp, targetProcesses, uids, false, now, cachedAdj);
+
+ reachableProcesses.addAll(targetProcesses);
+ assignCachedAdjIfNecessary(reachableProcesses);
+ for (int i = uids.size() - 1; i >= 0; i--) {
+ final UidRecord uidRec = uids.valueAt(i);
+ uidRec.forEachProcess(this::updateAppUidRecIfNecessaryLSP);
+ }
+ updateUidsLSP(uids, nowElapsed);
+ for (int i = 0, size = targetProcesses.size(); i < size; i++) {
+ applyOomAdjLSP(targetProcesses.valueAt(i), false, now, nowElapsed, oomAdjReason);
+ }
+ targetProcesses.clear();
+ reachableProcesses.clear();
+
+ mService.mOomAdjProfiler.oomAdjEnded();
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ return result;
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ @Override
+ protected void updateOomAdjInnerLSP(@OomAdjReason int oomAdjReason, final ProcessRecord topApp,
+ ArrayList<ProcessRecord> processes, ActiveUids uids, boolean potentialCycles,
+ boolean startProfiling) {
+ final boolean fullUpdate = processes == null;
+ final ArrayList<ProcessRecord> activeProcesses = fullUpdate
+ ? mProcessList.getLruProcessesLOSP() : processes;
+ ActiveUids activeUids = uids;
+ if (activeUids == null) {
+ final int numUids = mActiveUids.size();
+ activeUids = mTmpUidRecords;
+ activeUids.clear();
+ for (int i = 0; i < numUids; i++) {
+ UidRecord uidRec = mActiveUids.valueAt(i);
+ activeUids.put(uidRec.getUid(), uidRec);
+ }
+ }
+
+ if (startProfiling) {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason));
+ mService.mOomAdjProfiler.oomAdjStarted();
+ }
+ final long now = SystemClock.uptimeMillis();
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ final long oldTime = now - mConstants.mMaxEmptyTimeMillis;
+ final int numProc = activeProcesses.size();
+
+ mAdjSeq++;
+ if (fullUpdate) {
+ mNewNumServiceProcs = 0;
+ mNewNumAServiceProcs = 0;
+ }
+
+ final ArraySet<ProcessRecord> targetProcesses = mTmpProcessSet;
+ targetProcesses.clear();
+ if (!fullUpdate) {
+ targetProcesses.addAll(activeProcesses);
+ }
+
+ performNewUpdateOomAdjLSP(oomAdjReason, topApp, targetProcesses, activeUids,
+ fullUpdate, now, UNKNOWN_ADJ);
+
+ if (fullUpdate) {
+ assignCachedAdjIfNecessary(mProcessList.getLruProcessesLOSP());
+ postUpdateOomAdjInnerLSP(oomAdjReason, activeUids, now, nowElapsed, oldTime);
+ } else {
+ activeProcesses.clear();
+ activeProcesses.addAll(targetProcesses);
+ assignCachedAdjIfNecessary(activeProcesses);
+
+ for (int i = activeUids.size() - 1; i >= 0; i--) {
+ final UidRecord uidRec = activeUids.valueAt(i);
+ uidRec.forEachProcess(this::updateAppUidRecIfNecessaryLSP);
+ }
+ updateUidsLSP(activeUids, nowElapsed);
+
+ for (int i = 0, size = targetProcesses.size(); i < size; i++) {
+ applyOomAdjLSP(targetProcesses.valueAt(i), false, now, nowElapsed, oomAdjReason);
+ }
+
+ activeProcesses.clear();
+ }
+ targetProcesses.clear();
+
+ if (startProfiling) {
+ mService.mOomAdjProfiler.oomAdjEnded();
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
+ return;
+ }
+
+ /**
+ * Perform the oom adj update on the given {@code targetProcesses}.
+ *
+ * <p>Note: The expectation to the given {@code targetProcesses} is, the caller
+ * must have called {@link collectReachableProcessesLocked} on it.
+ */
+ private boolean performNewUpdateOomAdjLSP(@OomAdjReason int oomAdjReason,
+ ProcessRecord topApp, ArraySet<ProcessRecord> targetProcesses, ActiveUids uids,
+ boolean fullUpdate, long now, int cachedAdj) {
+
+ final ArrayList<ProcessRecord> clientProcesses = mTmpProcessList2;
+ clientProcesses.clear();
+
+ // We'll need to collect the upstream processes of the target apps here, because those
+ // processes would potentially impact the procstate/adj via bindings.
+ if (!fullUpdate) {
+ final boolean containsCycle = collectReversedReachableProcessesLocked(targetProcesses,
+ clientProcesses);
+
+ // If any of its upstream processes are in a cycle,
+ // move them into the candidate targets.
+ if (containsCycle) {
+ // Add all client apps to the target process list.
+ for (int i = 0, size = clientProcesses.size(); i < size; i++) {
+ final ProcessRecord client = clientProcesses.get(i);
+ final UidRecord uidRec = client.getUidRecord();
+ targetProcesses.add(client);
+ if (uidRec != null) {
+ uids.put(uidRec.getUid(), uidRec);
+ }
+ }
+ clientProcesses.clear();
+ }
+ for (int i = 0, size = targetProcesses.size(); i < size; i++) {
+ final ProcessRecord app = targetProcesses.valueAt(i);
+ app.mState.resetCachedInfo();
+ final UidRecord uidRec = app.getUidRecord();
+ if (uidRec != null) {
+ if (DEBUG_UID_OBSERVERS) {
+ Slog.i(TAG_UID_OBSERVERS, "Starting update of " + uidRec);
+ }
+ uidRec.reset();
+ }
+ }
+ } else {
+ final ArrayList<ProcessRecord> lru = mProcessList.getLruProcessesLOSP();
+ for (int i = 0, size = lru.size(); i < size; i++) {
+ final ProcessRecord app = lru.get(i);
+ app.mState.resetCachedInfo();
+ final UidRecord uidRec = app.getUidRecord();
+ if (uidRec != null) {
+ if (DEBUG_UID_OBSERVERS) {
+ Slog.i(TAG_UID_OBSERVERS, "Starting update of " + uidRec);
+ }
+ uidRec.reset();
+ }
+ }
+ }
+
+ updateNewOomAdjInnerLSP(oomAdjReason, topApp, targetProcesses, clientProcesses, uids,
+ cachedAdj, now, fullUpdate);
+
+ clientProcesses.clear();
+
+ return true;
+ }
+
+ /**
+ * Collect the reversed reachable processes from the given {@code apps}, the result will be
+ * returned in the given {@code processes}, which will <em>NOT</em> include the processes from
+ * the given {@code apps}.
+ */
+ @GuardedBy("mService")
+ private boolean collectReversedReachableProcessesLocked(ArraySet<ProcessRecord> apps,
+ ArrayList<ProcessRecord> clientProcesses) {
+ final ArrayDeque<ProcessRecord> queue = mTmpQueue;
+ queue.clear();
+ clientProcesses.clear();
+ for (int i = 0, size = apps.size(); i < size; i++) {
+ final ProcessRecord app = apps.valueAt(i);
+ app.mState.setReachable(true);
+ app.mState.setReversedReachable(true);
+ queue.offer(app);
+ }
+
+ // Track if any of them reachables could include a cycle
+ boolean containsCycle = false;
+
+ // Scan upstreams of the process record
+ for (ProcessRecord pr = queue.poll(); pr != null; pr = queue.poll()) {
+ if (!pr.mState.isReachable()) {
+ // If not in the given initial set of apps, add it.
+ clientProcesses.add(pr);
+ }
+ final ProcessServiceRecord psr = pr.mServices;
+ for (int i = psr.numberOfRunningServices() - 1; i >= 0; i--) {
+ final ServiceRecord s = psr.getRunningServiceAt(i);
+ final ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections =
+ s.getConnections();
+ for (int j = serviceConnections.size() - 1; j >= 0; j--) {
+ final ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(j);
+ for (int k = clist.size() - 1; k >= 0; k--) {
+ final ConnectionRecord cr = clist.get(k);
+ final ProcessRecord client = cr.binding.client;
+ containsCycle |= client.mState.isReversedReachable();
+ if (client.mState.isReversedReachable()) {
+ continue;
+ }
+ queue.offer(client);
+ client.mState.setReversedReachable(true);
+ }
+ }
+ }
+ final ProcessProviderRecord ppr = pr.mProviders;
+ for (int i = ppr.numberOfProviders() - 1; i >= 0; i--) {
+ final ContentProviderRecord cpr = ppr.getProviderAt(i);
+ for (int j = cpr.connections.size() - 1; j >= 0; j--) {
+ final ContentProviderConnection conn = cpr.connections.get(j);
+ final ProcessRecord client = conn.client;
+ containsCycle |= client.mState.isReversedReachable();
+ if (client.mState.isReversedReachable()) {
+ continue;
+ }
+ queue.offer(client);
+ client.mState.setReversedReachable(true);
+ }
+ }
+ // If this process is a sandbox itself, also add the app on whose behalf
+ // its running
+ if (pr.isSdkSandbox) {
+ for (int is = psr.numberOfRunningServices() - 1; is >= 0; is--) {
+ ServiceRecord s = psr.getRunningServiceAt(is);
+ ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections =
+ s.getConnections();
+ for (int conni = serviceConnections.size() - 1; conni >= 0; conni--) {
+ ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(conni);
+ for (int i = clist.size() - 1; i >= 0; i--) {
+ ConnectionRecord cr = clist.get(i);
+ ProcessRecord attributedApp = cr.binding.attributedClient;
+ if (attributedApp == null || attributedApp == pr) {
+ continue;
+ }
+ containsCycle |= attributedApp.mState.isReversedReachable();
+ if (attributedApp.mState.isReversedReachable()) {
+ continue;
+ }
+ queue.offer(attributedApp);
+ attributedApp.mState.setReversedReachable(true);
+ }
+ }
+ }
+ }
+ }
+
+ // Reset the temporary bits.
+ for (int i = clientProcesses.size() - 1; i >= 0; i--) {
+ clientProcesses.get(i).mState.setReversedReachable(false);
+ }
+ for (int i = 0, size = apps.size(); i < size; i++) {
+ final ProcessRecord app = apps.valueAt(i);
+ app.mState.setReachable(false);
+ app.mState.setReversedReachable(false);
+ }
+ return containsCycle;
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ private void updateNewOomAdjInnerLSP(@OomAdjReason int oomAdjReason, final ProcessRecord topApp,
+ ArraySet<ProcessRecord> targetProcesses, ArrayList<ProcessRecord> clientProcesses,
+ ActiveUids uids, int cachedAdj, long now, boolean fullUpdate) {
+ mTmpOomAdjusterArgs.update(topApp, now, cachedAdj, oomAdjReason, uids, fullUpdate);
+
+ mProcessRecordProcStateNodes.resetLastNodes();
+ mProcessRecordAdjNodes.resetLastNodes();
+
+ final int procStateTarget = mProcessRecordProcStateNodes.size() - 1;
+ final int adjTarget = mProcessRecordAdjNodes.size() - 1;
+
+ final int appUid = !fullUpdate && targetProcesses.size() > 0
+ ? targetProcesses.valueAt(0).uid : -1;
+ final int logUid = mService.mCurOomAdjUid;
+
+ mAdjSeq++;
+ // All apps to be updated will be moved to the lowest slot.
+ if (fullUpdate) {
+ // Move all the process record node to the lowest slot, we'll do recomputation on all of
+ // them. Use the processes from the lru list, because the scanning order matters here.
+ final ArrayList<ProcessRecord> lruList = mProcessList.getLruProcessesLOSP();
+ for (int i = procStateTarget; i >= 0; i--) {
+ mProcessRecordProcStateNodes.reset(i);
+ // Force the last node to the head since we'll recompute all of them.
+ mProcessRecordProcStateNodes.setLastNodeToHead(i);
+ }
+ // enqueue the targets in the reverse order of the lru list.
+ for (int i = lruList.size() - 1; i >= 0; i--) {
+ mProcessRecordProcStateNodes.append(lruList.get(i), procStateTarget);
+ }
+ // Do the same to the adj nodes.
+ for (int i = adjTarget; i >= 0; i--) {
+ mProcessRecordAdjNodes.reset(i);
+ // Force the last node to the head since we'll recompute all of them.
+ mProcessRecordAdjNodes.setLastNodeToHead(i);
+ }
+ for (int i = lruList.size() - 1; i >= 0; i--) {
+ mProcessRecordAdjNodes.append(lruList.get(i), adjTarget);
+ }
+ } else {
+ // Move the target processes to the lowest slot.
+ for (int i = 0, size = targetProcesses.size(); i < size; i++) {
+ final ProcessRecord app = targetProcesses.valueAt(i);
+ final int procStateSlot = processStateToSlot(app.mState.getCurProcState());
+ final int adjSlot = adjToSlot(app.mState.getCurRawAdj());
+ mProcessRecordProcStateNodes.moveAppTo(app, procStateSlot, procStateTarget);
+ mProcessRecordAdjNodes.moveAppTo(app, adjSlot, adjTarget);
+ }
+ // Move the "lastNode" to head to make sure we scan all nodes in this slot.
+ mProcessRecordProcStateNodes.setLastNodeToHead(procStateTarget);
+ mProcessRecordAdjNodes.setLastNodeToHead(adjTarget);
+ }
+
+ // All apps to be updated have been moved to the lowest slot.
+ // Do an initial pass of the computation.
+ mProcessRecordProcStateNodes.forEachNewNode(mProcessRecordProcStateNodes.size() - 1,
+ this::computeInitialOomAdjLSP);
+
+ if (!fullUpdate) {
+ // We didn't update the client processes with the computeInitialOomAdjLSP
+ // because they don't need to do so. But they'll be playing vital roles in
+ // computing the bindings. So include them into the scan list below.
+ for (int i = 0, size = clientProcesses.size(); i < size; i++) {
+ mProcessRecordProcStateNodes.moveAppToTail(clientProcesses.get(i));
+ }
+ // We don't update the adj list since we're resetting it below.
+ }
+
+ // Now nodes are set into their slots, without facting in the bindings.
+ // The nodes between the `lastNode` pointer and the TAIL should be the new nodes.
+ //
+ // The whole rationale here is that, the bindings from client to host app, won't elevate
+ // the host app's procstate/adj higher than the client app's state (BIND_ABOVE_CLIENT
+ // is a special case here, but client app's raw adj is still no less than the host app's).
+ // Therefore, starting from the top to the bottom, for each slot, scan all of the new nodes,
+ // check its bindings, elevate its host app's slot if necessary.
+ //
+ // We'd have to do this in two passes: 1) scan procstate node list; 2) scan adj node list.
+ // Because the procstate and adj are not always in sync - there are cases where
+ // the processes with lower proc state could be getting a higher oom adj score.
+ // And because of this, the procstate and adj node lists are basically two priority heaps.
+ //
+ // As the 2nd pass with the adj node lists potentially includes a significant amount of
+ // duplicated scans as the 1st pass has done, we'll reset the last node pointers for
+ // the adj node list before the 1st pass; so during the 1st pass, if any app's adj slot
+ // gets bumped, we'll only scan those in 2nd pass.
+
+ mProcessRecordAdjNodes.resetLastNodes();
+
+ // 1st pass, scan each slot in the procstate node list.
+ for (int i = 0, end = mProcessRecordProcStateNodes.size() - 1; i < end; i++) {
+ mProcessRecordProcStateNodes.forEachNewNode(i, this::computeHostOomAdjLSP);
+ }
+
+ // 2nd pass, scan each slot in the adj node list.
+ for (int i = 0, end = mProcessRecordAdjNodes.size() - 1; i < end; i++) {
+ mProcessRecordAdjNodes.forEachNewNode(i, this::computeHostOomAdjLSP);
+ }
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ private void computeInitialOomAdjLSP(OomAdjusterArgs args) {
+ final ProcessRecord app = args.mApp;
+ final int cachedAdj = args.mCachedAdj;
+ final ProcessRecord topApp = args.mTopApp;
+ final long now = args.mNow;
+ final int oomAdjReason = args.mOomAdjReason;
+ final ActiveUids uids = args.mUids;
+ final boolean fullUpdate = args.mFullUpdate;
+
+ if (DEBUG_OOM_ADJ) {
+ Slog.i(TAG, "OOM ADJ initial args app=" + app
+ + " cachedAdj=" + cachedAdj
+ + " topApp=" + topApp
+ + " now=" + now
+ + " oomAdjReason=" + oomAdjReasonToString(oomAdjReason)
+ + " fullUpdate=" + fullUpdate);
+ }
+
+ if (uids != null) {
+ final UidRecord uidRec = app.getUidRecord();
+
+ if (uidRec != null) {
+ uids.put(uidRec.getUid(), uidRec);
+ }
+ }
+
+ computeOomAdjLSP(app, cachedAdj, topApp, fullUpdate, now, false, false, oomAdjReason,
+ false);
+ }
+
+ /**
+ * @return The proposed change to the schedGroup.
+ */
+ @GuardedBy({"mService", "mProcLock"})
+ @Override
+ protected int setIntermediateAdjLSP(ProcessRecord app, int adj, int prevRawAppAdj,
+ int schedGroup) {
+ schedGroup = super.setIntermediateAdjLSP(app, adj, prevRawAppAdj, schedGroup);
+
+ updateAdjSlotIfNecessary(app, prevRawAppAdj);
+
+ return schedGroup;
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ @Override
+ protected void setIntermediateProcStateLSP(ProcessRecord app, int procState,
+ int prevProcState) {
+ super.setIntermediateProcStateLSP(app, procState, prevProcState);
+
+ updateProcStateSlotIfNecessary(app, prevProcState);
+ }
+
+ @GuardedBy({"mService", "mProcLock"})
+ private void computeHostOomAdjLSP(OomAdjusterArgs args) {
+ final ProcessRecord app = args.mApp;
+ final int cachedAdj = args.mCachedAdj;
+ final ProcessRecord topApp = args.mTopApp;
+ final long now = args.mNow;
+ final @OomAdjReason int oomAdjReason = args.mOomAdjReason;
+ final boolean fullUpdate = args.mFullUpdate;
+ final ActiveUids uids = args.mUids;
+
+ final ProcessServiceRecord psr = app.mServices;
+ for (int i = psr.numberOfConnections() - 1; i >= 0; i--) {
+ ConnectionRecord cr = psr.getConnectionAt(i);
+ ProcessRecord service = cr.hasFlag(ServiceInfo.FLAG_ISOLATED_PROCESS)
+ ? cr.binding.service.isolationHostProc : cr.binding.service.app;
+ if (service == null || service == app
+ || (service.mState.getMaxAdj() >= SYSTEM_ADJ
+ && service.mState.getMaxAdj() < FOREGROUND_APP_ADJ)
+ || (service.mState.getCurAdj() <= FOREGROUND_APP_ADJ
+ && service.mState.getCurrentSchedulingGroup() > SCHED_GROUP_BACKGROUND
+ && service.mState.getCurProcState() <= PROCESS_STATE_TOP)) {
+ continue;
+ }
+
+
+ computeServiceHostOomAdjLSP(cr, service, app, now, topApp, fullUpdate, false, false,
+ oomAdjReason, cachedAdj, false);
+ }
+
+ for (int i = psr.numberOfSdkSandboxConnections() - 1; i >= 0; i--) {
+ final ConnectionRecord cr = psr.getSdkSandboxConnectionAt(i);
+ final ProcessRecord service = cr.binding.service.app;
+ if (service == null || service == app
+ || (service.mState.getMaxAdj() >= SYSTEM_ADJ
+ && service.mState.getMaxAdj() < FOREGROUND_APP_ADJ)
+ || (service.mState.getCurAdj() <= FOREGROUND_APP_ADJ
+ && service.mState.getCurrentSchedulingGroup() > SCHED_GROUP_BACKGROUND
+ && service.mState.getCurProcState() <= PROCESS_STATE_TOP)) {
+ continue;
+ }
+
+ computeServiceHostOomAdjLSP(cr, service, app, now, topApp, fullUpdate, false, false,
+ oomAdjReason, cachedAdj, false);
+ }
+
+ final ProcessProviderRecord ppr = app.mProviders;
+ for (int i = ppr.numberOfProviderConnections() - 1; i >= 0; i--) {
+ ContentProviderConnection cpc = ppr.getProviderConnectionAt(i);
+ ProcessRecord provider = cpc.provider.proc;
+ if (provider == null || provider == app
+ || (provider.mState.getMaxAdj() >= ProcessList.SYSTEM_ADJ
+ && provider.mState.getMaxAdj() < FOREGROUND_APP_ADJ)
+ || (provider.mState.getCurAdj() <= FOREGROUND_APP_ADJ
+ && provider.mState.getCurrentSchedulingGroup() > SCHED_GROUP_BACKGROUND
+ && provider.mState.getCurProcState() <= PROCESS_STATE_TOP)) {
+ continue;
+ }
+
+ computeProviderHostOomAdjLSP(cpc, provider, app, now, topApp, fullUpdate, false, false,
+ oomAdjReason, cachedAdj, false);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index f532122c10d9..e2edd8a37091 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -22,6 +22,7 @@ import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityManagerService.MY_PID;
+import static com.android.server.am.OomAdjusterModernImpl.ProcessRecordNode.NUM_NODE_TYPE;
import static java.util.Objects.requireNonNull;
@@ -63,6 +64,7 @@ import com.android.internal.app.procstats.ProcessState;
import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.os.Zygote;
import com.android.server.FgThread;
+import com.android.server.am.OomAdjusterModernImpl.ProcessRecordNode;
import com.android.server.wm.WindowProcessController;
import com.android.server.wm.WindowProcessListener;
@@ -434,6 +436,8 @@ class ProcessRecord implements WindowProcessListener {
*/
volatile boolean mSkipProcessGroupCreation;
+ final ProcessRecordNode[] mLinkedNodes = new ProcessRecordNode[NUM_NODE_TYPE];
+
void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo,
long startUptime, long startElapsedTime) {
this.mStartUid = startUid;
@@ -770,6 +774,11 @@ class ProcessRecord implements WindowProcessListener {
}
@GuardedBy("mService")
+ boolean isThreadReady() {
+ return mThread != null && !mPendingFinishAttach;
+ }
+
+ @GuardedBy("mService")
long getStartSeq() {
return mStartSeq;
}
@@ -1114,6 +1123,7 @@ class ProcessRecord implements WindowProcessListener {
mState.onCleanupApplicationRecordLSP();
mServices.onCleanupApplicationRecordLocked();
mReceivers.onCleanupApplicationRecordLocked();
+ mService.mOomAdjuster.onProcessEndLocked(this);
return mProviders.onCleanupApplicationRecordLocked(allowRestart);
}
diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java
index 7ff6d116baaf..a165e8897aa4 100644
--- a/services/core/java/com/android/server/am/ProcessServiceRecord.java
+++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java
@@ -19,6 +19,7 @@ package com.android.server.am;
import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_BOUND_SERVICE;
import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_FOREGROUND_SERVICE;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ServiceInfo;
@@ -134,6 +135,11 @@ final class ProcessServiceRecord {
private final ArraySet<ConnectionRecord> mConnections = new ArraySet<>();
/**
+ * All ConnectionRecord this process holds indirectly to SDK sandbox processes.
+ */
+ private @Nullable ArraySet<ConnectionRecord> mSdkSandboxConnections;
+
+ /**
* A set of UIDs of all bound clients.
*/
private ArraySet<Integer> mBoundClientUids = new ArraySet<>();
@@ -490,13 +496,18 @@ final class ProcessServiceRecord {
void addConnection(ConnectionRecord connection) {
mConnections.add(connection);
+ addSdkSandboxConnectionIfNecessary(connection);
}
void removeConnection(ConnectionRecord connection) {
mConnections.remove(connection);
+ removeSdkSandboxConnectionIfNecessary(connection);
}
void removeAllConnections() {
+ for (int i = 0, size = mConnections.size(); i < size; i++) {
+ removeSdkSandboxConnectionIfNecessary(mConnections.valueAt(i));
+ }
mConnections.clear();
}
@@ -508,6 +519,39 @@ final class ProcessServiceRecord {
return mConnections.size();
}
+ private void addSdkSandboxConnectionIfNecessary(ConnectionRecord connection) {
+ final ProcessRecord attributedClient = connection.binding.attributedClient;
+ if (attributedClient != null && connection.binding.service.isSdkSandbox) {
+ if (attributedClient.mServices.mSdkSandboxConnections == null) {
+ attributedClient.mServices.mSdkSandboxConnections = new ArraySet<>();
+ }
+ attributedClient.mServices.mSdkSandboxConnections.add(connection);
+ }
+ }
+
+ private void removeSdkSandboxConnectionIfNecessary(ConnectionRecord connection) {
+ final ProcessRecord attributedClient = connection.binding.attributedClient;
+ if (attributedClient != null && connection.binding.service.isSdkSandbox) {
+ if (attributedClient.mServices.mSdkSandboxConnections == null) {
+ attributedClient.mServices.mSdkSandboxConnections.remove(connection);
+ }
+ }
+ }
+
+ void removeAllSdkSandboxConnections() {
+ if (mSdkSandboxConnections != null) {
+ mSdkSandboxConnections.clear();
+ }
+ }
+
+ ConnectionRecord getSdkSandboxConnectionAt(int index) {
+ return mSdkSandboxConnections != null ? mSdkSandboxConnections.valueAt(index) : null;
+ }
+
+ int numberOfSdkSandboxConnections() {
+ return mSdkSandboxConnections != null ? mSdkSandboxConnections.size() : 0;
+ }
+
void addBoundClientUid(int clientUid, String clientPackageName, long bindFlags) {
mBoundClientUids.add(clientUid);
mApp.getWindowProcessController()
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index db341d253818..a9c388c232ed 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -378,6 +378,12 @@ final class ProcessStateRecord {
private boolean mReachable;
/**
+ * Whether or not this process is reversed reachable from given process.
+ */
+ @GuardedBy("mService")
+ private boolean mReversedReachable;
+
+ /**
* The most recent time when the last visible activity within this process became invisible.
*
* <p> It'll be set to 0 if there is never a visible activity, or Long.MAX_VALUE if there is
@@ -454,6 +460,9 @@ final class ProcessStateRecord {
@GuardedBy("mService")
private int mCachedSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
+ @GuardedBy("mService")
+ private boolean mScheduleLikeTopApp = false;
+
ProcessStateRecord(ProcessRecord app) {
mApp = app;
mService = app.mService;
@@ -614,9 +623,11 @@ final class ProcessStateRecord {
void forceProcessStateUpTo(int newState) {
if (mRepProcState > newState) {
synchronized (mProcLock) {
+ final int prevProcState = mRepProcState;
setReportedProcState(newState);
setCurProcState(newState);
setCurRawProcState(newState);
+ mService.mOomAdjuster.onProcessStateChanged(mApp, prevProcState);
}
}
}
@@ -985,6 +996,16 @@ final class ProcessStateRecord {
}
@GuardedBy("mService")
+ boolean isReversedReachable() {
+ return mReversedReachable;
+ }
+
+ @GuardedBy("mService")
+ void setReversedReachable(boolean reversedReachable) {
+ mReversedReachable = reversedReachable;
+ }
+
+ @GuardedBy("mService")
void resetCachedInfo() {
mCachedHasActivities = VALUE_INVALID;
mCachedIsHeavyWeight = VALUE_INVALID;
@@ -1134,6 +1155,16 @@ final class ProcessStateRecord {
return mCachedSchedGroup;
}
+ @GuardedBy("mService")
+ boolean shouldScheduleLikeTopApp() {
+ return mScheduleLikeTopApp;
+ }
+
+ @GuardedBy("mService")
+ void setScheduleLikeTopApp(boolean scheduleLikeTopApp) {
+ mScheduleLikeTopApp = scheduleLikeTopApp;
+ }
+
@GuardedBy(anyOf = {"mService", "mProcLock"})
public String makeAdjReason() {
if (mAdjSource != null || mAdjTarget != null) {
diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING
index 0af9b2b4c26a..575db01931e6 100644
--- a/services/core/java/com/android/server/am/TEST_MAPPING
+++ b/services/core/java/com/android/server/am/TEST_MAPPING
@@ -88,11 +88,14 @@
"file_patterns": ["Battery[^/]*\\.java", "MeasuredEnergy[^/]*\\.java"],
"name": "FrameworksServicesTests",
"options": [
- { "include-filter": "com.android.server.am.BatteryStatsServiceTest" },
- { "include-filter": "com.android.server.power.stats.BatteryStatsTests" }
+ { "include-filter": "com.android.server.am.BatteryStatsServiceTest" }
]
},
{
+ "file_patterns": ["Battery[^/]*\\.java", "MeasuredEnergy[^/]*\\.java"],
+ "name": "PowerStatsTests"
+ },
+ {
"file_patterns": ["Broadcast.*"],
"name": "FrameworksMockingServicesTests",
"options": [
@@ -111,27 +114,14 @@
]
},
{
- "name": "CtsUsageStatsTestCases",
+ "name": "CtsBRSTestCases",
"file_patterns": [
"ActivityManagerService\\.java",
"BroadcastQueue\\.java"
],
"options": [
- {
- "include-filter": "android.app.usage.cts.BroadcastResponseStatsTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.MediumTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
+ { "exclude-annotation": "androidx.test.filters.FlakyTest" },
+ { "exclude-annotation": "org.junit.Ignore" }
]
}
],
diff --git a/services/core/java/com/android/server/audio/AdiDeviceState.java b/services/core/java/com/android/server/audio/AdiDeviceState.java
index 683b3eb7a92e..247094f2f796 100644
--- a/services/core/java/com/android/server/audio/AdiDeviceState.java
+++ b/services/core/java/com/android/server/audio/AdiDeviceState.java
@@ -16,6 +16,7 @@
package com.android.server.audio;
+import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_UNKNOWN;
import static android.media.AudioSystem.DEVICE_NONE;
import static android.media.AudioSystem.isBluetoothDevice;
@@ -23,8 +24,10 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Pair;
import java.util.Objects;
@@ -41,8 +44,16 @@ import java.util.Objects;
private final int mDeviceType;
private final int mInternalDeviceType;
+
@NonNull
private final String mDeviceAddress;
+
+ /** Unique device id from internal device type and address. */
+ private final Pair<Integer, String> mDeviceId;
+
+ @AudioManager.AudioDeviceCategory
+ private int mAudioDeviceCategory = AUDIO_DEVICE_CATEGORY_UNKNOWN;
+
private boolean mSAEnabled;
private boolean mHasHeadTracker = false;
private boolean mHeadTrackerEnabled;
@@ -68,6 +79,12 @@ import java.util.Objects;
}
mDeviceAddress = isBluetoothDevice(mInternalDeviceType) ? Objects.requireNonNull(
address) : "";
+
+ mDeviceId = new Pair<>(mInternalDeviceType, mDeviceAddress);
+ }
+
+ public Pair<Integer, String> getDeviceId() {
+ return mDeviceId;
}
@AudioDeviceInfo.AudioDeviceType
@@ -109,6 +126,15 @@ import java.util.Objects;
return mHasHeadTracker;
}
+ @AudioDeviceInfo.AudioDeviceType
+ public int getAudioDeviceCategory() {
+ return mAudioDeviceCategory;
+ }
+
+ public void setAudioDeviceCategory(@AudioDeviceInfo.AudioDeviceType int audioDeviceCategory) {
+ mAudioDeviceCategory = audioDeviceCategory;
+ }
+
@Override
public boolean equals(Object obj) {
if (this == obj) {
@@ -127,20 +153,23 @@ import java.util.Objects;
&& mDeviceAddress.equals(sads.mDeviceAddress) // NonNull
&& mSAEnabled == sads.mSAEnabled
&& mHasHeadTracker == sads.mHasHeadTracker
- && mHeadTrackerEnabled == sads.mHeadTrackerEnabled;
+ && mHeadTrackerEnabled == sads.mHeadTrackerEnabled
+ && mAudioDeviceCategory == sads.mAudioDeviceCategory;
}
@Override
public int hashCode() {
return Objects.hash(mDeviceType, mInternalDeviceType, mDeviceAddress, mSAEnabled,
- mHasHeadTracker, mHeadTrackerEnabled);
+ mHasHeadTracker, mHeadTrackerEnabled, mAudioDeviceCategory);
}
@Override
public String toString() {
return "type: " + mDeviceType + "internal type: " + mInternalDeviceType
- + " addr: " + mDeviceAddress + " enabled: " + mSAEnabled
- + " HT: " + mHasHeadTracker + " HTenabled: " + mHeadTrackerEnabled;
+ + " addr: " + mDeviceAddress + " bt audio type: "
+ + AudioManager.audioDeviceCategoryToString(mAudioDeviceCategory)
+ + " enabled: " + mSAEnabled + " HT: " + mHasHeadTracker
+ + " HTenabled: " + mHeadTrackerEnabled;
}
public String toPersistableString() {
@@ -150,6 +179,7 @@ import java.util.Objects;
.append(SETTING_FIELD_SEPARATOR).append(mHasHeadTracker ? "1" : "0")
.append(SETTING_FIELD_SEPARATOR).append(mHeadTrackerEnabled ? "1" : "0")
.append(SETTING_FIELD_SEPARATOR).append(mInternalDeviceType)
+ .append(SETTING_FIELD_SEPARATOR).append(mAudioDeviceCategory)
.toString());
}
@@ -174,21 +204,27 @@ import java.util.Objects;
String[] fields = TextUtils.split(persistedString, SETTING_FIELD_SEPARATOR);
// we may have 5 fields for the legacy AdiDeviceState and 6 containing the internal
// device type
- if (fields.length != 5 && fields.length != 6) {
- // expecting all fields, fewer may mean corruption, ignore those settings
+ if (fields.length < 5 || fields.length > 7) {
+ // different number of fields may mean corruption, ignore those settings
+ // newly added fields are optional (mInternalDeviceType, mBtAudioDeviceCategory)
return null;
}
try {
final int deviceType = Integer.parseInt(fields[0]);
int internalDeviceType = -1;
- if (fields.length == 6) {
+ if (fields.length >= 6) {
internalDeviceType = Integer.parseInt(fields[5]);
}
+ int audioDeviceCategory = AUDIO_DEVICE_CATEGORY_UNKNOWN;
+ if (fields.length == 7) {
+ audioDeviceCategory = Integer.parseInt(fields[6]);
+ }
final AdiDeviceState deviceState = new AdiDeviceState(deviceType,
internalDeviceType, fields[1]);
deviceState.setHasHeadTracker(Integer.parseInt(fields[2]) == 1);
deviceState.setHasHeadTracker(Integer.parseInt(fields[3]) == 1);
deviceState.setHeadTrackerEnabled(Integer.parseInt(fields[4]) == 1);
+ deviceState.setAudioDeviceCategory(audioDeviceCategory);
return deviceState;
} catch (NumberFormatException e) {
Log.e(TAG, "unable to parse setting for AdiDeviceState: " + persistedString, e);
@@ -200,5 +236,4 @@ import java.util.Objects;
return new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT,
mDeviceType, mDeviceAddress);
}
-
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 946f01688e66..af8aa9167217 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -63,6 +63,7 @@ import com.android.server.utils.EventLogger;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
@@ -2493,13 +2494,13 @@ public class AudioDeviceBroker {
void onPersistAudioDeviceSettings() {
final String deviceSettings = mDeviceInventory.getDeviceSettings();
- Log.v(TAG, "saving audio device settings: " + deviceSettings);
+ Log.v(TAG, "saving AdiDeviceState: " + deviceSettings);
final SettingsAdapter settings = mAudioService.getSettings();
boolean res = settings.putSecureStringForUser(mAudioService.getContentResolver(),
Settings.Secure.AUDIO_DEVICE_INVENTORY,
deviceSettings, UserHandle.USER_CURRENT);
if (!res) {
- Log.e(TAG, "error saving audio device settings: " + deviceSettings);
+ Log.e(TAG, "error saving AdiDeviceState: " + deviceSettings);
}
}
@@ -2509,7 +2510,7 @@ public class AudioDeviceBroker {
String settings = settingsAdapter.getSecureStringForUser(contentResolver,
Settings.Secure.AUDIO_DEVICE_INVENTORY, UserHandle.USER_CURRENT);
if (settings == null) {
- Log.i(TAG, "reading spatial audio device settings from legacy key"
+ Log.i(TAG, "reading AdiDeviceState from legacy key"
+ Settings.Secure.SPATIAL_AUDIO_ENABLED);
// legacy string format for key SPATIAL_AUDIO_ENABLED has the same order of fields like
// the strings for key AUDIO_DEVICE_INVENTORY. This will ensure to construct valid
@@ -2517,21 +2518,21 @@ public class AudioDeviceBroker {
settings = settingsAdapter.getSecureStringForUser(contentResolver,
Settings.Secure.SPATIAL_AUDIO_ENABLED, UserHandle.USER_CURRENT);
if (settings == null) {
- Log.i(TAG, "no spatial audio device settings stored with legacy key");
+ Log.i(TAG, "no AdiDeviceState stored with legacy key");
} else if (!settings.equals("")) {
// Delete old key value and update the new key
if (!settingsAdapter.putSecureStringForUser(contentResolver,
Settings.Secure.SPATIAL_AUDIO_ENABLED,
/*value=*/"",
UserHandle.USER_CURRENT)) {
- Log.w(TAG, "cannot erase the legacy audio device settings with key "
+ Log.w(TAG, "cannot erase the legacy AdiDeviceState with key "
+ Settings.Secure.SPATIAL_AUDIO_ENABLED);
}
if (!settingsAdapter.putSecureStringForUser(contentResolver,
Settings.Secure.AUDIO_DEVICE_INVENTORY,
settings,
UserHandle.USER_CURRENT)) {
- Log.e(TAG, "error updating the new audio device settings with key "
+ Log.e(TAG, "error updating the new AdiDeviceState with key "
+ Settings.Secure.AUDIO_DEVICE_INVENTORY);
}
}
@@ -2551,19 +2552,29 @@ public class AudioDeviceBroker {
return mDeviceInventory.getDeviceSettings();
}
- List<AdiDeviceState> getImmutableDeviceInventory() {
+ Collection<AdiDeviceState> getImmutableDeviceInventory() {
return mDeviceInventory.getImmutableDeviceInventory();
}
- void addDeviceStateToInventory(AdiDeviceState deviceState) {
- mDeviceInventory.addDeviceStateToInventory(deviceState);
+ void addOrUpdateDeviceSAStateInInventory(AdiDeviceState deviceState) {
+ mDeviceInventory.addOrUpdateDeviceSAStateInInventory(deviceState);
}
+ void addOrUpdateBtAudioDeviceCategoryInInventory(AdiDeviceState deviceState) {
+ mDeviceInventory.addOrUpdateAudioDeviceCategoryInInventory(deviceState);
+ }
+
+ @Nullable
AdiDeviceState findDeviceStateForAudioDeviceAttributes(AudioDeviceAttributes ada,
int canonicalType) {
return mDeviceInventory.findDeviceStateForAudioDeviceAttributes(ada, canonicalType);
}
+ @Nullable
+ AdiDeviceState findBtDeviceStateForAddress(String address, boolean isBle) {
+ return mDeviceInventory.findBtDeviceStateForAddress(address, isBle);
+ }
+
//------------------------------------------------
// for testing purposes only
void clearDeviceInventory() {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index f5b7ecf5daf4..5a92cb464950 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -15,6 +15,8 @@
*/
package com.android.server.audio;
+import static android.media.AudioSystem.DEVICE_OUT_ALL_A2DP_SET;
+import static android.media.AudioSystem.DEVICE_OUT_ALL_BLE_SET;
import static android.media.AudioSystem.isBluetoothDevice;
import android.annotation.NonNull;
@@ -61,11 +63,13 @@ import com.google.android.collect.Sets;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Map;
+import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
@@ -90,35 +94,95 @@ public class AudioDeviceInventory {
private static final String mMetricsId = "audio.device.";
private final Object mDeviceInventoryLock = new Object();
- @GuardedBy("mDeviceCatalogLock")
- private final ArrayList<AdiDeviceState> mDeviceInventory = new ArrayList<>(0);
- List<AdiDeviceState> getImmutableDeviceInventory() {
+
+ @GuardedBy("mDeviceInventoryLock")
+ private final HashMap<Pair<Integer, String>, AdiDeviceState> mDeviceInventory = new HashMap<>();
+
+ Collection<AdiDeviceState> getImmutableDeviceInventory() {
+ synchronized (mDeviceInventoryLock) {
+ return mDeviceInventory.values();
+ }
+ }
+
+ /**
+ * Adds a new AdiDeviceState or updates the spatial audio related properties of the matching
+ * AdiDeviceState in the {@link AudioDeviceInventory#mDeviceInventory} list.
+ * @param deviceState the device to update
+ */
+ void addOrUpdateDeviceSAStateInInventory(AdiDeviceState deviceState) {
+ synchronized (mDeviceInventoryLock) {
+ mDeviceInventory.merge(deviceState.getDeviceId(), deviceState, (oldState, newState) -> {
+ oldState.setHasHeadTracker(newState.hasHeadTracker());
+ oldState.setHeadTrackerEnabled(newState.isHeadTrackerEnabled());
+ oldState.setSAEnabled(newState.isSAEnabled());
+ return oldState;
+ });
+ }
+ }
+
+ /**
+ * Adds a new AdiDeviceState or updates the audio device cateogory of the matching
+ * AdiDeviceState in the {@link AudioDeviceInventory#mDeviceInventory} list.
+ * @param deviceState the device to update
+ */
+ void addOrUpdateAudioDeviceCategoryInInventory(AdiDeviceState deviceState) {
synchronized (mDeviceInventoryLock) {
- return List.copyOf(mDeviceInventory);
+ mDeviceInventory.merge(deviceState.getDeviceId(), deviceState, (oldState, newState) -> {
+ oldState.setAudioDeviceCategory(newState.getAudioDeviceCategory());
+ return oldState;
+ });
}
}
- void addDeviceStateToInventory(AdiDeviceState deviceState) {
+ /**
+ * Finds the BT device that matches the passed {@code address}. Currently, this method only
+ * returns a valid device for A2DP and BLE devices.
+ *
+ * @param address MAC address of BT device
+ * @param isBle true if the device is BLE, false for A2DP
+ * @return the found {@link AdiDeviceState} or {@code null} otherwise.
+ */
+ @Nullable
+ AdiDeviceState findBtDeviceStateForAddress(String address, boolean isBle) {
synchronized (mDeviceInventoryLock) {
- mDeviceInventory.add(deviceState);
+ final Set<Integer> deviceSet = isBle ? DEVICE_OUT_ALL_BLE_SET : DEVICE_OUT_ALL_A2DP_SET;
+ for (Integer internalType : deviceSet) {
+ AdiDeviceState deviceState = mDeviceInventory.get(
+ new Pair<>(internalType, address));
+ if (deviceState != null) {
+ return deviceState;
+ }
+ }
}
+ return null;
}
+ /**
+ * Finds the device state that matches the passed {@link AudioDeviceAttributes} and device
+ * type. Note: currently this method only returns a valid device for A2DP and BLE devices.
+ *
+ * @param ada attributes of device to match
+ * @param canonicalDeviceType external device type to match
+ * @return the found {@link AdiDeviceState} matching a cached A2DP or BLE device or
+ * {@code null} otherwise.
+ */
+ @Nullable
AdiDeviceState findDeviceStateForAudioDeviceAttributes(AudioDeviceAttributes ada,
int canonicalDeviceType) {
final boolean isWireless = isBluetoothDevice(ada.getInternalType());
synchronized (mDeviceInventoryLock) {
- for (AdiDeviceState deviceSetting : mDeviceInventory) {
- if (deviceSetting.getDeviceType() == canonicalDeviceType
+ for (AdiDeviceState deviceState : mDeviceInventory.values()) {
+ if (deviceState.getDeviceType() == canonicalDeviceType
&& (!isWireless || ada.getAddress().equals(
- deviceSetting.getDeviceAddress()))) {
- return deviceSetting;
+ deviceState.getDeviceAddress()))) {
+ return deviceState;
}
}
}
return null;
}
+ /** Clears all cached {@link AdiDeviceState}'s. */
void clearDeviceInventory() {
synchronized (mDeviceInventoryLock) {
mDeviceInventory.clear();
@@ -384,7 +448,7 @@ public class AudioDeviceInventory {
+ " role:" + key.second + " devices:" + devices); });
pw.println("\ndevices:\n");
synchronized (mDeviceInventoryLock) {
- for (AdiDeviceState device : mDeviceInventory) {
+ for (AdiDeviceState device : mDeviceInventory.values()) {
pw.println("\t" + device + "\n");
}
}
@@ -1232,11 +1296,11 @@ public class AudioDeviceInventory {
AudioDeviceInfo[] connectedDevices = AudioManager.getDevicesStatic(
AudioManager.GET_DEVICES_ALL);
- Iterator<Map.Entry<Pair<Integer, Integer>, List<AudioDeviceAttributes>>> itRole =
+ Iterator<Entry<Pair<Integer, Integer>, List<AudioDeviceAttributes>>> itRole =
rolesMap.entrySet().iterator();
while (itRole.hasNext()) {
- Map.Entry<Pair<Integer, Integer>, List<AudioDeviceAttributes>> entry =
+ Entry<Pair<Integer, Integer>, List<AudioDeviceAttributes>> entry =
itRole.next();
Pair<Integer, Integer> keyRole = entry.getKey();
Iterator<AudioDeviceAttributes> itDev = rolesMap.get(keyRole).iterator();
@@ -2423,19 +2487,20 @@ public class AudioDeviceInventory {
int deviceCatalogSize = 0;
synchronized (mDeviceInventoryLock) {
deviceCatalogSize = mDeviceInventory.size();
- }
- final StringBuilder settingsBuilder = new StringBuilder(
- deviceCatalogSize * AdiDeviceState.getPeristedMaxSize());
- synchronized (mDeviceInventoryLock) {
- for (int i = 0; i < mDeviceInventory.size(); i++) {
- settingsBuilder.append(mDeviceInventory.get(i).toPersistableString());
- if (i != mDeviceInventory.size() - 1) {
- settingsBuilder.append(SETTING_DEVICE_SEPARATOR_CHAR);
- }
+ final StringBuilder settingsBuilder = new StringBuilder(
+ deviceCatalogSize * AdiDeviceState.getPeristedMaxSize());
+
+ Iterator<AdiDeviceState> iterator = mDeviceInventory.values().iterator();
+ if (iterator.hasNext()) {
+ settingsBuilder.append(iterator.next().toPersistableString());
+ }
+ while (iterator.hasNext()) {
+ settingsBuilder.append(SETTING_DEVICE_SEPARATOR_CHAR);
+ settingsBuilder.append(iterator.next().toPersistableString());
}
+ return settingsBuilder.toString();
}
- return settingsBuilder.toString();
}
/*package*/ void setDeviceSettings(String settings) {
@@ -2448,7 +2513,8 @@ public class AudioDeviceInventory {
// Note if the device is not compatible with spatialization mode or the device
// type is not canonical, it will be ignored in {@link SpatializerHelper}.
if (devState != null) {
- addDeviceStateToInventory(devState);
+ addOrUpdateDeviceSAStateInInventory(devState);
+ addOrUpdateAudioDeviceCategoryInInventory(devState);
}
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 3353b9ec538f..76c4cfe929bb 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -18,6 +18,14 @@ package com.android.server.audio;
import static android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED;
import static android.app.BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT;
+import static android.media.AudioDeviceInfo.TYPE_BLE_HEADSET;
+import static android.media.AudioDeviceInfo.TYPE_BLE_SPEAKER;
+import static android.media.AudioDeviceInfo.TYPE_BLUETOOTH_A2DP;
+import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_HEADPHONES;
+import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_UNKNOWN;
+import static android.media.AudioManager.DEVICE_OUT_BLE_HEADSET;
+import static android.media.AudioManager.DEVICE_OUT_BLE_SPEAKER;
+import static android.media.AudioManager.DEVICE_OUT_BLUETOOTH_A2DP;
import static android.media.AudioManager.RINGER_MODE_NORMAL;
import static android.media.AudioManager.RINGER_MODE_SILENT;
import static android.media.AudioManager.RINGER_MODE_VIBRATE;
@@ -92,6 +100,7 @@ import android.media.AudioFocusRequest;
import android.media.AudioFormat;
import android.media.AudioHalVersionInfo;
import android.media.AudioManager;
+import android.media.AudioManager.AudioDeviceCategory;
import android.media.AudioManagerInternal;
import android.media.AudioMixerAttributes;
import android.media.AudioPlaybackConfiguration;
@@ -405,6 +414,7 @@ public class AudioService extends IAudioService.Stub
private static final int MSG_DISABLE_AUDIO_FOR_UID = 100;
private static final int MSG_INIT_STREAMS_VOLUMES = 101;
private static final int MSG_INIT_SPATIALIZER = 102;
+ private static final int MSG_INIT_ADI_DEVICE_STATES = 103;
// end of messages handled under wakelock
@@ -1286,6 +1296,8 @@ public class AudioService extends IAudioService.Stub
// done with service initialization, continue additional work in our Handler thread
queueMsgUnderWakeLock(mAudioHandler, MSG_INIT_STREAMS_VOLUMES,
0 /* arg1 */, 0 /* arg2 */, null /* obj */, 0 /* delay */);
+ queueMsgUnderWakeLock(mAudioHandler, MSG_INIT_ADI_DEVICE_STATES,
+ 0 /* arg1 */, 0 /* arg2 */, null /* obj */, 0 /* delay */);
queueMsgUnderWakeLock(mAudioHandler, MSG_INIT_SPATIALIZER,
0 /* arg1 */, 0 /* arg2 */, null /* obj */, 0 /* delay */);
@@ -7377,7 +7389,7 @@ public class AudioService extends IAudioService.Stub
if (pkgName == null) {
pkgName = "";
}
- if (device.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_A2DP) {
+ if (device.getType() == TYPE_BLUETOOTH_A2DP) {
avrcpSupportsAbsoluteVolume(device.getAddress(),
deviceVolumeBehavior == AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
return;
@@ -9253,6 +9265,11 @@ public class AudioService extends IAudioService.Stub
mAudioEventWakeLock.release();
break;
+ case MSG_INIT_ADI_DEVICE_STATES:
+ onInitAdiDeviceStates();
+ mAudioEventWakeLock.release();
+ break;
+
case MSG_INIT_SPATIALIZER:
onInitSpatializer();
mAudioEventWakeLock.release();
@@ -10322,8 +10339,13 @@ public class AudioService extends IAudioService.Stub
/*arg1*/ 0, /*arg2*/ 0, TAG, /*delay*/ 0);
}
- void onInitSpatializer() {
+ void onInitAdiDeviceStates() {
mDeviceBroker.onReadAudioDeviceSettings();
+ mSoundDoseHelper.initCachedAudioDeviceCategories(
+ mDeviceBroker.getImmutableDeviceInventory());
+ }
+
+ void onInitSpatializer() {
mSpatializerHelper.init(/*effectExpected*/ mHasSpatializerEffect);
mSpatializerHelper.setFeatureEnabled(mHasSpatializerEffect);
}
@@ -10718,6 +10740,51 @@ public class AudioService extends IAudioService.Stub
return mSoundDoseHelper.isCsdEnabled();
}
+ @Override
+ @android.annotation.EnforcePermission(MODIFY_AUDIO_SETTINGS_PRIVILEGED)
+ public void setBluetoothAudioDeviceCategory(@NonNull String address, boolean isBle,
+ @AudioDeviceCategory int btAudioDeviceCategory) {
+ super.setBluetoothAudioDeviceCategory_enforcePermission();
+
+ final String addr = Objects.requireNonNull(address);
+
+ AdiDeviceState deviceState = mDeviceBroker.findBtDeviceStateForAddress(addr, isBle);
+
+ int internalType = !isBle ? DEVICE_OUT_BLUETOOTH_A2DP
+ : ((btAudioDeviceCategory == AUDIO_DEVICE_CATEGORY_HEADPHONES)
+ ? DEVICE_OUT_BLE_HEADSET : DEVICE_OUT_BLE_SPEAKER);
+ int deviceType = !isBle ? TYPE_BLUETOOTH_A2DP
+ : ((btAudioDeviceCategory == AUDIO_DEVICE_CATEGORY_HEADPHONES) ? TYPE_BLE_HEADSET
+ : TYPE_BLE_SPEAKER);
+
+ if (deviceState == null) {
+ deviceState = new AdiDeviceState(deviceType, internalType, addr);
+ }
+
+ deviceState.setAudioDeviceCategory(btAudioDeviceCategory);
+
+ mDeviceBroker.addOrUpdateBtAudioDeviceCategoryInInventory(deviceState);
+ mDeviceBroker.persistAudioDeviceSettings();
+
+ mSoundDoseHelper.setAudioDeviceCategory(addr, internalType,
+ btAudioDeviceCategory == AUDIO_DEVICE_CATEGORY_HEADPHONES);
+ }
+
+ @Override
+ @android.annotation.EnforcePermission(MODIFY_AUDIO_SETTINGS_PRIVILEGED)
+ @AudioDeviceCategory
+ public int getBluetoothAudioDeviceCategory(@NonNull String address, boolean isBle) {
+ super.getBluetoothAudioDeviceCategory_enforcePermission();
+
+ final AdiDeviceState deviceState = mDeviceBroker.findBtDeviceStateForAddress(
+ Objects.requireNonNull(address), isBle);
+ if (deviceState == null) {
+ return AUDIO_DEVICE_CATEGORY_UNKNOWN;
+ }
+
+ return deviceState.getAudioDeviceCategory();
+ }
+
//==========================================================================================
// Hdmi CEC:
// - System audio mode:
diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java
index 01af3a838597..851c5c3cb73c 100644
--- a/services/core/java/com/android/server/audio/SoundDoseHelper.java
+++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java
@@ -16,6 +16,9 @@
package com.android.server.audio;
+import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_HEADPHONES;
+import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_UNKNOWN;
+
import static com.android.server.audio.AudioService.MAX_STREAM_VOLUME;
import static com.android.server.audio.AudioService.MIN_STREAM_VOLUME;
import static com.android.server.audio.AudioService.MSG_SET_DEVICE_VOLUME;
@@ -57,6 +60,7 @@ import com.android.server.utils.EventLogger;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -189,6 +193,9 @@ public class SoundDoseHelper {
private final AtomicBoolean mEnableCsd = new AtomicBoolean(false);
+ private ArrayList<ISoundDose.AudioDeviceCategory> mCachedAudioDeviceCategories =
+ new ArrayList<>();
+
private final Object mCsdStateLock = new Object();
private final AtomicReference<ISoundDose> mSoundDose = new AtomicReference<>();
@@ -487,6 +494,43 @@ public class SoundDoseHelper {
return false;
}
+ void setAudioDeviceCategory(String address, int internalAudioType, boolean isHeadphone) {
+ if (!mEnableCsd.get()) {
+ return;
+ }
+
+ final ISoundDose soundDose = mSoundDose.get();
+ if (soundDose == null) {
+ Log.w(TAG, "Sound dose interface not initialized");
+ return;
+ }
+
+ try {
+ final ISoundDose.AudioDeviceCategory audioDeviceCategory =
+ new ISoundDose.AudioDeviceCategory();
+ audioDeviceCategory.address = address;
+ audioDeviceCategory.internalAudioType = internalAudioType;
+ audioDeviceCategory.csdCompatible = isHeadphone;
+ soundDose.setAudioDeviceCategory(audioDeviceCategory);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception while forcing the internal MEL computation", e);
+ }
+ }
+
+ void initCachedAudioDeviceCategories(Collection<AdiDeviceState> deviceStates) {
+ for (final AdiDeviceState state : deviceStates) {
+ if (state.getAudioDeviceCategory() != AUDIO_DEVICE_CATEGORY_UNKNOWN) {
+ final ISoundDose.AudioDeviceCategory audioDeviceCategory =
+ new ISoundDose.AudioDeviceCategory();
+ audioDeviceCategory.address = state.getDeviceAddress();
+ audioDeviceCategory.internalAudioType = state.getInternalDeviceType();
+ audioDeviceCategory.csdCompatible =
+ state.getAudioDeviceCategory() == AUDIO_DEVICE_CATEGORY_HEADPHONES;
+ mCachedAudioDeviceCategories.add(audioDeviceCategory);
+ }
+ }
+ }
+
/*package*/ int safeMediaVolumeIndex(int device) {
final int vol = mSafeMediaVolumeDevices.get(device);
if (vol == SAFE_MEDIA_VOLUME_UNINITIALIZED) {
@@ -810,6 +854,16 @@ public class SoundDoseHelper {
Log.v(TAG, "Initializing sound dose");
+ try {
+ if (mCachedAudioDeviceCategories.size() > 0) {
+ soundDose.initCachedAudioDeviceCategories(mCachedAudioDeviceCategories.toArray(
+ new ISoundDose.AudioDeviceCategory[0]));
+ mCachedAudioDeviceCategories.clear();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception while forcing the internal MEL computation", e);
+ }
+
synchronized (mCsdStateLock) {
if (mGlobalTimeOffsetInSecs == GLOBAL_TIME_OFFSET_UNINITIALIZED) {
mGlobalTimeOffsetInSecs = System.currentTimeMillis() / 1000L;
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 969dd60a8012..496bdf48b5bf 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -560,7 +560,7 @@ public class SpatializerHelper {
updatedDevice = new AdiDeviceState(canonicalDeviceType, ada.getInternalType(),
ada.getAddress());
initSAState(updatedDevice);
- mDeviceBroker.addDeviceStateToInventory(updatedDevice);
+ mDeviceBroker.addOrUpdateDeviceSAStateInInventory(updatedDevice);
}
if (updatedDevice != null) {
onRoutingUpdated();
@@ -693,7 +693,7 @@ public class SpatializerHelper {
new AdiDeviceState(canonicalDeviceType, ada.getInternalType(),
ada.getAddress());
initSAState(deviceState);
- mDeviceBroker.addDeviceStateToInventory(deviceState);
+ mDeviceBroker.addOrUpdateDeviceSAStateInInventory(deviceState);
mDeviceBroker.persistAudioDeviceSettings();
logDeviceState(deviceState, "addWirelessDeviceIfNew"); // may be updated later.
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 279aaf9d3253..1898b8015462 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -1308,10 +1308,13 @@ public class BiometricService extends SystemService {
.getString(R.string.biometric_dialog_default_subtitle));
} else if (hasEligibleFingerprintSensor) {
promptInfo.setSubtitle(getContext()
- .getString(R.string.biometric_dialog_fingerprint_subtitle));
+ .getString(R.string.fingerprint_dialog_default_subtitle));
} else if (hasEligibleFaceSensor) {
promptInfo.setSubtitle(getContext()
- .getString(R.string.biometric_dialog_face_subtitle));
+ .getString(R.string.face_dialog_default_subtitle));
+ } else {
+ promptInfo.setSubtitle(getContext()
+ .getString(R.string.screen_lock_dialog_default_subtitle));
}
}
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java b/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java
index fc3d7c8114b0..745222873698 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java
@@ -216,6 +216,10 @@ public final class BiometricContextProvider implements BiometricContext {
public void subscribe(@NonNull OperationContextExt context,
@NonNull Consumer<OperationContext> consumer) {
mSubscribers.put(context, consumer);
+ // TODO(b/294161627) Combine the getContext/subscribe APIs to avoid race
+ if (context.getDisplayState() != getDisplayState()) {
+ consumer.accept(context.update(this, context.isCrypto()).toAidlContext());
+ }
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 3d0ea9d8bef6..54d1faa39be0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -260,6 +260,14 @@ class FingerprintAuthenticationClient
final AidlSession session = getFreshDaemon();
final OperationContextExt opContext = getOperationContext();
+ final ICancellationSignal cancel;
+ if (session.hasContextMethods()) {
+ cancel = session.getSession().authenticateWithContext(
+ mOperationId, opContext.toAidlContext(getOptions()));
+ } else {
+ cancel = session.getSession().authenticate(mOperationId);
+ }
+
getBiometricContext().subscribe(opContext, ctx -> {
if (session.hasContextMethods()) {
try {
@@ -281,12 +289,7 @@ class FingerprintAuthenticationClient
mALSProbeCallback.getProbe().enable();
}
- if (session.hasContextMethods()) {
- return session.getSession().authenticateWithContext(
- mOperationId, opContext.toAidlContext(getOptions()));
- } else {
- return session.getSession().authenticate(mOperationId);
- }
+ return cancel;
}
@Override
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index e5965eff7070..c131226a60dd 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -222,8 +222,14 @@ import javax.xml.datatype.DatatypeConfigurationException;
* <minimum>120</minimum>
* <maximum>120</maximum>
* </refreshRate>
- * <thermalStatusLimit>light</thermalStatusLimit>
* <allowInLowPowerMode>false</allowInLowPowerMode>
+ * <minimumHdrPercentOfScreen>0.6</minimumHdrPercentOfScreen>
+ * <sdrHdrRatioMap>
+ * <point>
+ * <sdrNits>2.000</sdrNits>
+ * <hdrRatio>4.000</hdrRatio>
+ * </point>
+ * </sdrHdrRatioMap>
* </highBrightnessMode>
*
* <luxThrottling>
@@ -276,6 +282,10 @@ import javax.xml.datatype.DatatypeConfigurationException;
* <lightSensor>
* <type>android.sensor.light</type>
* <name>1234 Ambient Light Sensor</name>
+ * <refreshRate>
+ * <minimum>60</minimum>
+ * <maximum>120</maximum>
+ * </refreshRate>
* </lightSensor>
* <screenOffBrightnessSensor>
* <type>com.google.sensor.binned_brightness</type>
@@ -1568,37 +1578,40 @@ public class DisplayDeviceConfig {
public String toString() {
return "DisplayDeviceConfig{"
+ "mLoadedFrom=" + mLoadedFrom
- + ", mBacklight=" + Arrays.toString(mBacklight)
+ + "\n"
+ + "mBacklight=" + Arrays.toString(mBacklight)
+ ", mNits=" + Arrays.toString(mNits)
+ ", mRawBacklight=" + Arrays.toString(mRawBacklight)
+ ", mRawNits=" + Arrays.toString(mRawNits)
+ ", mInterpolationType=" + mInterpolationType
- + ", mBrightness=" + Arrays.toString(mBrightness)
- + ", mBrightnessToBacklightSpline=" + mBrightnessToBacklightSpline
+ + "mBrightness=" + Arrays.toString(mBrightness)
+ + "\n"
+ + "mBrightnessToBacklightSpline=" + mBrightnessToBacklightSpline
+ ", mBacklightToBrightnessSpline=" + mBacklightToBrightnessSpline
+ ", mNitsToBacklightSpline=" + mNitsToBacklightSpline
+ ", mBacklightMinimum=" + mBacklightMinimum
+ ", mBacklightMaximum=" + mBacklightMaximum
+ ", mBrightnessDefault=" + mBrightnessDefault
+ ", mQuirks=" + mQuirks
- + ", isHbmEnabled=" + mIsHighBrightnessModeEnabled
- + ", mLuxThrottlingData=" + mLuxThrottlingData
+ + ", mIsHighBrightnessModeEnabled=" + mIsHighBrightnessModeEnabled
+ + "\n"
+ + "mLuxThrottlingData=" + mLuxThrottlingData
+ ", mHbmData=" + mHbmData
+ ", mSdrToHdrRatioSpline=" + mSdrToHdrRatioSpline
+ ", mThermalBrightnessThrottlingDataMapByThrottlingId="
+ mThermalBrightnessThrottlingDataMapByThrottlingId
+ "\n"
- + ", mBrightnessRampFastDecrease=" + mBrightnessRampFastDecrease
+ + "mBrightnessRampFastDecrease=" + mBrightnessRampFastDecrease
+ ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease
+ ", mBrightnessRampSlowDecrease=" + mBrightnessRampSlowDecrease
+ ", mBrightnessRampSlowIncrease=" + mBrightnessRampSlowIncrease
+ ", mBrightnessRampDecreaseMaxMillis=" + mBrightnessRampDecreaseMaxMillis
+ ", mBrightnessRampIncreaseMaxMillis=" + mBrightnessRampIncreaseMaxMillis
+ "\n"
- + ", mAmbientHorizonLong=" + mAmbientHorizonLong
+ + "mAmbientHorizonLong=" + mAmbientHorizonLong
+ ", mAmbientHorizonShort=" + mAmbientHorizonShort
+ "\n"
- + ", mScreenDarkeningMinThreshold=" + mScreenDarkeningMinThreshold
+ + "mScreenDarkeningMinThreshold=" + mScreenDarkeningMinThreshold
+ ", mScreenDarkeningMinThresholdIdle=" + mScreenDarkeningMinThresholdIdle
+ ", mScreenBrighteningMinThreshold=" + mScreenBrighteningMinThreshold
+ ", mScreenBrighteningMinThresholdIdle=" + mScreenBrighteningMinThresholdIdle
@@ -1608,7 +1621,7 @@ public class DisplayDeviceConfig {
+ ", mAmbientLuxBrighteningMinThresholdIdle="
+ mAmbientLuxBrighteningMinThresholdIdle
+ "\n"
- + ", mScreenBrighteningLevels=" + Arrays.toString(
+ + "mScreenBrighteningLevels=" + Arrays.toString(
mScreenBrighteningLevels)
+ ", mScreenBrighteningPercentages=" + Arrays.toString(
mScreenBrighteningPercentages)
@@ -1625,7 +1638,7 @@ public class DisplayDeviceConfig {
+ ", mAmbientDarkeningPercentages=" + Arrays.toString(
mAmbientDarkeningPercentages)
+ "\n"
- + ", mAmbientBrighteningLevelsIdle=" + Arrays.toString(
+ + "mAmbientBrighteningLevelsIdle=" + Arrays.toString(
mAmbientBrighteningLevelsIdle)
+ ", mAmbientBrighteningPercentagesIdle=" + Arrays.toString(
mAmbientBrighteningPercentagesIdle)
@@ -1642,7 +1655,7 @@ public class DisplayDeviceConfig {
+ ", mScreenDarkeningPercentagesIdle=" + Arrays.toString(
mScreenDarkeningPercentagesIdle)
+ "\n"
- + ", mAmbientLightSensor=" + mAmbientLightSensor
+ + "mAmbientLightSensor=" + mAmbientLightSensor
+ ", mScreenOffBrightnessSensor=" + mScreenOffBrightnessSensor
+ ", mProximitySensor=" + mProximitySensor
+ ", mRefreshRateLimitations= " + Arrays.toString(mRefreshRateLimitations.toArray())
@@ -1656,7 +1669,7 @@ public class DisplayDeviceConfig {
+ ", mDdcAutoBrightnessAvailable= " + mDdcAutoBrightnessAvailable
+ ", mAutoBrightnessAvailable= " + mAutoBrightnessAvailable
+ "\n"
- + ", mDefaultLowBlockingZoneRefreshRate= " + mDefaultLowBlockingZoneRefreshRate
+ + "mDefaultLowBlockingZoneRefreshRate= " + mDefaultLowBlockingZoneRefreshRate
+ ", mDefaultHighBlockingZoneRefreshRate= " + mDefaultHighBlockingZoneRefreshRate
+ ", mDefaultPeakRefreshRate= " + mDefaultPeakRefreshRate
+ ", mDefaultRefreshRate= " + mDefaultRefreshRate
@@ -1665,7 +1678,7 @@ public class DisplayDeviceConfig {
+ ", mDefaultRefreshRateInHbmSunlight= " + mDefaultRefreshRateInHbmSunlight
+ ", mRefreshRateThrottlingMap= " + mRefreshRateThrottlingMap
+ "\n"
- + ", mLowDisplayBrightnessThresholds= "
+ + "mLowDisplayBrightnessThresholds= "
+ Arrays.toString(mLowDisplayBrightnessThresholds)
+ ", mLowAmbientBrightnessThresholds= "
+ Arrays.toString(mLowAmbientBrightnessThresholds)
@@ -1674,10 +1687,10 @@ public class DisplayDeviceConfig {
+ ", mHighAmbientBrightnessThresholds= "
+ Arrays.toString(mHighAmbientBrightnessThresholds)
+ "\n"
- + ", mScreenOffBrightnessSensorValueToLux=" + Arrays.toString(
+ + "mScreenOffBrightnessSensorValueToLux=" + Arrays.toString(
mScreenOffBrightnessSensorValueToLux)
+ "\n"
- + ", mUsiVersion= " + mHostUsiVersion
+ + "mUsiVersion= " + mHostUsiVersion
+ "}";
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 19dffeba868e..58f4d0859c1a 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -39,6 +39,7 @@ import static android.hardware.display.DisplayViewport.VIEWPORT_EXTERNAL;
import static android.hardware.display.DisplayViewport.VIEWPORT_INTERNAL;
import static android.hardware.display.DisplayViewport.VIEWPORT_VIRTUAL;
import static android.hardware.display.HdrConversionMode.HDR_CONVERSION_UNSUPPORTED;
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.Process.FIRST_APPLICATION_UID;
import static android.os.Process.ROOT_UID;
@@ -593,7 +594,7 @@ public final class DisplayManagerService extends SystemService {
DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
- true /*allowIsolated*/);
+ true /*allowIsolated*/, DUMP_FLAG_PRIORITY_CRITICAL);
publishLocalService(DisplayManagerInternal.class, new LocalService());
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index b96187f7af77..5213d3179de7 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -613,7 +613,9 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
setUpAutoBrightness(resources, handler);
- mColorFadeEnabled = mInjector.isColorFadeEnabled(resources);
+ mColorFadeEnabled = mInjector.isColorFadeEnabled()
+ && !resources.getBoolean(
+ com.android.internal.R.bool.config_displayColorFadeDisabled);
mColorFadeFadesConfig = resources.getBoolean(
R.bool.config_animateScreenLights);
@@ -2449,6 +2451,10 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
dumpRbcEvents(pw);
+ if (mScreenOffBrightnessSensorController != null) {
+ mScreenOffBrightnessSensorController.dump(pw);
+ }
+
if (mBrightnessRangeController != null) {
mBrightnessRangeController.dump(pw);
}
@@ -3005,10 +3011,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
sensorManager, resources);
}
- boolean isColorFadeEnabled(Resources resources) {
- return !ActivityManager.isLowRamDeviceStatic()
- && !resources.getBoolean(
- com.android.internal.R.bool.config_displayColorFadeDisabled);
+ boolean isColorFadeEnabled() {
+ return !ActivityManager.isLowRamDeviceStatic();
}
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 4edc8bc3eceb..9c271ff54d6b 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -441,6 +441,9 @@ final class LogicalDisplay {
if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED) != 0) {
mBaseDisplayInfo.flags |= Display.FLAG_ALWAYS_UNLOCKED;
}
+ if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0) {
+ mBaseDisplayInfo.flags |= Display.FLAG_ROTATES_WITH_CONTENT;
+ }
if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
mBaseDisplayInfo.flags |= Display.FLAG_TOUCH_FEEDBACK_DISABLED;
}
diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
index 5bdf26307d11..a5162c09f838 100644
--- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java
+++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
@@ -169,7 +169,9 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
@Override
@MainThread
public void onInputDeviceAdded(int deviceId) {
- onInputDeviceChanged(deviceId);
+ // Logging keyboard configuration data to statsd whenever input device is added. Currently
+ // only logging for New Settings UI where we are using IME to decide the layout information.
+ onInputDeviceChangedInternal(deviceId, true /* shouldLogConfiguration */);
}
@Override
@@ -182,6 +184,10 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
@Override
@MainThread
public void onInputDeviceChanged(int deviceId) {
+ onInputDeviceChangedInternal(deviceId, false /* shouldLogConfiguration */);
+ }
+
+ private void onInputDeviceChangedInternal(int deviceId, boolean shouldLogConfiguration) {
final InputDevice inputDevice = getInputDevice(deviceId);
if (inputDevice == null || inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) {
return;
@@ -243,18 +249,15 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
synchronized (mDataStore) {
try {
final String key = keyboardIdentifier.toString();
- boolean isFirstConfiguration = !mDataStore.hasInputDeviceEntry(key);
if (mDataStore.setSelectedKeyboardLayouts(key, selectedLayouts)) {
// Need to show the notification only if layout selection changed
// from the previous configuration
needToShowNotification = true;
+ }
- // Logging keyboard configuration data to statsd only if the
- // configuration changed from the previous configuration. Currently
- // only logging for New Settings UI where we are using IME to decide
- // the layout information.
+ if (shouldLogConfiguration) {
logKeyboardConfigurationEvent(inputDevice, imeInfoList, layoutInfoList,
- isFirstConfiguration);
+ !mDataStore.hasInputDeviceEntry(key));
}
} finally {
mDataStore.saveIfNeeded();
diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
index 9ad4628596fc..2e0274b79d1f 100644
--- a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
+++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
@@ -23,6 +23,7 @@ import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_EXP
import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_FORCED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
+import static android.view.MotionEvent.TOOL_TYPE_UNKNOWN;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED;
@@ -44,6 +45,7 @@ import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
+import android.view.MotionEvent;
import android.view.WindowManager;
import android.view.inputmethod.ImeTracker;
import android.view.inputmethod.InputMethod;
@@ -351,7 +353,8 @@ public final class ImeVisibilityStateComputer {
void setWindowState(IBinder windowToken, @NonNull ImeTargetWindowState newState) {
final ImeTargetWindowState state = mRequestWindowStateMap.get(windowToken);
- if (state != null && newState.hasEditorFocused()) {
+ if (state != null && newState.hasEditorFocused()
+ && newState.mToolType != MotionEvent.TOOL_TYPE_STYLUS) {
// Inherit the last requested IME visible state when the target window is still
// focused with an editor.
newState.setRequestedImeVisible(state.mRequestedImeVisible);
@@ -652,14 +655,23 @@ public final class ImeVisibilityStateComputer {
* A class that represents the current state of the IME target window.
*/
static class ImeTargetWindowState {
+
ImeTargetWindowState(@SoftInputModeFlags int softInputModeState, int windowFlags,
boolean imeFocusChanged, boolean hasFocusedEditor,
boolean isStartInputByGainFocus) {
+ this(softInputModeState, windowFlags, imeFocusChanged, hasFocusedEditor,
+ isStartInputByGainFocus, TOOL_TYPE_UNKNOWN);
+ }
+
+ ImeTargetWindowState(@SoftInputModeFlags int softInputModeState, int windowFlags,
+ boolean imeFocusChanged, boolean hasFocusedEditor,
+ boolean isStartInputByGainFocus, @MotionEvent.ToolType int toolType) {
mSoftInputModeState = softInputModeState;
mWindowFlags = windowFlags;
mImeFocusChanged = imeFocusChanged;
mHasFocusedEditor = hasFocusedEditor;
mIsStartInputByGainFocus = isStartInputByGainFocus;
+ mToolType = toolType;
}
/**
@@ -670,6 +682,11 @@ public final class ImeVisibilityStateComputer {
private final int mWindowFlags;
/**
+ * {@link MotionEvent#getToolType(int)} that was used to click editor.
+ */
+ private final int mToolType;
+
+ /**
* {@code true} means the IME focus changed from the previous window, {@code false}
* otherwise.
*/
@@ -718,6 +735,10 @@ public final class ImeVisibilityStateComputer {
return mWindowFlags;
}
+ int getToolType() {
+ return mToolType;
+ }
+
private void setImeDisplayId(int imeDisplayId) {
mImeDisplayId = imeDisplayId;
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index 1d222e58c8fd..20c7029b77cb 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -40,6 +40,7 @@ import android.util.Slog;
import android.view.WindowManager;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -295,7 +296,12 @@ final class InputMethodBindingController {
}
if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
final InputMethodInfo info = mMethodMap.get(mSelectedMethodId);
+ boolean supportsStylusHwChanged =
+ mSupportsStylusHw != info.supportsStylusHandwriting();
mSupportsStylusHw = info.supportsStylusHandwriting();
+ if (supportsStylusHwChanged) {
+ InputMethodManager.invalidateLocalStylusHandwritingAvailabilityCaches();
+ }
mService.initializeImeLocked(mCurMethod, mCurToken);
mService.scheduleNotifyImeUidToAudioService(mCurMethodUid);
mService.reRequestCurrentClientSessionLocked();
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 4ce7e2448487..2fc48294ae70 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2315,8 +2315,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
mCurClient = null;
ImeTracker.forLogging().onFailed(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
mCurStatsToken = null;
- InputMethodManager.invalidateLocalStylusHandwritingAvailabilityCaches();
-
mMenuController.hideInputMethodMenuLocked();
}
}
@@ -3794,11 +3792,14 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
final boolean startInputByWinGainedFocus =
(startInputFlags & StartInputFlags.WINDOW_GAINED_FOCUS) != 0;
+ final int toolType = editorInfo != null
+ ? editorInfo.getInitialToolType() : MotionEvent.TOOL_TYPE_UNKNOWN;
// Init the focused window state (e.g. whether the editor has focused or IME focus has
// changed from another window).
- final ImeTargetWindowState windowState = new ImeTargetWindowState(softInputMode,
- windowFlags, !sameWindowFocused, isTextEditor, startInputByWinGainedFocus);
+ final ImeTargetWindowState windowState = new ImeTargetWindowState(
+ softInputMode, windowFlags, !sameWindowFocused, isTextEditor,
+ startInputByWinGainedFocus, toolType);
mVisibilityStateComputer.setWindowState(windowToken, windowState);
if (sameWindowFocused && isTextEditor) {
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 595b2e4113b2..74b7f0866b54 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -1750,13 +1750,6 @@ public class LocationManagerService extends ILocationManager.Stub implements
}
@Override
- public void sendNiResponse(int notifId, int userResponse) {
- if (mGnssManagerService != null) {
- mGnssManagerService.sendNiResponse(notifId, userResponse);
- }
- }
-
- @Override
public @Nullable LocationTime getGnssTimeMillis() {
LocationProviderManager gpsManager = getLocationProviderManager(GPS_PROVIDER);
if (gpsManager == null) {
diff --git a/services/core/java/com/android/server/location/TEST_MAPPING b/services/core/java/com/android/server/location/TEST_MAPPING
index 214d2f3f5646..f5deb2ba3e07 100644
--- a/services/core/java/com/android/server/location/TEST_MAPPING
+++ b/services/core/java/com/android/server/location/TEST_MAPPING
@@ -1,7 +1,13 @@
{
"presubmit": [
{
- "name": "CtsLocationFineTestCases"
+ "name": "CtsLocationFineTestCases",
+ "options": [
+ {
+ // TODO: Wait for test to deflake - b/293934372
+ "exclude-filter":"android.location.cts.fine.ScanningSettingsTest"
+ }
+ ]
},
{
"name": "CtsLocationCoarseTestCases"
@@ -16,4 +22,4 @@
}]
}
]
-} \ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index ed5c1306733e..e97a12a83b1f 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -62,7 +62,6 @@ import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.location.GnssCapabilities;
import android.location.GnssStatus;
-import android.location.INetInitiatedListener;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
@@ -109,7 +108,6 @@ import android.util.TimeUtils;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IBatteryStats;
import com.android.internal.location.GpsNetInitiatedHandler;
-import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.HexDump;
import com.android.server.FgThread;
@@ -396,7 +394,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
mC2KServerPort = mGnssConfiguration.getC2KPort(TCP_MIN_PORT);
mNIHandler.setEmergencyExtensionSeconds(mGnssConfiguration.getEsExtensionSec());
mSuplEsEnabled = mGnssConfiguration.getSuplEs(0) == 1;
- mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
if (mGnssVisibilityControl != null) {
mGnssVisibilityControl.onConfigurationUpdated(mGnssConfiguration);
}
@@ -465,7 +462,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
};
mNIHandler = new GpsNetInitiatedHandler(context,
- mNetInitiatedListener,
emergencyCallCallback,
mSuplEsEnabled);
// Trigger PSDS data download when the network comes up after booting.
@@ -1435,96 +1431,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
updateRequirements();
}
- //=============================================================
- // NI Client support
- //=============================================================
- private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
- // Sends a response for an NI request to HAL.
- @Override
- public boolean sendNiResponse(int notificationId, int userResponse) {
- // TODO Add Permission check
-
- if (DEBUG) {
- Log.d(TAG, "sendNiResponse, notifId: " + notificationId
- + ", response: " + userResponse);
- }
- mGnssNative.sendNiResponse(notificationId, userResponse);
-
- FrameworkStatsLog.write(FrameworkStatsLog.GNSS_NI_EVENT_REPORTED,
- FrameworkStatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_RESPONSE,
- notificationId,
- /* niType= */ 0,
- /* needNotify= */ false,
- /* needVerify= */ false,
- /* privacyOverride= */ false,
- /* timeout= */ 0,
- /* defaultResponse= */ 0,
- /* requestorId= */ null,
- /* text= */ null,
- /* requestorIdEncoding= */ 0,
- /* textEncoding= */ 0,
- mSuplEsEnabled,
- isGpsEnabled(),
- userResponse);
-
- return true;
- }
- };
-
- public INetInitiatedListener getNetInitiatedListener() {
- return mNetInitiatedListener;
- }
-
- /** Reports a NI notification. */
- private void reportNiNotification(int notificationId, int niType, int notifyFlags, int timeout,
- int defaultResponse, String requestorId, String text, int requestorIdEncoding,
- int textEncoding) {
- Log.i(TAG, "reportNiNotification: entered");
- Log.i(TAG, "notificationId: " + notificationId
- + ", niType: " + niType
- + ", notifyFlags: " + notifyFlags
- + ", timeout: " + timeout
- + ", defaultResponse: " + defaultResponse);
-
- Log.i(TAG, "requestorId: " + requestorId
- + ", text: " + text
- + ", requestorIdEncoding: " + requestorIdEncoding
- + ", textEncoding: " + textEncoding);
-
- GpsNiNotification notification = new GpsNiNotification();
-
- notification.notificationId = notificationId;
- notification.niType = niType;
- notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
- notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
- notification.privacyOverride =
- (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
- notification.timeout = timeout;
- notification.defaultResponse = defaultResponse;
- notification.requestorId = requestorId;
- notification.text = text;
- notification.requestorIdEncoding = requestorIdEncoding;
- notification.textEncoding = textEncoding;
-
- mNIHandler.handleNiNotification(notification);
- FrameworkStatsLog.write(FrameworkStatsLog.GNSS_NI_EVENT_REPORTED,
- FrameworkStatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_REQUEST,
- notification.notificationId,
- notification.niType,
- notification.needNotify,
- notification.needVerify,
- notification.privacyOverride,
- notification.timeout,
- notification.defaultResponse,
- notification.requestorId,
- notification.text,
- notification.requestorIdEncoding,
- notification.textEncoding,
- mSuplEsEnabled,
- isGpsEnabled(),
- /* userResponse= */ 0);
- }
-
private void demandUtcTimeInjection() {
if (DEBUG) Log.d(TAG, "demandUtcTimeInjection");
postWithWakeLockHeld(mNetworkTimeHelper::demandUtcTimeInjection);
@@ -1829,14 +1735,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
@Override
- public void onReportNiNotification(int notificationId, int niType, int notifyFlags,
- int timeout, int defaultResponse, String requestorId, String text,
- int requestorIdEncoding, int textEncoding) {
- reportNiNotification(notificationId, niType, notifyFlags, timeout,
- defaultResponse, requestorId, text, requestorIdEncoding, textEncoding);
- }
-
- @Override
public void onRequestSetID(@GnssNative.AGpsCallbacks.AgpsSetIdFlags int flags) {
TelephonyManager phone = (TelephonyManager)
mContext.getSystemService(Context.TELEPHONY_SERVICE);
diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
index c962bc4c20d8..133704d11b08 100644
--- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java
+++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
@@ -38,7 +38,6 @@ import android.location.LocationManager;
import android.location.util.identity.CallerIdentity;
import android.os.BatteryStats;
import android.os.Binder;
-import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.IndentingPrintWriter;
@@ -275,17 +274,6 @@ public class GnssManagerService {
}
/**
- * Send Ni Response, indicating a location request initiated by a network carrier.
- */
- public void sendNiResponse(int notifId, int userResponse) {
- try {
- mGnssLocationProvider.getNetInitiatedListener().sendNiResponse(notifId, userResponse);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Dump info for debugging.
*/
public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
diff --git a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
index 7618419ab0e4..bdd488581817 100644
--- a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
+++ b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
@@ -284,9 +284,6 @@ public class GnssNative {
/** Callbacks for notifications. */
public interface NotificationCallbacks {
- void onReportNiNotification(int notificationId, int niType, int notifyFlags,
- int timeout, int defaultResponse, String requestorId, String text,
- int requestorIdEncoding, int textEncoding);
void onReportNfwNotification(String proxyAppPackageName, byte protocolStack,
String otherProtocolStackName, byte requestor, String requestorId,
byte responseType, boolean inEmergencyMode, boolean isCachedLocation);
@@ -933,14 +930,6 @@ public class GnssNative {
}
/**
- * Send a network initiated respnse.
- */
- public void sendNiResponse(int notificationId, int userResponse) {
- Preconditions.checkState(mRegistered);
- mGnssHal.sendNiResponse(notificationId, userResponse);
- }
-
- /**
* Request an eventual update of GNSS power statistics.
*/
public void requestPowerStats() {
@@ -1244,16 +1233,6 @@ public class GnssNative {
}
@NativeEntryPoint
- void reportNiNotification(int notificationId, int niType, int notifyFlags,
- int timeout, int defaultResponse, String requestorId, String text,
- int requestorIdEncoding, int textEncoding) {
- Binder.withCleanCallingIdentity(
- () -> mNotificationCallbacks.onReportNiNotification(notificationId, niType,
- notifyFlags, timeout, defaultResponse, requestorId, text,
- requestorIdEncoding, textEncoding));
- }
-
- @NativeEntryPoint
void requestSetID(int flags) {
Binder.withCleanCallingIdentity(() -> mAGpsCallbacks.onRequestSetID(flags));
}
@@ -1488,10 +1467,6 @@ public class GnssNative {
return native_is_gnss_visibility_control_supported();
}
- protected void sendNiResponse(int notificationId, int userResponse) {
- native_send_ni_response(notificationId, userResponse);
- }
-
protected void requestPowerStats() {
native_request_power_stats();
}
@@ -1648,8 +1623,6 @@ public class GnssNative {
private static native boolean native_is_gnss_visibility_control_supported();
- private static native void native_send_ni_response(int notificationId, int userResponse);
-
// power stats APIs
private static native void native_request_power_stats();
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
index 06db6b8a38f8..ef56a1e26854 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
@@ -138,7 +138,7 @@ public class ApplicationKeyStorage {
} catch (android.security.KeyStoreException e) {
if (e.getNumericErrorCode()
== android.security.KeyStoreException.ERROR_KEY_DOES_NOT_EXIST) {
- Log.e(TAG, "Failed to get grant for KeyStore key - key not found", e);
+ Log.w(TAG, "Failed to get grant for KeyStore key - key not found");
throw new ServiceSpecificException(ERROR_KEY_NOT_FOUND, e.getMessage());
}
Log.e(TAG, "Failed to get grant for KeyStore key.", e);
diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java
index 446c4f7e335a..899287886009 100644
--- a/services/core/java/com/android/server/notification/NotificationComparator.java
+++ b/services/core/java/com/android/server/notification/NotificationComparator.java
@@ -25,7 +25,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.telecom.TelecomManager;
-import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
import com.android.internal.util.NotificationMessagingUtil;
import java.util.Comparator;
@@ -39,7 +38,6 @@ public class NotificationComparator
private final Context mContext;
private final NotificationMessagingUtil mMessagingUtil;
- private final boolean mSortByInterruptiveness;
private String mDefaultPhoneApp;
public NotificationComparator(Context context) {
@@ -47,8 +45,6 @@ public class NotificationComparator
mContext.registerReceiver(mPhoneAppBroadcastReceiver,
new IntentFilter(TelecomManager.ACTION_DEFAULT_DIALER_CHANGED));
mMessagingUtil = new NotificationMessagingUtil(mContext);
- mSortByInterruptiveness = !SystemUiSystemPropertiesFlags.getResolver().isEnabled(
- SystemUiSystemPropertiesFlags.NotificationFlags.NO_SORT_BY_INTERRUPTIVENESS);
}
@Override
@@ -139,14 +135,6 @@ public class NotificationComparator
return -1 * Integer.compare(leftPriority, rightPriority);
}
- if (mSortByInterruptiveness) {
- final boolean leftInterruptive = left.isInterruptive();
- final boolean rightInterruptive = right.isInterruptive();
- if (leftInterruptive != rightInterruptive) {
- return -1 * Boolean.compare(leftInterruptive, rightInterruptive);
- }
- }
-
// then break ties by time, most recent first
return -1 * Long.compare(left.getRankingTimeMs(), right.getRankingTimeMs());
}
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 1b5272514b63..dd3604eb02a5 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -1519,6 +1519,7 @@ public class ComputerEngine implements Computer {
ai.privateFlags = ps.getPrivateFlags();
pi.applicationInfo = PackageInfoUtils.generateDelegateApplicationInfo(
ai, flags, state, userId);
+ pi.signingInfo = ps.getSigningInfo();
if (DEBUG_PACKAGE_INFO) {
Log.v(TAG, "ps.pkg is n/a for ["
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index a5a4594ce6ac..b5ec1366fec6 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -470,7 +470,6 @@ final class DeletePackageHelper {
// We need to set it back to 'installed' so the uninstall
// broadcasts will be sent correctly.
if (DEBUG_REMOVE) Slog.d(TAG, "Not installed by other users, full delete");
- ps.setPkg(null);
ps.setInstalled(true, userId);
mPm.mSettings.writeKernelMappingLPr(ps);
clearPackageStateAndReturn = false;
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 7e1560ada784..31869b8ea0b5 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -2417,7 +2417,8 @@ final class InstallPackageHelper {
final InstallRequest installRequest = reconciledPkg.mInstallRequest;
final boolean instantApp = ((installRequest.getScanFlags() & SCAN_AS_INSTANT_APP) != 0);
final boolean isApex = ((installRequest.getScanFlags() & SCAN_AS_APEX) != 0);
- final AndroidPackage pkg = installRequest.getScannedPackageSetting().getPkg();
+ final PackageSetting ps = installRequest.getScannedPackageSetting();
+ final AndroidPackage pkg = ps.getPkg();
final String packageName = pkg.getPackageName();
final String codePath = pkg.getPath();
final boolean onIncremental = mIncrementalManager != null
@@ -2517,7 +2518,7 @@ final class InstallPackageHelper {
// Compile the layout resources.
if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts");
- mViewCompiler.compileLayouts(pkg);
+ mViewCompiler.compileLayouts(ps, pkg.getBaseApkPath());
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 12f3aa9780ea..e73eced77f2a 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -86,7 +86,10 @@ import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.os.ServiceManager;
+import android.os.ShellCallback;
+import android.os.ShellCommand;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -127,6 +130,9 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutionException;
+import java.util.function.BiConsumer;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
/**
* Service that manages requests and callbacks for launchers that support
@@ -215,7 +221,8 @@ public class LauncherAppsService extends SystemService {
final LauncherAppsServiceInternal mInternal;
- private RemoteCallbackList<IDumpCallback> mDumpCallbacks = new RemoteCallbackList<>();
+ @NonNull
+ private final RemoteCallbackList<IDumpCallback> mDumpCallbacks = new RemoteCallbackList<>();
public LauncherAppsImpl(Context context) {
mContext = context;
@@ -1462,46 +1469,124 @@ public class LauncherAppsService extends SystemService {
getActivityOptionsForLauncher(opts), user.getIdentifier());
}
+ @Override
+ public void onShellCommand(FileDescriptor in, @NonNull FileDescriptor out,
+ @NonNull FileDescriptor err, @Nullable String[] args, ShellCallback cb,
+ @Nullable ResultReceiver receiver) {
+ final int callingUid = injectBinderCallingUid();
+ if (!(callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID)) {
+ throw new SecurityException("Caller must be shell");
+ }
+
+ final long token = injectClearCallingIdentity();
+ try {
+ int status = (new LauncherAppsShellCommand())
+ .exec(this, in, out, err, args, cb, receiver);
+ if (receiver != null) {
+ receiver.send(status, null);
+ }
+ } finally {
+ injectRestoreCallingIdentity(token);
+ }
+ }
+
+ /** Handles Shell commands for LauncherAppsService */
+ private class LauncherAppsShellCommand extends ShellCommand {
+ @Override
+ public int onCommand(@Nullable String cmd) {
+ if ("dump-view-hierarchies".equals(cmd)) {
+ dumpViewCaptureDataToShell();
+ return 0;
+ } else {
+ return handleDefaultCommands(cmd);
+ }
+ }
+
+ private void dumpViewCaptureDataToShell() {
+ try (ZipOutputStream zipOs = new ZipOutputStream(getRawOutputStream())) {
+ forEachViewCaptureWindow((fileName, is) -> {
+ try {
+ zipOs.putNextEntry(new ZipEntry("FS" + fileName));
+ is.transferTo(zipOs);
+ zipOs.closeEntry();
+ } catch (IOException e) {
+ getErrPrintWriter().write("Failed to output " + fileName
+ + " data to shell: " + e.getMessage());
+ }
+ });
+ } catch (IOException e) {
+ getErrPrintWriter().write("Failed to create or close zip output stream: "
+ + e.getMessage());
+ }
+ }
+
+ @Override
+ public void onHelp() {
+ final PrintWriter pw = getOutPrintWriter();
+ pw.println("Usage: cmd launcherapps COMMAND [options ...]");
+ pw.println();
+ pw.println("cmd launcherapps dump-view-hierarchies");
+ pw.println(" Output captured view hierarchies. Files will be generated in ");
+ pw.println(" `" + WM_TRACE_DIR + "`. After pulling the data to your device,");
+ pw.println(" you can upload / visualize it at `go/winscope`.");
+ pw.println();
+ }
+ }
/**
* Using a pipe, outputs view capture data to the wmtrace dir
*/
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
+ @Nullable String[] args) {
super.dump(fd, pw, args);
// Before the wmtrace directory is picked up by dumpstate service, some processes need
// to write their data to that location. They can do that via these dumpCallbacks.
- int i = mDumpCallbacks.beginBroadcast();
- while (i > 0) {
- i--;
- dumpDataToWmTrace((String) mDumpCallbacks.getBroadcastCookie(i) + "_" + i,
- mDumpCallbacks.getBroadcastItem(i));
- }
- mDumpCallbacks.finishBroadcast();
+ forEachViewCaptureWindow(this::dumpViewCaptureDataToWmTrace);
}
- private void dumpDataToWmTrace(String name, IDumpCallback cb) {
- ParcelFileDescriptor[] pipe;
+ private void dumpViewCaptureDataToWmTrace(@NonNull String fileName,
+ @NonNull InputStream is) {
+ Path outPath = Paths.get(fileName);
try {
- pipe = ParcelFileDescriptor.createPipe();
- cb.onDump(pipe[1]);
- } catch (IOException | RemoteException e) {
- Log.d(TAG, "failed to pipe view capture data", e);
- return;
+ Files.copy(is, outPath, StandardCopyOption.REPLACE_EXISTING);
+ Files.setPosixFilePermissions(outPath, WM_TRACE_FILE_PERMISSIONS);
+ } catch (IOException e) {
+ Log.d(TAG, "failed to write data to " + fileName + " in wmtrace dir", e);
}
+ }
- Path path = Paths.get(WM_TRACE_DIR + Paths.get(name + VC_FILE_SUFFIX).getFileName());
- try (InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pipe[0])) {
- Files.copy(is, path, StandardCopyOption.REPLACE_EXISTING);
- Files.setPosixFilePermissions(path, WM_TRACE_FILE_PERMISSIONS);
- } catch (IOException e) {
- Log.d(TAG, "failed to write data to file in wmtrace dir", e);
+ /**
+ * IDumpCallback.onDump alerts the in-process ViewCapture instance to start sending data
+ * to LauncherAppsService via the pipe's input provided. This data (as well as an output
+ * file name) is provided to the consumer via an InputStream to output where it wants (for
+ * example, the winscope trace directory or the shell's stdout).
+ */
+ private void forEachViewCaptureWindow(
+ @NonNull BiConsumer<String, InputStream> outputtingConsumer) {
+ for (int i = mDumpCallbacks.beginBroadcast() - 1; i >= 0; i--) {
+ String packageName = (String) mDumpCallbacks.getBroadcastCookie(i);
+ String fileName = WM_TRACE_DIR + packageName + "_" + i + VC_FILE_SUFFIX;
+
+ try {
+ // Order is important here. OnDump needs to be called before the BiConsumer
+ // accepts & starts blocking on reading the input stream.
+ ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
+ mDumpCallbacks.getBroadcastItem(i).onDump(pipe[1]);
+
+ InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pipe[0]);
+ outputtingConsumer.accept(fileName, is);
+ is.close();
+ } catch (Exception e) {
+ Log.d(TAG, "failed to pipe view capture data", e);
+ }
}
+ mDumpCallbacks.finishBroadcast();
}
@RequiresPermission(READ_FRAME_BUFFER)
@Override
- public void registerDumpCallback(IDumpCallback cb) {
+ public void registerDumpCallback(@NonNull IDumpCallback cb) {
int status = checkCallingOrSelfPermissionForPreflight(mContext, READ_FRAME_BUFFER);
if (PERMISSION_GRANTED == status) {
String name = mContext.getPackageManager().getNameForUid(Binder.getCallingUid());
@@ -1513,7 +1598,7 @@ public class LauncherAppsService extends SystemService {
@RequiresPermission(READ_FRAME_BUFFER)
@Override
- public void unRegisterDumpCallback(IDumpCallback cb) {
+ public void unRegisterDumpCallback(@NonNull IDumpCallback cb) {
int status = checkCallingOrSelfPermissionForPreflight(mContext, READ_FRAME_BUFFER);
if (PERMISSION_GRANTED == status) {
mDumpCallbacks.unregister(cb);
diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
index 4e7521070132..82587c529e29 100644
--- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
+++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
@@ -745,6 +745,13 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
mService.setPackageStoppedState(snapshot(), packageName, stopped, userId);
}
+ @Override
+ public void notifyComponentUsed(@NonNull String packageName,
+ @UserIdInt int userId, @NonNull String recentCallingPackage) {
+ mService.notifyComponentUsed(snapshot(), packageName, userId,
+ recentCallingPackage);
+ }
+
@NonNull
@Override
@Deprecated
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 770ed8b40d2e..dc42644b04c0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4582,6 +4582,13 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
}
+ void notifyComponentUsed(@NonNull Computer snapshot, @NonNull String packageName,
+ @UserIdInt int userId, @NonNull String recentCallingPackage) {
+ PackageManagerService.this
+ .setPackageStoppedState(snapshot, packageName, false /* stopped */,
+ userId);
+ }
+
public class IPackageManagerImpl extends IPackageManagerBase {
public IPackageManagerImpl() {
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index cf4d1b0439d4..dee31ec460d7 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -20,6 +20,7 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -80,9 +81,38 @@ import java.util.UUID;
* @hide
*/
@DataClass(genGetters = true, genConstructor = false, genSetters = false, genBuilder = false)
-@DataClass.Suppress({"getSnapshot", })
+@DataClass.Suppress({"getSnapshot", "getBooleans"})
public class PackageSetting extends SettingBase implements PackageStateInternal {
+ // Use a bitset to store boolean data to save memory
+ private static class Booleans {
+ @IntDef({
+ INSTALL_PERMISSION_FIXED,
+ DEFAULT_TO_DEVICE_PROTECTED_STORAGE,
+ UPDATE_AVAILABLE,
+ FORCE_QUERYABLE_OVERRIDE
+ })
+ public @interface Flags {
+ }
+ private static final int INSTALL_PERMISSION_FIXED = 1;
+ private static final int DEFAULT_TO_DEVICE_PROTECTED_STORAGE = 1 << 1;
+ private static final int UPDATE_AVAILABLE = 1 << 2;
+ private static final int FORCE_QUERYABLE_OVERRIDE = 1 << 3;
+ }
+ private int mBooleans;
+
+ private void setBoolean(@Booleans.Flags int flag, boolean value) {
+ if (value) {
+ mBooleans |= flag;
+ } else {
+ mBooleans &= ~flag;
+ }
+ }
+
+ private boolean getBoolean(@Booleans.Flags int flag) {
+ return (mBooleans & flag) != 0;
+ }
+
/**
* The shared user ID lets us link this object to {@link SharedUserSetting}.
*/
@@ -160,8 +190,6 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
@NonNull
private PackageSignatures signatures;
- private boolean installPermissionsFixed;
-
@NonNull
private PackageKeySetData keySetData = new PackageKeySetData();
@@ -179,11 +207,6 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
/** @see PackageState#getCategoryOverride() */
private int categoryOverride = ApplicationInfo.CATEGORY_UNDEFINED;
- /** @see PackageState#isUpdateAvailable() */
- private boolean updateAvailable;
-
- private boolean forceQueryableOverride;
-
@NonNull
private final PackageStateUnserialized pkgState = new PackageStateUnserialized(this);
@@ -259,7 +282,8 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
this.mRealName = realPkgName;
}
- PackageSetting(@NonNull PackageSetting original, boolean sealedSnapshot) {
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public PackageSetting(@NonNull PackageSetting original, boolean sealedSnapshot) {
super(original);
copyPackageSetting(original, sealedSnapshot);
if (sealedSnapshot) {
@@ -363,7 +387,7 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
}
public PackageSetting setForceQueryableOverride(boolean forceQueryableOverride) {
- this.forceQueryableOverride = forceQueryableOverride;
+ setBoolean(Booleans.FORCE_QUERYABLE_OVERRIDE, forceQueryableOverride);
onChanged();
return this;
}
@@ -487,13 +511,20 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
return this;
}
+ public PackageSetting setDefaultToDeviceProtectedStorage(
+ boolean defaultToDeviceProtectedStorage) {
+ setBoolean(Booleans.DEFAULT_TO_DEVICE_PROTECTED_STORAGE, defaultToDeviceProtectedStorage);
+ onChanged();
+ return this;
+ }
+
@Override
public boolean isExternalStorage() {
return (getFlags() & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
}
public PackageSetting setUpdateAvailable(boolean updateAvailable) {
- this.updateAvailable = updateAvailable;
+ setBoolean(Booleans.UPDATE_AVAILABLE, updateAvailable);
onChanged();
return this;
}
@@ -585,7 +616,7 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
}
public PackageSetting setInstallPermissionsFixed(boolean installPermissionsFixed) {
- this.installPermissionsFixed = installPermissionsFixed;
+ setBoolean(Booleans.INSTALL_PERMISSION_FIXED, installPermissionsFixed);
return this;
}
@@ -635,6 +666,7 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
public void copyPackageSetting(PackageSetting other, boolean sealedSnapshot) {
super.copySettingBase(other);
+ mBooleans = other.mBooleans;
mSharedUserAppId = other.mSharedUserAppId;
mLoadingProgress = other.mLoadingProgress;
mLoadingCompletedTime = other.mLoadingCompletedTime;
@@ -652,13 +684,10 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
lastUpdateTime = other.lastUpdateTime;
versionCode = other.versionCode;
signatures = other.signatures;
- installPermissionsFixed = other.installPermissionsFixed;
keySetData = new PackageKeySetData(other.keySetData);
installSource = other.installSource;
volumeUuid = other.volumeUuid;
categoryOverride = other.categoryOverride;
- updateAvailable = other.updateAvailable;
- forceQueryableOverride = other.forceQueryableOverride;
mDomainSetId = other.mDomainSetId;
mAppMetadataFilePath = other.mAppMetadataFilePath;
@@ -1282,7 +1311,7 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
@NonNull
@Override
public List<SharedLibrary> getSharedLibraryDependencies() {
- return (List<SharedLibrary>) (List<?>) pkgState.getUsesLibraryInfos();
+ return Collections.unmodifiableList(pkgState.getUsesLibraryInfos());
}
@NonNull
@@ -1294,7 +1323,7 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
@NonNull
@Override
public List<String> getUsesLibraryFiles() {
- return pkgState.getUsesLibraryFiles();
+ return Collections.unmodifiableList(pkgState.getUsesLibraryFiles());
}
@NonNull
@@ -1474,6 +1503,32 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
return getAndroidPackage() != null && getAndroidPackage().isApex();
}
+ @Override
+ public boolean isForceQueryableOverride() {
+ return getBoolean(Booleans.FORCE_QUERYABLE_OVERRIDE);
+ }
+
+ /**
+ * @see PackageState#isUpdateAvailable()
+ */
+ @Override
+ public boolean isUpdateAvailable() {
+ return getBoolean(Booleans.UPDATE_AVAILABLE);
+ }
+
+ @Override
+ public boolean isInstallPermissionsFixed() {
+ return getBoolean(Booleans.INSTALL_PERMISSION_FIXED);
+ }
+
+ /**
+ * @see PackageState#isDefaultToDeviceProtectedStorage()
+ */
+ @Override
+ public boolean isDefaultToDeviceProtectedStorage() {
+ return getBoolean(Booleans.DEFAULT_TO_DEVICE_PROTECTED_STORAGE);
+ }
+
// Code below generated by codegen v1.0.23.
@@ -1576,11 +1631,6 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
}
@DataClass.Generated.Member
- public boolean isInstallPermissionsFixed() {
- return installPermissionsFixed;
- }
-
- @DataClass.Generated.Member
public @NonNull PackageKeySetData getKeySetData() {
return keySetData;
}
@@ -1606,19 +1656,6 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
return categoryOverride;
}
- /**
- * @see PackageState#isUpdateAvailable()
- */
- @DataClass.Generated.Member
- public boolean isUpdateAvailable() {
- return updateAvailable;
- }
-
- @DataClass.Generated.Member
- public boolean isForceQueryableOverride() {
- return forceQueryableOverride;
- }
-
@DataClass.Generated.Member
public @NonNull PackageStateUnserialized getPkgState() {
return pkgState;
@@ -1635,10 +1672,10 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
}
@DataClass.Generated(
- time = 1688743336932L,
+ time = 1691185420362L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/PackageSetting.java",
- inputSignatures = "private int mSharedUserAppId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set<java.lang.String> mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesSdkLibraries\nprivate @android.annotation.Nullable long[] usesSdkLibrariesVersionsMajor\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackageInternal pkg\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate float mLoadingProgress\nprivate long mLoadingCompletedTime\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate long mLastModifiedTime\nprivate long lastUpdateTime\nprivate long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate boolean installPermissionsFixed\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate int categoryOverride\nprivate boolean updateAvailable\nprivate boolean forceQueryableOverride\nprivate final @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate @android.annotation.Nullable java.lang.String mAppMetadataFilePath\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic com.android.server.pm.PackageSetting snapshot()\npublic void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic com.android.server.pm.PackageSetting setAppId(int)\npublic com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic com.android.server.pm.PackageSetting setFirstInstallTimeFromReplaced(com.android.server.pm.pkg.PackageStateInternal,int[])\npublic com.android.server.pm.PackageSetting setFirstInstallTime(long,int)\npublic com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic com.android.server.pm.PackageSetting setInstallerPackage(java.lang.String,int)\npublic com.android.server.pm.PackageSetting setUpdateOwnerPackage(java.lang.String)\npublic com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic boolean setMimeGroup(java.lang.String,android.util.ArraySet<java.lang.String>)\npublic com.android.server.pm.PackageSetting setPkg(com.android.server.pm.pkg.AndroidPackage)\npublic com.android.server.pm.PackageSetting setPkgStateLibraryFiles(java.util.Collection<java.lang.String>)\npublic com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic void setSharedUserAppId(int)\npublic @java.lang.Override int getSharedUserAppId()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override java.lang.String toString()\nprotected void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic void updateFrom(com.android.server.pm.PackageSetting)\n com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic boolean isPrivileged()\npublic boolean isOem()\npublic boolean isVendor()\npublic boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic boolean isSystemExt()\npublic boolean isOdm()\npublic boolean isSystem()\npublic android.content.pm.SigningDetails getSigningDetails()\npublic com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic void copyPackageSetting(com.android.server.pm.PackageSetting,boolean)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n void setEnabled(int,int,java.lang.String)\n int getEnabled(int)\n void setInstalled(boolean,int)\n boolean getInstalled(int)\n int getInstallReason(int)\n void setInstallReason(int,int)\n int getUninstallReason(int)\n void setUninstallReason(int,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n boolean isAnyInstalled(int[])\n int[] queryInstalledUsers(int[],boolean)\n long getCeDataInode(int)\n void setCeDataInode(long,int)\n boolean getStopped(int)\n void setStopped(boolean,int)\n boolean getNotLaunched(int)\n void setNotLaunched(boolean,int)\n boolean getHidden(int)\n void setHidden(boolean,int)\n int getDistractionFlags(int)\n void setDistractionFlags(int,int)\npublic boolean getInstantApp(int)\n void setInstantApp(boolean,int)\n boolean getVirtualPreload(int)\n void setVirtualPreload(boolean,int)\n void setUserState(int,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String,long,com.android.server.pm.pkg.ArchiveState)\n void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponents(int)\n com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponents(int)\n void setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n void setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n void setEnabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n void setDisabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n void addDisabledComponent(java.lang.String,int)\n void addEnabledComponent(java.lang.String,int)\n boolean enableComponentLPw(java.lang.String,int)\n boolean disableComponentLPw(java.lang.String,int)\n boolean restoreComponentLPw(java.lang.String,int)\n int getCurrentEnabledStateLPr(java.lang.String,int)\n void removeUser(int)\npublic int[] getNotInstalledUserIds()\n void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\nprivate static void writeArchiveState(android.util.proto.ProtoOutputStream,com.android.server.pm.pkg.ArchiveState)\n com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic void resetOverrideComponentLabelIcon(int)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic boolean isIncremental()\npublic boolean isLoading()\npublic com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic com.android.server.pm.PackageSetting setLoadingCompletedTime(long)\npublic com.android.server.pm.PackageSetting setAppMetadataFilePath(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackage getAndroidPackage()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesSdkLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesSdkLibrariesVersionsMajor()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<com.android.server.pm.pkg.SharedLibrary> getSharedLibraryDependencies()\npublic @android.annotation.NonNull com.android.server.pm.PackageSetting addUsesLibraryInfo(android.content.pm.SharedLibraryInfo)\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @android.annotation.NonNull com.android.server.pm.PackageSetting addUsesLibraryFile(java.lang.String)\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isApkInUpdatedApex()\npublic @android.annotation.Nullable @java.lang.Override java.lang.String getApexModuleName()\npublic com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set<java.lang.String>)\npublic com.android.server.pm.PackageSetting setUsesSdkLibraries(java.lang.String[])\npublic com.android.server.pm.PackageSetting setUsesSdkLibrariesVersionsMajor(long[])\npublic com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic com.android.server.pm.PackageSetting setApexModuleName(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\npublic com.android.server.pm.PackageSetting addMimeTypes(java.lang.String,java.util.Set<java.lang.String>)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserState getStateForUser(android.os.UserHandle)\npublic @android.annotation.Nullable java.lang.String getPrimaryCpuAbi()\npublic @android.annotation.Nullable java.lang.String getSecondaryCpuAbi()\npublic @android.annotation.Nullable @java.lang.Override java.lang.String getSeInfo()\npublic @android.annotation.Nullable java.lang.String getPrimaryCpuAbiLegacy()\npublic @android.annotation.Nullable java.lang.String getSecondaryCpuAbiLegacy()\npublic @android.content.pm.ApplicationInfo.HiddenApiEnforcementPolicy @java.lang.Override int getHiddenApiEnforcementPolicy()\npublic @java.lang.Override boolean isApex()\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
+ inputSignatures = "private int mBooleans\nprivate int mSharedUserAppId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set<java.lang.String> mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesSdkLibraries\nprivate @android.annotation.Nullable long[] usesSdkLibrariesVersionsMajor\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackageInternal pkg\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate float mLoadingProgress\nprivate long mLoadingCompletedTime\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate long mLastModifiedTime\nprivate long lastUpdateTime\nprivate long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate int categoryOverride\nprivate final @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate @android.annotation.Nullable java.lang.String mAppMetadataFilePath\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate void setBoolean(int,boolean)\nprivate boolean getBoolean(int)\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic com.android.server.pm.PackageSetting snapshot()\npublic void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic com.android.server.pm.PackageSetting setAppId(int)\npublic com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic com.android.server.pm.PackageSetting setFirstInstallTimeFromReplaced(com.android.server.pm.pkg.PackageStateInternal,int[])\npublic com.android.server.pm.PackageSetting setFirstInstallTime(long,int)\npublic com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic com.android.server.pm.PackageSetting setInstallerPackage(java.lang.String,int)\npublic com.android.server.pm.PackageSetting setUpdateOwnerPackage(java.lang.String)\npublic com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic boolean setMimeGroup(java.lang.String,android.util.ArraySet<java.lang.String>)\npublic com.android.server.pm.PackageSetting setPkg(com.android.server.pm.pkg.AndroidPackage)\npublic com.android.server.pm.PackageSetting setPkgStateLibraryFiles(java.util.Collection<java.lang.String>)\npublic com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic com.android.server.pm.PackageSetting setDefaultToDeviceProtectedStorage(boolean)\npublic @java.lang.Override boolean isExternalStorage()\npublic com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic void setSharedUserAppId(int)\npublic @java.lang.Override int getSharedUserAppId()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override java.lang.String toString()\nprotected void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic void updateFrom(com.android.server.pm.PackageSetting)\n com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic boolean isPrivileged()\npublic boolean isOem()\npublic boolean isVendor()\npublic boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic boolean isSystemExt()\npublic boolean isOdm()\npublic boolean isSystem()\npublic android.content.pm.SigningDetails getSigningDetails()\npublic com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic void copyPackageSetting(com.android.server.pm.PackageSetting,boolean)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n void setEnabled(int,int,java.lang.String)\n int getEnabled(int)\n void setInstalled(boolean,int)\n boolean getInstalled(int)\n int getInstallReason(int)\n void setInstallReason(int,int)\n int getUninstallReason(int)\n void setUninstallReason(int,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n boolean isAnyInstalled(int[])\n int[] queryInstalledUsers(int[],boolean)\n long getCeDataInode(int)\n void setCeDataInode(long,int)\n boolean getStopped(int)\n void setStopped(boolean,int)\n boolean getNotLaunched(int)\n void setNotLaunched(boolean,int)\n boolean getHidden(int)\n void setHidden(boolean,int)\n int getDistractionFlags(int)\n void setDistractionFlags(int,int)\npublic boolean getInstantApp(int)\n void setInstantApp(boolean,int)\n boolean getVirtualPreload(int)\n void setVirtualPreload(boolean,int)\n void setUserState(int,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String,long,int,com.android.server.pm.pkg.ArchiveState)\n void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponents(int)\n com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponents(int)\n void setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n void setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n void setEnabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n void setDisabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n void addDisabledComponent(java.lang.String,int)\n void addEnabledComponent(java.lang.String,int)\n boolean enableComponentLPw(java.lang.String,int)\n boolean disableComponentLPw(java.lang.String,int)\n boolean restoreComponentLPw(java.lang.String,int)\n int getCurrentEnabledStateLPr(java.lang.String,int)\n void removeUser(int)\npublic int[] getNotInstalledUserIds()\n void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\nprivate static void writeArchiveState(android.util.proto.ProtoOutputStream,com.android.server.pm.pkg.ArchiveState)\n com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic void resetOverrideComponentLabelIcon(int)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic boolean isIncremental()\npublic boolean isLoading()\npublic com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic com.android.server.pm.PackageSetting setLoadingCompletedTime(long)\npublic com.android.server.pm.PackageSetting setAppMetadataFilePath(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackage getAndroidPackage()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesSdkLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesSdkLibrariesVersionsMajor()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<com.android.server.pm.pkg.SharedLibrary> getSharedLibraryDependencies()\npublic @android.annotation.NonNull com.android.server.pm.PackageSetting addUsesLibraryInfo(android.content.pm.SharedLibraryInfo)\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @android.annotation.NonNull com.android.server.pm.PackageSetting addUsesLibraryFile(java.lang.String)\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isApkInUpdatedApex()\npublic @android.annotation.Nullable @java.lang.Override java.lang.String getApexModuleName()\npublic com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set<java.lang.String>)\npublic com.android.server.pm.PackageSetting setUsesSdkLibraries(java.lang.String[])\npublic com.android.server.pm.PackageSetting setUsesSdkLibrariesVersionsMajor(long[])\npublic com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic com.android.server.pm.PackageSetting setApexModuleName(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\npublic com.android.server.pm.PackageSetting addMimeTypes(java.lang.String,java.util.Set<java.lang.String>)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserState getStateForUser(android.os.UserHandle)\npublic @android.annotation.Nullable java.lang.String getPrimaryCpuAbi()\npublic @android.annotation.Nullable java.lang.String getSecondaryCpuAbi()\npublic @android.annotation.Nullable @java.lang.Override java.lang.String getSeInfo()\npublic @android.annotation.Nullable java.lang.String getPrimaryCpuAbiLegacy()\npublic @android.annotation.Nullable java.lang.String getSecondaryCpuAbiLegacy()\npublic @android.content.pm.ApplicationInfo.HiddenApiEnforcementPolicy @java.lang.Override int getHiddenApiEnforcementPolicy()\npublic @java.lang.Override boolean isApex()\npublic @java.lang.Override boolean isForceQueryableOverride()\npublic @java.lang.Override boolean isUpdateAvailable()\npublic @java.lang.Override boolean isInstallPermissionsFixed()\npublic @java.lang.Override boolean isDefaultToDeviceProtectedStorage()\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\nprivate static final int INSTALL_PERMISSION_FIXED\nprivate static final int DEFAULT_TO_DEVICE_PROTECTED_STORAGE\nprivate static final int UPDATE_AVAILABLE\nprivate static final int FORCE_QUERYABLE_OVERRIDE\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index 59314a26ab97..6d3b26cc2fd4 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -135,6 +135,7 @@ final class RemovePackageHelper {
cacher.cleanCachedResult(codePath);
}
+ // Used for system apps only
public void removePackage(AndroidPackage pkg, boolean chatty) {
synchronized (mPm.mInstallLock) {
removePackageLI(pkg, chatty);
@@ -284,6 +285,13 @@ final class RemovePackageHelper {
}
removePackageLI(deletedPs.getPackageName(), (flags & PackageManager.DELETE_CHATTY) != 0);
+ if (!deletedPs.isSystem()) {
+ // A non-system app's AndroidPackage object has been removed from the service.
+ // Explicitly nullify the corresponding app's PackageSetting's pkg object to
+ // prevent any future usage of it, in case the PackageSetting object will remain because
+ // of DELETE_KEEP_DATA.
+ deletedPs.setPkg(null);
+ }
if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
final AndroidPackage resolvedPkg;
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 1cd44e62e1f5..f4dca3fe064b 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -462,6 +462,8 @@ final class ScanPackageUtils {
+ " to " + volumeUuid);
pkgSetting.setVolumeUuid(volumeUuid);
}
+ pkgSetting.setDefaultToDeviceProtectedStorage(
+ parsedPackage.isDefaultToDeviceProtectedStorage());
SharedLibraryInfo sdkLibraryInfo = null;
if (!TextUtils.isEmpty(parsedPackage.getSdkLibraryName())) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index e5ad01f9880e..c6135e0f582e 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2914,29 +2914,28 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
FileUtils.setPermissions(fstr.getFD(), 0640, SYSTEM_UID, PACKAGE_INFO_GID);
StringBuilder sb = new StringBuilder();
- for (final PackageSetting pkg : mPackages.values()) {
+ for (final PackageSetting ps : mPackages.values()) {
// TODO(b/135203078): This doesn't handle multiple users
- final String dataPath = pkg.getPkg() == null ? null :
- PackageInfoUtils.getDataDir(pkg.getPkg(), UserHandle.USER_SYSTEM)
- .getAbsolutePath();
+ final String dataPath = PackageInfoUtils.getDataDir(ps, UserHandle.USER_SYSTEM)
+ .getAbsolutePath();
- if (pkg.getPkg() == null || dataPath == null) {
- if (!"android".equals(pkg.getPackageName())) {
- Slog.w(TAG, "Skipping " + pkg + " due to missing metadata");
+ if (ps.getPkg() == null || dataPath == null) {
+ if (!"android".equals(ps.getPackageName())) {
+ Slog.w(TAG, "Skipping " + ps + " due to missing metadata");
}
continue;
}
- if (pkg.getPkg().isApex()) {
+ if (ps.getPkg().isApex()) {
// Don't persist APEX which doesn't have a valid app id and will cause parsing
// error in libpackagelistparser
continue;
}
- final boolean isDebug = pkg.getPkg().isDebuggable();
+ final boolean isDebug = ps.getPkg().isDebuggable();
final IntArray gids = new IntArray();
for (final int userId : userIds) {
gids.addAll(mPermissionDataProvider.getGidsForUid(UserHandle.getUid(userId,
- pkg.getAppId())));
+ ps.getAppId())));
}
// Avoid any application that has a space in its path.
@@ -2964,13 +2963,13 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
// system/core/libpackagelistparser
//
sb.setLength(0);
- sb.append(pkg.getPkg().getPackageName());
+ sb.append(ps.getPkg().getPackageName());
sb.append(" ");
- sb.append(pkg.getPkg().getUid());
+ sb.append(ps.getPkg().getUid());
sb.append(isDebug ? " 1 " : " 0 ");
sb.append(dataPath);
sb.append(" ");
- sb.append(pkg.getSeInfo());
+ sb.append(ps.getSeInfo());
sb.append(" ");
final int gidsSize = gids.size();
if (gids != null && gids.size() > 0) {
@@ -2983,19 +2982,19 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
sb.append("none");
}
sb.append(" ");
- sb.append(pkg.getPkg().isProfileableByShell() ? "1" : "0");
+ sb.append(ps.getPkg().isProfileableByShell() ? "1" : "0");
sb.append(" ");
- sb.append(pkg.getPkg().getLongVersionCode());
+ sb.append(ps.getPkg().getLongVersionCode());
sb.append(" ");
- sb.append(pkg.getPkg().isProfileable() ? "1" : "0");
+ sb.append(ps.getPkg().isProfileable() ? "1" : "0");
sb.append(" ");
- if (pkg.isSystem()) {
+ if (ps.isSystem()) {
sb.append("@system");
- } else if (pkg.isProduct()) {
+ } else if (ps.isProduct()) {
sb.append("@product");
- } else if (pkg.getInstallSource().mInstallerPackageName != null
- && !pkg.getInstallSource().mInstallerPackageName.isEmpty()) {
- sb.append(pkg.getInstallSource().mInstallerPackageName);
+ } else if (ps.getInstallSource().mInstallerPackageName != null
+ && !ps.getInstallSource().mInstallerPackageName.isEmpty()) {
+ sb.append(ps.getInstallSource().mInstallerPackageName);
} else {
sb.append("@null");
}
@@ -3123,6 +3122,8 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
if (pkg.getVolumeUuid() != null) {
serializer.attribute(null, "volumeUuid", pkg.getVolumeUuid());
}
+ serializer.attributeBoolean(null, "defaultToDeviceProtectedStorage",
+ pkg.isDefaultToDeviceProtectedStorage());
if (pkg.getCategoryOverride() != ApplicationInfo.CATEGORY_UNDEFINED) {
serializer.attributeInt(null, "categoryHint", pkg.getCategoryOverride());
}
@@ -3911,6 +3912,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
String installInitiatingPackageName = null;
boolean installInitiatorUninstalled = false;
String volumeUuid = null;
+ boolean defaultToDeviceProtectedStorage = false;
boolean updateAvailable = false;
int categoryHint = ApplicationInfo.CATEGORY_UNDEFINED;
int pkgFlags = 0;
@@ -3960,6 +3962,8 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
installInitiatorUninstalled = parser.getAttributeBoolean(null,
"installInitiatorUninstalled", false);
volumeUuid = parser.getAttributeValue(null, "volumeUuid");
+ defaultToDeviceProtectedStorage = parser.getAttributeBoolean(
+ null, "defaultToDeviceProtectedStorage", false);
categoryHint = parser.getAttributeInt(null, "categoryHint",
ApplicationInfo.CATEGORY_UNDEFINED);
appMetadataFilePath = parser.getAttributeValue(null, "appMetadataFilePath");
@@ -4099,6 +4103,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
installInitiatorUninstalled);
packageSetting.setInstallSource(installSource)
.setVolumeUuid(volumeUuid)
+ .setDefaultToDeviceProtectedStorage(defaultToDeviceProtectedStorage)
.setCategoryOverride(categoryHint)
.setLegacyNativeLibraryPath(legacyNativeLibraryPathStr)
.setPrimaryCpuAbi(primaryCpuAbiString)
@@ -4886,6 +4891,8 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
pw.print("]");
}
pw.println();
+ File dataDir = PackageInfoUtils.getDataDir(ps, UserHandle.myUserId());
+ pw.print(prefix); pw.print(" dataDir="); pw.println(dataDir.getAbsolutePath());
if (pkg != null) {
pw.print(prefix); pw.print(" versionName="); pw.println(pkg.getVersionName());
pw.print(prefix); pw.print(" usesNonSdkApi="); pw.println(pkg.isNonSdkApiRequested());
@@ -4917,8 +4924,6 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
pw.append(prefix).append(" queriesIntents=")
.println(ps.getPkg().getQueriesIntents());
}
- File dataDir = PackageInfoUtils.getDataDir(pkg, UserHandle.myUserId());
- pw.print(prefix); pw.print(" dataDir="); pw.println(dataDir.getAbsolutePath());
pw.print(prefix); pw.print(" supportsScreens=[");
boolean first = true;
if (pkg.isSmallScreensSupported()) {
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index e2bbaffe5058..04d1da61f3cc 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -102,7 +102,9 @@
"include-filter": "android.appsecurity.cts.EphemeralTest#testGetSearchableInfo"
}
]
- },
+ }
+ ],
+ "presubmit-large":[
{
"name": "CtsPackageManagerTestCases",
"options": [
@@ -111,6 +113,9 @@
},
{
"exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-filter": "android.content.pm.cts.PackageManagerShellCommandMultiUserTest"
}
]
}
@@ -132,6 +137,14 @@
},
{
"name": "CtsAppEnumerationTestCases"
+ },
+ {
+ "name": "CtsPackageManagerTestCases",
+ "options": [
+ {
+ "include-filter": "android.content.pm.cts.PackageManagerShellCommandMultiUserTest"
+ }
+ ]
}
],
"imports": [
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index d88b66b412e7..31856f1630bb 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -61,7 +61,7 @@ import com.android.server.pm.PackageManagerServiceCompilerMapping;
import com.android.server.pm.PackageManagerServiceUtils;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.PackageState;
+import com.android.server.pm.pkg.PackageStateInternal;
import dalvik.system.DexFile;
import dalvik.system.VMRuntime;
@@ -542,14 +542,14 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
/**
* Compile layout resources in a given package.
*/
- public boolean compileLayouts(@NonNull PackageState packageState, @NonNull AndroidPackage pkg) {
+ public boolean compileLayouts(@NonNull PackageStateInternal ps, @NonNull AndroidPackage pkg) {
try {
final String packageName = pkg.getPackageName();
final String apkPath = pkg.getSplits().get(0).getPath();
// TODO(b/143971007): Use a cross-user directory
- File dataDir = PackageInfoUtils.getDataDir(pkg, UserHandle.myUserId());
+ File dataDir = PackageInfoUtils.getDataDir(ps, UserHandle.myUserId());
final String outDexFile = dataDir.getAbsolutePath() + "/code_cache/compiled_view.dex";
- if (packageState.isPrivileged() || pkg.isUseEmbeddedDex()
+ if (ps.isPrivileged() || pkg.isUseEmbeddedDex()
|| pkg.isDefaultToDeviceProtectedStorage()) {
// Privileged apps prefer to load trusted code so they don't use compiled views.
// If the app is not privileged but prefers code integrity, also avoid compiling
diff --git a/services/core/java/com/android/server/pm/dex/ViewCompiler.java b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
index 9ce648f12ffe..6405ea5667d3 100644
--- a/services/core/java/com/android/server/pm/dex/ViewCompiler.java
+++ b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
@@ -23,7 +23,7 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.server.pm.Installer;
import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.PackageStateInternal;
import java.io.File;
@@ -37,12 +37,11 @@ public class ViewCompiler {
mInstaller = installer;
}
- public boolean compileLayouts(AndroidPackage pkg) {
+ public boolean compileLayouts(PackageStateInternal ps, String apkPath) {
try {
- final String packageName = pkg.getPackageName();
- final String apkPath = pkg.getBaseApkPath();
+ final String packageName = ps.getPackageName();
// TODO(b/143971007): Use a cross-user directory
- File dataDir = PackageInfoUtils.getDataDir(pkg, UserHandle.myUserId());
+ File dataDir = PackageInfoUtils.getDataDir(ps, UserHandle.myUserId());
final String outDexFile = dataDir.getAbsolutePath() + "/code_cache/compiled_view.dex";
Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath +
") to " + outDexFile);
@@ -50,7 +49,7 @@ public class ViewCompiler {
try {
synchronized (mInstallLock) {
return mInstaller.compileLayouts(apkPath, packageName, outDexFile,
- pkg.getUid());
+ ps.getAppId());
}
} finally {
Binder.restoreCallingIdentity(callingId);
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index d55f85cde5af..94e959968179 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -1082,18 +1082,18 @@ public class PackageInfoUtils {
}
@NonNull
- public static File getDataDir(AndroidPackage pkg, int userId) {
- if ("android".equals(pkg.getPackageName())) {
+ public static File getDataDir(PackageStateInternal ps, int userId) {
+ if ("android".equals(ps.getPackageName())) {
return Environment.getDataSystemDirectory();
}
- if (pkg.isDefaultToDeviceProtectedStorage()
+ if (ps.isDefaultToDeviceProtectedStorage()
&& PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
- return Environment.getDataUserDePackageDirectory(pkg.getVolumeUuid(), userId,
- pkg.getPackageName());
+ return Environment.getDataUserDePackageDirectory(ps.getVolumeUuid(), userId,
+ ps.getPackageName());
} else {
- return Environment.getDataUserCePackageDirectory(pkg.getVolumeUuid(), userId,
- pkg.getPackageName());
+ return Environment.getDataUserCePackageDirectory(ps.getVolumeUuid(), userId,
+ ps.getPackageName());
}
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 789719527c8d..b01a89e672be 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -72,7 +72,6 @@ import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
-import com.android.internal.util.function.QuadFunction;
import com.android.internal.util.function.TriFunction;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerInternal;
@@ -94,6 +93,7 @@ import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.BiFunction;
/**
* Manages all permissions and handles permissions related tasks.
@@ -233,11 +233,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
if (checkPermissionDelegate == null) {
- return mPermissionManagerServiceImpl.checkPermission(packageName, permissionName,
- deviceId, userId);
+ return mPermissionManagerServiceImpl.checkPermission(
+ packageName, permissionName, userId);
}
- return checkPermissionDelegate.checkPermission(packageName, permissionName,
- deviceId, userId, mPermissionManagerServiceImpl::checkPermission);
+ return checkPermissionDelegate.checkPermission(packageName, permissionName, userId,
+ mPermissionManagerServiceImpl::checkPermission);
}
@Override
@@ -254,10 +254,10 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
if (checkPermissionDelegate == null) {
- return mPermissionManagerServiceImpl.checkUidPermission(uid, permissionName, deviceId);
+ return mPermissionManagerServiceImpl.checkUidPermission(uid, permissionName);
}
return checkPermissionDelegate.checkUidPermission(uid, permissionName,
- deviceId, mPermissionManagerServiceImpl::checkUidPermission);
+ mPermissionManagerServiceImpl::checkUidPermission);
}
@Override
@@ -511,14 +511,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
public int getPermissionFlags(String packageName, String permissionName, int deviceId,
int userId) {
return mPermissionManagerServiceImpl
- .getPermissionFlags(packageName, permissionName, deviceId, userId);
+ .getPermissionFlags(packageName, permissionName, userId);
}
@Override
public void updatePermissionFlags(String packageName, String permissionName, int flagMask,
int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId, int userId) {
mPermissionManagerServiceImpl.updatePermissionFlags(packageName, permissionName, flagMask,
- flagValues, checkAdjustPolicyFlagPermission, deviceId, userId);
+ flagValues, checkAdjustPolicyFlagPermission, userId);
}
@Override
@@ -560,15 +560,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@Override
public void grantRuntimePermission(String packageName, String permissionName, int deviceId,
int userId) {
- mPermissionManagerServiceImpl.grantRuntimePermission(packageName, permissionName,
- deviceId, userId);
+ mPermissionManagerServiceImpl.grantRuntimePermission(packageName, permissionName, userId);
}
@Override
public void revokeRuntimePermission(String packageName, String permissionName, int deviceId,
int userId, String reason) {
mPermissionManagerServiceImpl.revokeRuntimePermission(packageName, permissionName,
- deviceId, userId, reason);
+ userId, reason);
}
@Override
@@ -581,14 +580,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
public boolean shouldShowRequestPermissionRationale(String packageName, String permissionName,
int deviceId, int userId) {
return mPermissionManagerServiceImpl.shouldShowRequestPermissionRationale(packageName,
- permissionName, deviceId, userId);
+ permissionName, userId);
}
@Override
public boolean isPermissionRevokedByPolicy(String packageName, String permissionName,
int deviceId, int userId) {
- return mPermissionManagerServiceImpl.isPermissionRevokedByPolicy(packageName,
- permissionName, deviceId, userId);
+ return mPermissionManagerServiceImpl
+ .isPermissionRevokedByPolicy(packageName, permissionName, userId);
}
@Override
@@ -869,7 +868,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
*
* @param packageName the name of the package to be checked
* @param permissionName the name of the permission to be checked
- * @param deviceId The device ID
* @param userId the user ID
* @param superImpl the original implementation that can be delegated to
* @return {@link android.content.pm.PackageManager#PERMISSION_GRANTED} if the package has
@@ -878,21 +876,20 @@ public class PermissionManagerService extends IPermissionManager.Stub {
* @see android.content.pm.PackageManager#checkPermission(String, String)
*/
int checkPermission(@NonNull String packageName, @NonNull String permissionName,
- int deviceId, @UserIdInt int userId,
- @NonNull QuadFunction<String, String, Integer, Integer, Integer> superImpl);
+ @UserIdInt int userId,
+ @NonNull TriFunction<String, String, Integer, Integer> superImpl);
/**
* Check whether the given UID has been granted the specified permission.
*
* @param uid the UID to be checked
* @param permissionName the name of the permission to be checked
- * @param deviceId The device ID
* @param superImpl the original implementation that can be delegated to
* @return {@link android.content.pm.PackageManager#PERMISSION_GRANTED} if the package has
* the permission, or {@link android.content.pm.PackageManager#PERMISSION_DENIED} otherwise
*/
- int checkUidPermission(int uid, @NonNull String permissionName, int deviceId,
- TriFunction<Integer, String, Integer, Integer> superImpl);
+ int checkUidPermission(int uid, @NonNull String permissionName,
+ BiFunction<Integer, String, Integer> superImpl);
/**
* @return list of delegated permissions
@@ -921,32 +918,31 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@Override
public int checkPermission(@NonNull String packageName, @NonNull String permissionName,
- int deviceId, int userId,
- @NonNull QuadFunction<String, String, Integer, Integer, Integer> superImpl) {
+ int userId, @NonNull TriFunction<String, String, Integer, Integer> superImpl) {
if (mDelegatedPackageName.equals(packageName)
&& isDelegatedPermission(permissionName)) {
final long identity = Binder.clearCallingIdentity();
try {
- return superImpl.apply("com.android.shell", permissionName, deviceId, userId);
+ return superImpl.apply("com.android.shell", permissionName, userId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
- return superImpl.apply(packageName, permissionName, deviceId, userId);
+ return superImpl.apply(packageName, permissionName, userId);
}
@Override
- public int checkUidPermission(int uid, @NonNull String permissionName, int deviceId,
- @NonNull TriFunction<Integer, String, Integer, Integer> superImpl) {
+ public int checkUidPermission(int uid, @NonNull String permissionName,
+ @NonNull BiFunction<Integer, String, Integer> superImpl) {
if (uid == mDelegatedUid && isDelegatedPermission(permissionName)) {
final long identity = Binder.clearCallingIdentity();
try {
- return superImpl.apply(Process.SHELL_UID, permissionName, deviceId);
+ return superImpl.apply(Process.SHELL_UID, permissionName);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
- return superImpl.apply(uid, permissionName, deviceId);
+ return superImpl.apply(uid, permissionName);
}
@Override
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 6764e087ff04..4353c5787d4b 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -681,7 +681,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
@Override
- public int getPermissionFlags(String packageName, String permName, int deviceId, int userId) {
+ public int getPermissionFlags(String packageName, String permName, int userId) {
final int callingUid = Binder.getCallingUid();
return getPermissionFlagsInternal(packageName, permName, callingUid, userId);
}
@@ -724,7 +724,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
@Override
public void updatePermissionFlags(String packageName, String permName, int flagMask,
- int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId, int userId) {
+ int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
final int callingUid = Binder.getCallingUid();
boolean overridePolicy = false;
@@ -908,12 +908,8 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
}
- private int checkPermission(String pkgName, String permName, int userId) {
- return checkPermission(pkgName, permName, Context.DEVICE_ID_DEFAULT, userId);
- }
-
@Override
- public int checkPermission(String pkgName, String permName, int deviceId, int userId) {
+ public int checkPermission(String pkgName, String permName, int userId) {
if (!mUserManagerInt.exists(userId)) {
return PackageManager.PERMISSION_DENIED;
}
@@ -979,12 +975,8 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
return true;
}
- private int checkUidPermission(int uid, String permName) {
- return checkUidPermission(uid, permName, Context.DEVICE_ID_DEFAULT);
- }
-
@Override
- public int checkUidPermission(int uid, String permName, int deviceId) {
+ public int checkUidPermission(int uid, String permName) {
final int userId = UserHandle.getUserId(uid);
if (!mUserManagerInt.exists(userId)) {
return PackageManager.PERMISSION_DENIED;
@@ -1303,8 +1295,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
@Override
- public void grantRuntimePermission(String packageName, String permName, int deviceId,
- int userId) {
+ public void grantRuntimePermission(String packageName, String permName, final int userId) {
final int callingUid = Binder.getCallingUid();
final boolean overridePolicy =
checkUidPermission(callingUid, ADJUST_RUNTIME_PERMISSIONS_POLICY)
@@ -1477,11 +1468,11 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
@Override
- public void revokeRuntimePermission(String packageName, String permName, int deviceId,
- int userId, String reason) {
+ public void revokeRuntimePermission(String packageName, String permName, int userId,
+ String reason) {
final int callingUid = Binder.getCallingUid();
final boolean overridePolicy =
- checkUidPermission(callingUid, ADJUST_RUNTIME_PERMISSIONS_POLICY, deviceId)
+ checkUidPermission(callingUid, ADJUST_RUNTIME_PERMISSIONS_POLICY)
== PackageManager.PERMISSION_GRANTED;
revokeRuntimePermissionInternal(packageName, permName, overridePolicy, callingUid, userId,
@@ -1868,7 +1859,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
@Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
- int deviceId, @UserIdInt int userId) {
+ @UserIdInt int userId) {
final int callingUid = Binder.getCallingUid();
if (UserHandle.getCallingUserId() != userId) {
mContext.enforceCallingPermission(
@@ -1931,8 +1922,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
@Override
- public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
- int userId) {
+ public boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId) {
if (UserHandle.getCallingUserId() != userId) {
mContext.enforceCallingPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
@@ -2069,8 +2059,8 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
continue;
}
boolean isSystemOrPolicyFixed = (getPermissionFlags(newPackage.getPackageName(),
- permInfo.name, Context.DEVICE_ID_DEFAULT, userId) & (
- FLAG_PERMISSION_SYSTEM_FIXED | FLAG_PERMISSION_POLICY_FIXED)) != 0;
+ permInfo.name, userId) & (FLAG_PERMISSION_SYSTEM_FIXED
+ | FLAG_PERMISSION_POLICY_FIXED)) != 0;
if (isSystemOrPolicyFixed) {
continue;
}
@@ -2236,8 +2226,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
for (final int userId : userIds) {
final int permissionState = checkPermission(packageName, permName,
userId);
- final int flags = getPermissionFlags(packageName, permName,
- Context.DEVICE_ID_DEFAULT, userId);
+ final int flags = getPermissionFlags(packageName, permName, userId);
final int flagMask = FLAG_PERMISSION_SYSTEM_FIXED
| FLAG_PERMISSION_POLICY_FIXED
| FLAG_PERMISSION_GRANTED_BY_DEFAULT
@@ -5133,7 +5122,8 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
@NonNull
@Override
- public Set<String> getGrantedPermissions(@NonNull String packageName, @UserIdInt int userId) {
+ public Set<String> getGrantedPermissions(@NonNull String packageName,
+ @UserIdInt int userId) {
Objects.requireNonNull(packageName, "packageName");
Preconditions.checkArgumentNonNegative(userId, "userId");
return getGrantedPermissionsInternal(packageName, userId);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 2d824aa1ba13..128f847715ab 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -25,6 +25,7 @@ import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.permission.IOnPermissionsChangeListener;
+import android.permission.PermissionManager;
import android.permission.PermissionManagerInternal;
import com.android.server.pm.pkg.AndroidPackage;
@@ -136,16 +137,14 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
void removePermission(String permName);
/**
- * Gets the permission state flags associated with a permission.
+ * Gets the state flags associated with a permission.
*
* @param packageName the package name for which to get the flags
* @param permName the permission for which to get the flags
- * @param deviceId The device for which to get the flags
* @param userId the user for which to get permission flags
* @return the permission flags
*/
- int getPermissionFlags(String packageName, String permName, int deviceId,
- @UserIdInt int userId);
+ int getPermissionFlags(String packageName, String permName, int userId);
/**
* Updates the flags associated with a permission by replacing the flags in the specified mask
@@ -155,11 +154,10 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
* @param permName The permission for which to update the flags
* @param flagMask The flags which to replace
* @param flagValues The flags with which to replace
- * @param deviceId The device for which to update the permission flags
* @param userId The user for which to update the permission flags
*/
- void updatePermissionFlags(String packageName, String permName, int flagMask, int flagValues,
- boolean checkAdjustPolicyFlagPermission, int deviceId, @UserIdInt int userId);
+ void updatePermissionFlags(String packageName, String permName, int flagMask,
+ int flagValues, boolean checkAdjustPolicyFlagPermission, int userId);
/**
* Update the permission flags for all packages and runtime permissions of a user in order
@@ -293,13 +291,11 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
*
* @param packageName the package to which to grant the permission
* @param permName the permission name to grant
- * @param deviceId the device for which to grant the permission
* @param userId the user for which to grant the permission
*
- * @see #revokeRuntimePermission(String, String, int, int, String)
+ * @see #revokeRuntimePermission(String, String, android.os.UserHandle, String)
*/
- void grantRuntimePermission(String packageName, String permName, int deviceId,
- @UserIdInt int userId);
+ void grantRuntimePermission(String packageName, String permName, int userId);
/**
* Revoke a runtime permission that was previously granted by
@@ -314,14 +310,13 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
*
* @param packageName the package from which to revoke the permission
* @param permName the permission name to revoke
- * @param deviceId the device for which to revoke the permission
* @param userId the user for which to revoke the permission
* @param reason the reason for the revoke, or {@code null} for unspecified
*
- * @see #grantRuntimePermission(String, String, int, int)
+ * @see #grantRuntimePermission(String, String, android.os.UserHandle)
*/
- void revokeRuntimePermission(String packageName, String permName, int deviceId,
- @UserIdInt int userId, String reason);
+ void revokeRuntimePermission(String packageName, String permName, int userId,
+ String reason);
/**
* Revoke the POST_NOTIFICATIONS permission, without killing the app. This method must ONLY BE
@@ -338,29 +333,24 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
* does not clearly communicate to the user what would be the benefit from grating this
* permission.
*
- * @param packageName the package name
* @param permName a permission your app wants to request
- * @param deviceId the device for which to check the permission
- * @param userId the user for which to check the permission
* @return whether you can show permission rationale UI
*/
boolean shouldShowRequestPermissionRationale(String packageName, String permName,
- int deviceId, @UserIdInt int userId);
+ @UserIdInt int userId);
/**
- * Checks whether a particular permission has been revoked for a package by policy. Typically,
+ * Checks whether a particular permissions has been revoked for a package by policy. Typically
* the device owner or the profile owner may apply such a policy. The user cannot grant policy
* revoked permissions, hence the only way for an app to get such a permission is by a policy
* change.
*
* @param packageName the name of the package you are checking against
* @param permName the name of the permission you are checking for
- * @param deviceId the device for which you are checking the permission
- * @param userId the device for which you are checking the permission
+ *
* @return whether the permission is restricted by policy
*/
- boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
- @UserIdInt int userId);
+ boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId);
/**
* Get set of permissions that have been split into more granular or dependent permissions.
@@ -383,25 +373,14 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
List<SplitPermissionInfoParcelable> getSplitPermissions();
/**
- * Check whether a permission is granted or not to a package.
- *
- * @param pkgName package name
- * @param permName permission name
- * @param deviceId device ID
- * @param userId user ID
- * @return permission result {@link PackageManager.PermissionResult}
+ * TODO:theianchen add doc describing this is the old checkPermissionImpl
*/
- int checkPermission(String pkgName, String permName, int deviceId, @UserIdInt int userId);
+ int checkPermission(String pkgName, String permName, int userId);
/**
- * Check whether a permission is granted or not to an UID.
- *
- * @param uid UID
- * @param permName permission name
- * @param deviceId device ID
- * @return permission result {@link PackageManager.PermissionResult}
+ * TODO:theianchen add doc describing this is the old checkUidPermissionImpl
*/
- int checkUidPermission(int uid, String permName, int deviceId);
+ int checkUidPermission(int uid, String permName);
/**
* Get all the package names requesting app op permissions.
@@ -421,11 +400,15 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
@UserIdInt int userId);
/**
- * Reset the runtime permission state changes for a package for all devices.
+ * Reset the runtime permission state changes for a package.
*
* TODO(zhanghai): Turn this into package change callback?
+ *
+ * @param pkg the package
+ * @param userId the user ID
*/
- void resetRuntimePermissions(@NonNull AndroidPackage pkg, @UserIdInt int userId);
+ void resetRuntimePermissions(@NonNull AndroidPackage pkg,
+ @UserIdInt int userId);
/**
* Reset the runtime permission state changes for all packages in a user.
@@ -466,8 +449,8 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
/**
* Get all the permissions granted to a package.
*
- * @param packageName package name
- * @param userId user ID
+ * @param packageName the name of the package
+ * @param userId the user ID
* @return the names of the granted permissions
*/
@NonNull
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
index dacb8c6890a0..7f98e2163178 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceLoggingDecorator.java
@@ -120,21 +120,21 @@ public class PermissionManagerServiceLoggingDecorator implements PermissionManag
}
@Override
- public int getPermissionFlags(String packageName, String permName, int deviceId, int userId) {
+ public int getPermissionFlags(String packageName, String permName, int userId) {
Log.i(LOG_TAG, "getPermissionFlags(packageName = " + packageName + ", permName = "
- + permName + ", deviceId = " + deviceId + ", userId = " + userId + ")");
- return mService.getPermissionFlags(packageName, permName, deviceId, userId);
+ + permName + ", userId = " + userId + ")");
+ return mService.getPermissionFlags(packageName, permName, userId);
}
@Override
public void updatePermissionFlags(String packageName, String permName, int flagMask,
- int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId, int userId) {
+ int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
Log.i(LOG_TAG, "updatePermissionFlags(packageName = " + packageName + ", permName = "
+ permName + ", flagMask = " + flagMask + ", flagValues = " + flagValues
+ ", checkAdjustPolicyFlagPermission = " + checkAdjustPolicyFlagPermission
- + ", deviceId = " + deviceId + ", userId = " + userId + ")");
+ + ", userId = " + userId + ")");
mService.updatePermissionFlags(packageName, permName, flagMask, flagValues,
- checkAdjustPolicyFlagPermission, deviceId, userId);
+ checkAdjustPolicyFlagPermission, userId);
}
@Override
@@ -182,20 +182,18 @@ public class PermissionManagerServiceLoggingDecorator implements PermissionManag
}
@Override
- public void grantRuntimePermission(String packageName, String permName, int deviceId,
- int userId) {
+ public void grantRuntimePermission(String packageName, String permName, int userId) {
Log.i(LOG_TAG, "grantRuntimePermission(packageName = " + packageName + ", permName = "
- + permName + ", deviceId = " + deviceId + ", userId = " + userId + ")");
- mService.grantRuntimePermission(packageName, permName, deviceId, userId);
+ + permName + ", userId = " + userId + ")");
+ mService.grantRuntimePermission(packageName, permName, userId);
}
@Override
- public void revokeRuntimePermission(String packageName, String permName, int deviceId,
- int userId, String reason) {
+ public void revokeRuntimePermission(String packageName, String permName, int userId,
+ String reason) {
Log.i(LOG_TAG, "revokeRuntimePermission(packageName = " + packageName + ", permName = "
- + permName + ", deviceId = " + deviceId + ", userId = " + userId
- + ", reason = " + reason + ")");
- mService.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
+ + permName + ", userId = " + userId + ", reason = " + reason + ")");
+ mService.revokeRuntimePermission(packageName, permName, userId, reason);
}
@Override
@@ -207,20 +205,17 @@ public class PermissionManagerServiceLoggingDecorator implements PermissionManag
@Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
- int deviceId, int userId) {
+ int userId) {
Log.i(LOG_TAG, "shouldShowRequestPermissionRationale(packageName = " + packageName
- + ", permName = " + permName + ", deviceId = " + deviceId
- + ", userId = " + userId + ")");
- return mService.shouldShowRequestPermissionRationale(packageName, permName, deviceId,
- userId);
+ + ", permName = " + permName + ", userId = " + userId + ")");
+ return mService.shouldShowRequestPermissionRationale(packageName, permName, userId);
}
@Override
- public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
- int userId) {
+ public boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId) {
Log.i(LOG_TAG, "isPermissionRevokedByPolicy(packageName = " + packageName + ", permName = "
- + permName + ", deviceId = " + deviceId + ", userId = " + userId + ")");
- return mService.isPermissionRevokedByPolicy(packageName, permName, deviceId, userId);
+ + permName + ", userId = " + userId + ")");
+ return mService.isPermissionRevokedByPolicy(packageName, permName, userId);
}
@Override
@@ -230,17 +225,16 @@ public class PermissionManagerServiceLoggingDecorator implements PermissionManag
}
@Override
- public int checkPermission(String pkgName, String permName, int deviceId, int userId) {
+ public int checkPermission(String pkgName, String permName, int userId) {
Log.i(LOG_TAG, "checkPermission(pkgName = " + pkgName + ", permName = " + permName
- + ", deviceId = " + deviceId + ", userId = " + userId + ")");
- return mService.checkPermission(pkgName, permName, deviceId, userId);
+ + ", userId = " + userId + ")");
+ return mService.checkPermission(pkgName, permName, userId);
}
@Override
- public int checkUidPermission(int uid, String permName, int deviceId) {
- Log.i(LOG_TAG, "checkUidPermission(uid = " + uid + ", permName = " + permName
- + ", deviceId = " + deviceId + ")");
- return mService.checkUidPermission(uid, permName, deviceId);
+ public int checkUidPermission(int uid, String permName) {
+ Log.i(LOG_TAG, "checkUidPermission(uid = " + uid + ", permName = " + permName + ")");
+ return mService.checkUidPermission(uid, permName);
}
@Override
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
index 35d165b9b54a..d4c6d42deeaa 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTestingShim.java
@@ -153,10 +153,9 @@ public class PermissionManagerServiceTestingShim implements PermissionManagerSer
}
@Override
- public int getPermissionFlags(String packageName, String permName, int deviceId,
- @UserIdInt int userId) {
- int oldVal = mOldImplementation.getPermissionFlags(packageName, permName, deviceId, userId);
- int newVal = mNewImplementation.getPermissionFlags(packageName, permName, deviceId, userId);
+ public int getPermissionFlags(String packageName, String permName, int userId) {
+ int oldVal = mOldImplementation.getPermissionFlags(packageName, permName, userId);
+ int newVal = mNewImplementation.getPermissionFlags(packageName, permName, userId);
if (!Objects.equals(oldVal, newVal)) {
signalImplDifference("getPermissionFlags");
@@ -166,12 +165,11 @@ public class PermissionManagerServiceTestingShim implements PermissionManagerSer
@Override
public void updatePermissionFlags(String packageName, String permName, int flagMask,
- int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId,
- @UserIdInt int userId) {
+ int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
mOldImplementation.updatePermissionFlags(packageName, permName, flagMask, flagValues,
- checkAdjustPolicyFlagPermission, deviceId, userId);
+ checkAdjustPolicyFlagPermission, userId);
mNewImplementation.updatePermissionFlags(packageName, permName, flagMask, flagValues,
- checkAdjustPolicyFlagPermission, deviceId, userId);
+ checkAdjustPolicyFlagPermission, userId);
}
@Override
@@ -236,17 +234,16 @@ public class PermissionManagerServiceTestingShim implements PermissionManagerSer
}
@Override
- public void grantRuntimePermission(String packageName, String permName, int deviceId,
- @UserIdInt int userId) {
- mOldImplementation.grantRuntimePermission(packageName, permName, deviceId, userId);
- mNewImplementation.grantRuntimePermission(packageName, permName, deviceId, userId);
+ public void grantRuntimePermission(String packageName, String permName, int userId) {
+ mOldImplementation.grantRuntimePermission(packageName, permName, userId);
+ mNewImplementation.grantRuntimePermission(packageName, permName, userId);
}
@Override
- public void revokeRuntimePermission(String packageName, String permName, int deviceId,
- @UserIdInt int userId, String reason) {
- mOldImplementation.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
- mNewImplementation.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
+ public void revokeRuntimePermission(String packageName, String permName, int userId,
+ String reason) {
+ mOldImplementation.grantRuntimePermission(packageName, permName, userId);
+ mNewImplementation.grantRuntimePermission(packageName, permName, userId);
}
@Override
@@ -258,11 +255,11 @@ public class PermissionManagerServiceTestingShim implements PermissionManagerSer
@Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
- int deviceId, @UserIdInt int userId) {
- boolean oldVal = mOldImplementation.shouldShowRequestPermissionRationale(packageName,
- permName, deviceId, userId);
- boolean newVal = mNewImplementation.shouldShowRequestPermissionRationale(packageName,
- permName, deviceId, userId);
+ int userId) {
+ boolean oldVal = mOldImplementation
+ .shouldShowRequestPermissionRationale(packageName, permName, userId);
+ boolean newVal = mNewImplementation
+ .shouldShowRequestPermissionRationale(packageName, permName, userId);
if (!Objects.equals(oldVal, newVal)) {
signalImplDifference("shouldShowRequestPermissionRationale");
@@ -271,12 +268,11 @@ public class PermissionManagerServiceTestingShim implements PermissionManagerSer
}
@Override
- public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
- @UserIdInt int userId) {
- boolean oldVal = mOldImplementation.isPermissionRevokedByPolicy(packageName, permName,
- deviceId, userId);
+ public boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId) {
+ boolean oldVal = mOldImplementation
+ .isPermissionRevokedByPolicy(packageName, permName, userId);
boolean newVal = mNewImplementation.isPermissionRevokedByPolicy(packageName, permName,
- deviceId, userId);
+ userId);
if (!Objects.equals(oldVal, newVal)) {
signalImplDifference("isPermissionRevokedByPolicy");
@@ -296,9 +292,9 @@ public class PermissionManagerServiceTestingShim implements PermissionManagerSer
}
@Override
- public int checkPermission(String pkgName, String permName, int deviceId, int userId) {
- int oldVal = mOldImplementation.checkPermission(pkgName, permName, deviceId, userId);
- int newVal = mNewImplementation.checkPermission(pkgName, permName, deviceId, userId);
+ public int checkPermission(String pkgName, String permName, int userId) {
+ int oldVal = mOldImplementation.checkPermission(pkgName, permName, userId);
+ int newVal = mNewImplementation.checkPermission(pkgName, permName, userId);
if (!Objects.equals(oldVal, newVal)) {
signalImplDifference("checkPermission");
@@ -307,9 +303,9 @@ public class PermissionManagerServiceTestingShim implements PermissionManagerSer
}
@Override
- public int checkUidPermission(int uid, String permName, int deviceId) {
- int oldVal = mOldImplementation.checkUidPermission(uid, permName, deviceId);
- int newVal = mNewImplementation.checkUidPermission(uid, permName, deviceId);
+ public int checkUidPermission(int uid, String permName) {
+ int oldVal = mOldImplementation.checkUidPermission(uid, permName);
+ int newVal = mNewImplementation.checkUidPermission(uid, permName);
if (!Objects.equals(oldVal, newVal)) {
signalImplDifference("checkUidPermission");
@@ -376,7 +372,7 @@ public class PermissionManagerServiceTestingShim implements PermissionManagerSer
@NonNull
@Override
- public Set<String> getGrantedPermissions(@NonNull String packageName, @UserIdInt int userId) {
+ public Set<String> getGrantedPermissions(@NonNull String packageName, int userId) {
Set<String> oldVal = mOldImplementation.getGrantedPermissions(packageName, userId);
Set<String> newVal = mNewImplementation.getGrantedPermissions(packageName, userId);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
index cbeede0f425c..4e72fae99c9c 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceTracingDecorator.java
@@ -158,10 +158,10 @@ public class PermissionManagerServiceTracingDecorator implements PermissionManag
}
@Override
- public int getPermissionFlags(String packageName, String permName, int deviceId, int userId) {
+ public int getPermissionFlags(String packageName, String permName, int userId) {
Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#getPermissionFlags");
try {
- return mService.getPermissionFlags(packageName, permName, deviceId, userId);
+ return mService.getPermissionFlags(packageName, permName, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
@@ -169,12 +169,12 @@ public class PermissionManagerServiceTracingDecorator implements PermissionManag
@Override
public void updatePermissionFlags(String packageName, String permName, int flagMask,
- int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId, int userId) {
+ int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#updatePermissionFlags");
try {
mService.updatePermissionFlags(packageName, permName, flagMask, flagValues,
- checkAdjustPolicyFlagPermission, deviceId, userId);
+ checkAdjustPolicyFlagPermission, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
@@ -253,24 +253,23 @@ public class PermissionManagerServiceTracingDecorator implements PermissionManag
}
@Override
- public void grantRuntimePermission(String packageName, String permName, int deviceId,
- int userId) {
+ public void grantRuntimePermission(String packageName, String permName, int userId) {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#grantRuntimePermission");
try {
- mService.grantRuntimePermission(packageName, permName, deviceId, userId);
+ mService.grantRuntimePermission(packageName, permName, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
}
@Override
- public void revokeRuntimePermission(String packageName, String permName, int deviceId,
- int userId, String reason) {
+ public void revokeRuntimePermission(String packageName, String permName, int userId,
+ String reason) {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#revokeRuntimePermission");
try {
- mService.revokeRuntimePermission(packageName, permName, deviceId, userId, reason);
+ mService.revokeRuntimePermission(packageName, permName, userId, reason);
} finally {
Trace.traceEnd(TRACE_TAG);
}
@@ -289,24 +288,22 @@ public class PermissionManagerServiceTracingDecorator implements PermissionManag
@Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permName,
- int deviceId, int userId) {
+ int userId) {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#shouldShowRequestPermissionRationale");
try {
- return mService.shouldShowRequestPermissionRationale(
- packageName, permName, deviceId, userId);
+ return mService.shouldShowRequestPermissionRationale(packageName, permName, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
}
@Override
- public boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,
- int userId) {
+ public boolean isPermissionRevokedByPolicy(String packageName, String permName, int userId) {
Trace.traceBegin(TRACE_TAG,
"TaggedTracingPermissionManagerServiceImpl#isPermissionRevokedByPolicy");
try {
- return mService.isPermissionRevokedByPolicy(packageName, permName, deviceId, userId);
+ return mService.isPermissionRevokedByPolicy(packageName, permName, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
@@ -324,20 +321,20 @@ public class PermissionManagerServiceTracingDecorator implements PermissionManag
}
@Override
- public int checkPermission(String pkgName, String permName, int deviceId, int userId) {
+ public int checkPermission(String pkgName, String permName, int userId) {
Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#checkPermission");
try {
- return mService.checkPermission(pkgName, permName, deviceId, userId);
+ return mService.checkPermission(pkgName, permName, userId);
} finally {
Trace.traceEnd(TRACE_TAG);
}
}
@Override
- public int checkUidPermission(int uid, String permName, int deviceId) {
+ public int checkUidPermission(int uid, String permName) {
Trace.traceBegin(TRACE_TAG, "TaggedTracingPermissionManagerServiceImpl#checkUidPermission");
try {
- return mService.checkUidPermission(uid, permName, deviceId);
+ return mService.checkUidPermission(uid, permName);
} finally {
Trace.traceEnd(TRACE_TAG);
}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageState.java b/services/core/java/com/android/server/pm/pkg/PackageState.java
index 2c37876dd261..3f347e465f81 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageState.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageState.java
@@ -59,11 +59,6 @@ import java.util.Set;
public interface PackageState {
/*
- * Until immutability or read-only caching is enabled, {@link PackageSetting} cannot be
- * returned directly, so {@link PackageStateImpl} is used to temporarily copy the data.
- * This is a relatively expensive operation since it has to create an object for every package,
- * but it's much lighter than the alternative of generating {@link PackageInfo} objects.
- * <p>
* TODO: Documentation
* TODO: Currently missing, should be exposed as API?
* - keySetData
@@ -350,6 +345,12 @@ public interface PackageState {
String getVolumeUuid();
/**
+ * @see AndroidPackage#isDefaultToDeviceProtectedStorage()
+ * @hide
+ */
+ boolean isDefaultToDeviceProtectedStorage();
+
+ /**
* @see AndroidPackage#isExternalStorage()
* @hide
*/
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
deleted file mode 100644
index ba274e046b47..000000000000
--- a/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
+++ /dev/null
@@ -1,759 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm.pkg;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
-import android.content.pm.SigningInfo;
-import android.content.pm.overlay.OverlayPaths;
-import android.os.UserHandle;
-import android.util.ArraySet;
-import android.util.SparseArray;
-
-import com.android.internal.util.DataClass;
-import com.android.server.pm.PackageManagerService;
-import com.android.server.pm.PackageSetting;
-import com.android.server.pm.Settings;
-
-import java.io.File;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Consumer;
-
-/**
- * Because a {@link PackageSetting} cannot be returned from {@link Settings} without holding the
- * {@link PackageManagerService#mLock}, this class serves as a memory snapshot of the state of a
- * single package, for use with {@link PackageManagerInternal#getPackageState(String)} and {@link
- * PackageManagerInternal#forEachPackageState(boolean, Consumer)}.
- *
- * @hide
- */
-@DataClass(genConstructor = false)
-@DataClass.Suppress({"mUserStates"})
-public class PackageStateImpl implements PackageState {
-
- public static PackageState copy(@NonNull PackageStateInternal pkgSetting) {
- return new PackageStateImpl(pkgSetting, pkgSetting.getPkg());
- }
-
- private static class Booleans {
- @IntDef({
- SYSTEM,
- EXTERNAL_STORAGE,
- PRIVILEGED,
- OEM,
- VENDOR,
- PRODUCT,
- SYSTEM_EXT,
- REQUIRED_FOR_SYSTEM_USER,
- ODM,
- FORCE_QUERYABLE_OVERRIDE,
- HIDDEN_UNTIL_INSTALLED,
- INSTALL_PERMISSIONS_FIXED,
- UPDATE_AVAILABLE,
- UPDATED_SYSTEM_APP,
- APK_IN_UPDATED_APEX,
- })
- public @interface Flags {
- }
-
- private static final int SYSTEM = 1;
- private static final int EXTERNAL_STORAGE = 1 << 1;
- private static final int PRIVILEGED = 1 << 2;
- private static final int OEM = 1 << 3;
- private static final int VENDOR = 1 << 4;
- private static final int PRODUCT = 1 << 5;
- private static final int SYSTEM_EXT = 1 << 6;
- private static final int REQUIRED_FOR_SYSTEM_USER = 1 << 7;
- private static final int ODM = 1 << 8;
- private static final int FORCE_QUERYABLE_OVERRIDE = 1 << 9;
- private static final int HIDDEN_UNTIL_INSTALLED = 1 << 10;
- private static final int INSTALL_PERMISSIONS_FIXED = 1 << 11;
- private static final int UPDATE_AVAILABLE = 1 << 12;
- private static final int UPDATED_SYSTEM_APP = 1 << 13;
- private static final int APK_IN_UPDATED_APEX = 1 << 14;
- }
-
- private int mBooleans;
-
- private void setBoolean(@Booleans.Flags int flag, boolean value) {
- if (value) {
- mBooleans |= flag;
- } else {
- mBooleans &= ~flag;
- }
- }
-
- private boolean getBoolean(@Booleans.Flags int flag) {
- return (mBooleans & flag) != 0;
- }
-
- @Nullable
- private final AndroidPackage mAndroidPackage;
-
- @NonNull
- private final String mPackageName;
- @Nullable
- private final String mVolumeUuid;
- private final int mAppId;
- private final int mCategoryOverride;
- @Nullable
- private final String mCpuAbiOverride;
- @ApplicationInfo.HiddenApiEnforcementPolicy
- private final int mHiddenApiEnforcementPolicy;
- private final long mLastModifiedTime;
- private final long mLastUpdateTime;
- private final long mLongVersionCode;
- @NonNull
- private final Map<String, Set<String>> mMimeGroups;
- @NonNull
- private final File mPath;
- @Nullable
- private final String mPrimaryCpuAbi;
- @Nullable
- private final String mSecondaryCpuAbi;
- @Nullable
- private final String mSeInfo;
- private final boolean mHasSharedUser;
- private final int mSharedUserAppId;
- @NonNull
- private final String[] mUsesSdkLibraries;
- @NonNull
- private final long[] mUsesSdkLibrariesVersionsMajor;
- @NonNull
- private final String[] mUsesStaticLibraries;
- @NonNull
- private final long[] mUsesStaticLibrariesVersions;
- @NonNull
- private final List<SharedLibrary> mUsesLibraries;
- @NonNull
- private final List<String> mUsesLibraryFiles;
- @NonNull
- private final long[] mLastPackageUsageTime;
- @NonNull
- private final SigningInfo mSigningInfo;
- @NonNull
- private final SparseArray<PackageUserState> mUserStates;
- @Nullable
- private final String mApexModuleName;
-
- private PackageStateImpl(@NonNull PackageState pkgState, @Nullable AndroidPackage pkg) {
- mAndroidPackage = pkg;
-
- setBoolean(Booleans.SYSTEM, pkgState.isSystem());
- setBoolean(Booleans.EXTERNAL_STORAGE, pkgState.isExternalStorage());
- setBoolean(Booleans.PRIVILEGED, pkgState.isPrivileged());
- setBoolean(Booleans.OEM, pkgState.isOem());
- setBoolean(Booleans.VENDOR, pkgState.isVendor());
- setBoolean(Booleans.PRODUCT, pkgState.isProduct());
- setBoolean(Booleans.SYSTEM_EXT, pkgState.isSystemExt());
- setBoolean(Booleans.REQUIRED_FOR_SYSTEM_USER, pkgState.isRequiredForSystemUser());
- setBoolean(Booleans.ODM, pkgState.isOdm());
-
- mPackageName = pkgState.getPackageName();
- mVolumeUuid = pkgState.getVolumeUuid();
- mAppId = pkgState.getAppId();
- mCategoryOverride = pkgState.getCategoryOverride();
- mCpuAbiOverride = pkgState.getCpuAbiOverride();
- mHiddenApiEnforcementPolicy = pkgState.getHiddenApiEnforcementPolicy();
- mLastModifiedTime = pkgState.getLastModifiedTime();
- mLastUpdateTime = pkgState.getLastUpdateTime();
- mLongVersionCode = pkgState.getVersionCode();
- mMimeGroups = Collections.unmodifiableMap(pkgState.getMimeGroups());
- mPath = pkgState.getPath();
- mPrimaryCpuAbi = pkgState.getPrimaryCpuAbi();
- mSecondaryCpuAbi = pkgState.getSecondaryCpuAbi();
- mSeInfo = pkgState.getSeInfo();
- mHasSharedUser = pkgState.hasSharedUser();
- mSharedUserAppId = pkgState.getSharedUserAppId();
- mUsesSdkLibraries = pkgState.getUsesSdkLibraries();
- mUsesSdkLibrariesVersionsMajor = pkgState.getUsesSdkLibrariesVersionsMajor();
- mUsesStaticLibraries = pkgState.getUsesStaticLibraries();
- mUsesStaticLibrariesVersions = pkgState.getUsesStaticLibrariesVersions();
- mUsesLibraries = Collections.unmodifiableList(pkgState.getSharedLibraryDependencies());
- mUsesLibraryFiles = Collections.unmodifiableList(pkgState.getUsesLibraryFiles());
- setBoolean(Booleans.FORCE_QUERYABLE_OVERRIDE, pkgState.isForceQueryableOverride());
- setBoolean(Booleans.HIDDEN_UNTIL_INSTALLED, pkgState.isHiddenUntilInstalled());
- setBoolean(Booleans.INSTALL_PERMISSIONS_FIXED, pkgState.isInstallPermissionsFixed());
- setBoolean(Booleans.UPDATE_AVAILABLE, pkgState.isUpdateAvailable());
- mLastPackageUsageTime = pkgState.getLastPackageUsageTime();
- setBoolean(Booleans.UPDATED_SYSTEM_APP, pkgState.isUpdatedSystemApp());
- setBoolean(Booleans.APK_IN_UPDATED_APEX, pkgState.isApkInUpdatedApex());
- mSigningInfo = pkgState.getSigningInfo();
-
- SparseArray<? extends PackageUserState> userStates = pkgState.getUserStates();
- int userStatesSize = userStates.size();
- mUserStates = new SparseArray<>(userStatesSize);
- for (int index = 0; index < userStatesSize; index++) {
- mUserStates.put(userStates.keyAt(index),
- UserStateImpl.copy(userStates.valueAt(index)));
- }
-
- mApexModuleName = pkgState.getApexModuleName();
- }
-
- @NonNull
- @Override
- public PackageUserState getStateForUser(@NonNull UserHandle user) {
- PackageUserState userState = getUserStates().get(user.getIdentifier());
- return userState == null ? PackageUserState.DEFAULT : userState;
- }
-
- @Override
- public boolean isExternalStorage() {
- return getBoolean(Booleans.EXTERNAL_STORAGE);
- }
-
- @Override
- public boolean isForceQueryableOverride() {
- return getBoolean(Booleans.FORCE_QUERYABLE_OVERRIDE);
- }
-
- @Override
- public boolean isHiddenUntilInstalled() {
- return getBoolean(Booleans.HIDDEN_UNTIL_INSTALLED);
- }
-
- @Override
- public boolean isInstallPermissionsFixed() {
- return getBoolean(Booleans.INSTALL_PERMISSIONS_FIXED);
- }
-
- @Override
- public boolean isOdm() {
- return getBoolean(Booleans.ODM);
- }
-
- @Override
- public boolean isOem() {
- return getBoolean(Booleans.OEM);
- }
-
- @Override
- public boolean isPrivileged() {
- return getBoolean(Booleans.PRIVILEGED);
- }
-
- @Override
- public boolean isProduct() {
- return getBoolean(Booleans.PRODUCT);
- }
-
- @Override
- public boolean isRequiredForSystemUser() {
- return getBoolean(Booleans.REQUIRED_FOR_SYSTEM_USER);
- }
-
- @Override
- public boolean isSystem() {
- return getBoolean(Booleans.SYSTEM);
- }
-
- @Override
- public boolean isSystemExt() {
- return getBoolean(Booleans.SYSTEM_EXT);
- }
-
- @Override
- public boolean isUpdateAvailable() {
- return getBoolean(Booleans.UPDATE_AVAILABLE);
- }
-
- @Override
- public boolean isUpdatedSystemApp() {
- return getBoolean(Booleans.UPDATED_SYSTEM_APP);
- }
-
- @Override
- public boolean isApkInUpdatedApex() {
- return getBoolean(Booleans.APK_IN_UPDATED_APEX);
- }
-
- @Override
- public boolean isVendor() {
- return getBoolean(Booleans.VENDOR);
- }
-
- @Override
- public long getVersionCode() {
- return mLongVersionCode;
- }
-
- @Override
- public boolean hasSharedUser() {
- return mHasSharedUser;
- }
-
- @Override
- public boolean isApex() {
- return getAndroidPackage() != null && getAndroidPackage().isApex();
- }
-
- /**
- * @hide
- */
- @DataClass(genConstructor = false)
- public static class UserStateImpl implements PackageUserState {
-
- public static PackageUserState copy(@NonNull PackageUserState state) {
- return new UserStateImpl(state);
- }
-
- private static class Booleans {
- @IntDef({
- HIDDEN,
- INSTALLED,
- INSTANT_APP,
- NOT_LAUNCHED,
- STOPPED,
- SUSPENDED,
- VIRTUAL_PRELOAD,
- })
- public @interface Flags {
- }
-
- private static final int HIDDEN = 1;
- private static final int INSTALLED = 1 << 1;
- private static final int INSTANT_APP = 1 << 2;
- private static final int NOT_LAUNCHED = 1 << 3;
- private static final int STOPPED = 1 << 4;
- private static final int SUSPENDED = 1 << 5;
- private static final int VIRTUAL_PRELOAD = 1 << 6;
- }
-
- private int mBooleans;
-
- private void setBoolean(@Booleans.Flags int flag, boolean value) {
- if (value) {
- mBooleans |= flag;
- } else {
- mBooleans &= ~flag;
- }
- }
-
- private boolean getBoolean(@Booleans.Flags int flag) {
- return (mBooleans & flag) != 0;
- }
-
- private final long mCeDataInode;
- @NonNull
- private final ArraySet<String> mDisabledComponents;
- @PackageManager.DistractionRestriction
- private final int mDistractionFlags;
- @NonNull
- private final ArraySet<String> mEnabledComponents;
- private final int mEnabledState;
- @Nullable
- private final String mHarmfulAppWarning;
- @PackageManager.InstallReason
- private final int mInstallReason;
- @Nullable
- private final String mLastDisableAppCaller;
- @NonNull
- private final OverlayPaths mOverlayPaths;
- @NonNull
- private final Map<String, OverlayPaths> mSharedLibraryOverlayPaths;
- @PackageManager.UninstallReason
- private final int mUninstallReason;
- @Nullable
- private final String mSplashScreenTheme;
- @PackageManager.UserMinAspectRatio
- private final int mMinAspectRatio;
- private final long mFirstInstallTimeMillis;
- @Nullable
- private final ArchiveState mArchiveState;
-
- private UserStateImpl(@NonNull PackageUserState userState) {
- mCeDataInode = userState.getCeDataInode();
- mDisabledComponents = userState.getDisabledComponents();
- mDistractionFlags = userState.getDistractionFlags();
- mEnabledComponents = userState.getEnabledComponents();
- mEnabledState = userState.getEnabledState();
- mHarmfulAppWarning = userState.getHarmfulAppWarning();
- mInstallReason = userState.getInstallReason();
- mLastDisableAppCaller = userState.getLastDisableAppCaller();
- mOverlayPaths = userState.getOverlayPaths();
- mSharedLibraryOverlayPaths = userState.getSharedLibraryOverlayPaths();
- mUninstallReason = userState.getUninstallReason();
- mSplashScreenTheme = userState.getSplashScreenTheme();
- mMinAspectRatio = userState.getMinAspectRatio();
- setBoolean(Booleans.HIDDEN, userState.isHidden());
- setBoolean(Booleans.INSTALLED, userState.isInstalled());
- setBoolean(Booleans.INSTANT_APP, userState.isInstantApp());
- setBoolean(Booleans.NOT_LAUNCHED, userState.isNotLaunched());
- setBoolean(Booleans.STOPPED, userState.isStopped());
- setBoolean(Booleans.SUSPENDED, userState.isSuspended());
- setBoolean(Booleans.VIRTUAL_PRELOAD, userState.isVirtualPreload());
- mFirstInstallTimeMillis = userState.getFirstInstallTimeMillis();
- mArchiveState = userState.getArchiveState();
- }
-
- @Override
- public boolean isHidden() {
- return getBoolean(Booleans.HIDDEN);
- }
-
- @Override
- public boolean isInstalled() {
- return getBoolean(Booleans.INSTALLED);
- }
-
- @Override
- public boolean isInstantApp() {
- return getBoolean(Booleans.INSTANT_APP);
- }
-
- @Override
- public boolean isNotLaunched() {
- return getBoolean(Booleans.NOT_LAUNCHED);
- }
-
- @Override
- public boolean isStopped() {
- return getBoolean(Booleans.STOPPED);
- }
-
- @Override
- public boolean isSuspended() {
- return getBoolean(Booleans.SUSPENDED);
- }
-
- @Override
- public boolean isVirtualPreload() {
- return getBoolean(Booleans.VIRTUAL_PRELOAD);
- }
-
- @Override
- public boolean isComponentEnabled(String componentName) {
- return mEnabledComponents.contains(componentName);
- }
-
- @Override
- public boolean isComponentDisabled(String componentName) {
- return mDisabledComponents.contains(componentName);
- }
-
- @Override
- public OverlayPaths getAllOverlayPaths() {
- if (mOverlayPaths == null && mSharedLibraryOverlayPaths == null) {
- return null;
- }
- final OverlayPaths.Builder newPaths = new OverlayPaths.Builder();
- newPaths.addAll(mOverlayPaths);
- if (mSharedLibraryOverlayPaths != null) {
- for (final OverlayPaths libOverlayPaths : mSharedLibraryOverlayPaths.values()) {
- newPaths.addAll(libOverlayPaths);
- }
- }
- return newPaths.build();
- }
-
-
-
- // Code below generated by codegen v1.0.23.
- //
- // DO NOT MODIFY!
- // CHECKSTYLE:OFF Generated code
- //
- // To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
- //
- // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
- // Settings > Editor > Code Style > Formatter Control
- //@formatter:off
-
-
- @DataClass.Generated.Member
- public int getBooleans() {
- return mBooleans;
- }
-
- @DataClass.Generated.Member
- public long getCeDataInode() {
- return mCeDataInode;
- }
-
- @DataClass.Generated.Member
- public @NonNull ArraySet<String> getDisabledComponents() {
- return mDisabledComponents;
- }
-
- @DataClass.Generated.Member
- public @PackageManager.DistractionRestriction int getDistractionFlags() {
- return mDistractionFlags;
- }
-
- @DataClass.Generated.Member
- public @NonNull ArraySet<String> getEnabledComponents() {
- return mEnabledComponents;
- }
-
- @DataClass.Generated.Member
- public int getEnabledState() {
- return mEnabledState;
- }
-
- @DataClass.Generated.Member
- public @Nullable String getHarmfulAppWarning() {
- return mHarmfulAppWarning;
- }
-
- @DataClass.Generated.Member
- public @PackageManager.InstallReason int getInstallReason() {
- return mInstallReason;
- }
-
- @DataClass.Generated.Member
- public @Nullable String getLastDisableAppCaller() {
- return mLastDisableAppCaller;
- }
-
- @DataClass.Generated.Member
- public @NonNull OverlayPaths getOverlayPaths() {
- return mOverlayPaths;
- }
-
- @DataClass.Generated.Member
- public @NonNull Map<String,OverlayPaths> getSharedLibraryOverlayPaths() {
- return mSharedLibraryOverlayPaths;
- }
-
- @DataClass.Generated.Member
- public @PackageManager.UninstallReason int getUninstallReason() {
- return mUninstallReason;
- }
-
- @DataClass.Generated.Member
- public @Nullable String getSplashScreenTheme() {
- return mSplashScreenTheme;
- }
-
- @DataClass.Generated.Member
- public @PackageManager.UserMinAspectRatio int getMinAspectRatio() {
- return mMinAspectRatio;
- }
-
- @DataClass.Generated.Member
- public long getFirstInstallTimeMillis() {
- return mFirstInstallTimeMillis;
- }
-
- @DataClass.Generated.Member
- public @Nullable ArchiveState getArchiveState() {
- return mArchiveState;
- }
-
- @DataClass.Generated.Member
- public @NonNull UserStateImpl setBooleans( int value) {
- mBooleans = value;
- return this;
- }
-
- @DataClass.Generated(
- time = 1689171425723L,
- codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java",
- inputSignatures = "private int mBooleans\nprivate final long mCeDataInode\nprivate final @android.annotation.NonNull android.util.ArraySet<java.lang.String> mDisabledComponents\nprivate final @android.content.pm.PackageManager.DistractionRestriction int mDistractionFlags\nprivate final @android.annotation.NonNull android.util.ArraySet<java.lang.String> mEnabledComponents\nprivate final int mEnabledState\nprivate final @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate final @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate final @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate final @android.annotation.NonNull android.content.pm.overlay.OverlayPaths mOverlayPaths\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate final @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate final @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate final @android.content.pm.PackageManager.UserMinAspectRatio int mMinAspectRatio\nprivate final long mFirstInstallTimeMillis\nprivate final @android.annotation.Nullable com.android.server.pm.pkg.ArchiveState mArchiveState\npublic static com.android.server.pm.pkg.PackageUserState copy(com.android.server.pm.pkg.PackageUserState)\nprivate void setBoolean(int,boolean)\nprivate boolean getBoolean(int)\npublic @java.lang.Override boolean isHidden()\npublic @java.lang.Override boolean isInstalled()\npublic @java.lang.Override boolean isInstantApp()\npublic @java.lang.Override boolean isNotLaunched()\npublic @java.lang.Override boolean isStopped()\npublic @java.lang.Override boolean isSuspended()\npublic @java.lang.Override boolean isVirtualPreload()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\nclass UserStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageUserState]\nprivate static final int HIDDEN\nprivate static final int INSTALLED\nprivate static final int INSTANT_APP\nprivate static final int NOT_LAUNCHED\nprivate static final int STOPPED\nprivate static final int SUSPENDED\nprivate static final int VIRTUAL_PRELOAD\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false)")
- @Deprecated
- private void __metadata() {}
-
-
- //@formatter:on
- // End of generated code
-
- }
-
-
-
- // Code below generated by codegen v1.0.23.
- //
- // DO NOT MODIFY!
- // CHECKSTYLE:OFF Generated code
- //
- // To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
- //
- // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
- // Settings > Editor > Code Style > Formatter Control
- //@formatter:off
-
-
- @DataClass.Generated.Member
- public int getBooleans() {
- return mBooleans;
- }
-
- @DataClass.Generated.Member
- public @Nullable AndroidPackage getAndroidPackage() {
- return mAndroidPackage;
- }
-
- @DataClass.Generated.Member
- public @NonNull String getPackageName() {
- return mPackageName;
- }
-
- @DataClass.Generated.Member
- public @Nullable String getVolumeUuid() {
- return mVolumeUuid;
- }
-
- @DataClass.Generated.Member
- public int getAppId() {
- return mAppId;
- }
-
- @DataClass.Generated.Member
- public int getCategoryOverride() {
- return mCategoryOverride;
- }
-
- @DataClass.Generated.Member
- public @Nullable String getCpuAbiOverride() {
- return mCpuAbiOverride;
- }
-
- @DataClass.Generated.Member
- public @ApplicationInfo.HiddenApiEnforcementPolicy int getHiddenApiEnforcementPolicy() {
- return mHiddenApiEnforcementPolicy;
- }
-
- @DataClass.Generated.Member
- public long getLastModifiedTime() {
- return mLastModifiedTime;
- }
-
- @DataClass.Generated.Member
- public long getLastUpdateTime() {
- return mLastUpdateTime;
- }
-
- @DataClass.Generated.Member
- public long getLongVersionCode() {
- return mLongVersionCode;
- }
-
- @DataClass.Generated.Member
- public @NonNull Map<String,Set<String>> getMimeGroups() {
- return mMimeGroups;
- }
-
- @DataClass.Generated.Member
- public @NonNull File getPath() {
- return mPath;
- }
-
- @DataClass.Generated.Member
- public @Nullable String getPrimaryCpuAbi() {
- return mPrimaryCpuAbi;
- }
-
- @DataClass.Generated.Member
- public @Nullable String getSecondaryCpuAbi() {
- return mSecondaryCpuAbi;
- }
-
- @DataClass.Generated.Member
- public @Nullable String getSeInfo() {
- return mSeInfo;
- }
-
- @DataClass.Generated.Member
- public boolean isHasSharedUser() {
- return mHasSharedUser;
- }
-
- @DataClass.Generated.Member
- public int getSharedUserAppId() {
- return mSharedUserAppId;
- }
-
- @DataClass.Generated.Member
- public @NonNull String[] getUsesSdkLibraries() {
- return mUsesSdkLibraries;
- }
-
- @DataClass.Generated.Member
- public @NonNull long[] getUsesSdkLibrariesVersionsMajor() {
- return mUsesSdkLibrariesVersionsMajor;
- }
-
- @DataClass.Generated.Member
- public @NonNull String[] getUsesStaticLibraries() {
- return mUsesStaticLibraries;
- }
-
- @DataClass.Generated.Member
- public @NonNull long[] getUsesStaticLibrariesVersions() {
- return mUsesStaticLibrariesVersions;
- }
-
- @DataClass.Generated.Member
- public @NonNull List<SharedLibrary> getSharedLibraryDependencies() {
- return mUsesLibraries;
- }
-
- @DataClass.Generated.Member
- public @NonNull List<String> getUsesLibraryFiles() {
- return mUsesLibraryFiles;
- }
-
- @DataClass.Generated.Member
- public @NonNull long[] getLastPackageUsageTime() {
- return mLastPackageUsageTime;
- }
-
- @DataClass.Generated.Member
- public @NonNull SigningInfo getSigningInfo() {
- return mSigningInfo;
- }
-
- @DataClass.Generated.Member
- public @NonNull SparseArray<PackageUserState> getUserStates() {
- return mUserStates;
- }
-
- @DataClass.Generated.Member
- public @Nullable String getApexModuleName() {
- return mApexModuleName;
- }
-
- @DataClass.Generated.Member
- public @NonNull PackageStateImpl setBooleans( int value) {
- mBooleans = value;
- return this;
- }
-
- @DataClass.Generated(
- time = 1689171425753L,
- codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java",
- inputSignatures = "private int mBooleans\nprivate final @android.annotation.Nullable com.android.server.pm.pkg.AndroidPackage mAndroidPackage\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mVolumeUuid\nprivate final int mAppId\nprivate final int mCategoryOverride\nprivate final @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate final @android.content.pm.ApplicationInfo.HiddenApiEnforcementPolicy int mHiddenApiEnforcementPolicy\nprivate final long mLastModifiedTime\nprivate final long mLastUpdateTime\nprivate final long mLongVersionCode\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mMimeGroups\nprivate final @android.annotation.NonNull java.io.File mPath\nprivate final @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate final @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate final @android.annotation.Nullable java.lang.String mSeInfo\nprivate final boolean mHasSharedUser\nprivate final int mSharedUserAppId\nprivate final @android.annotation.NonNull java.lang.String[] mUsesSdkLibraries\nprivate final @android.annotation.NonNull long[] mUsesSdkLibrariesVersionsMajor\nprivate final @android.annotation.NonNull java.lang.String[] mUsesStaticLibraries\nprivate final @android.annotation.NonNull long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.NonNull java.util.List<com.android.server.pm.pkg.SharedLibrary> mUsesLibraries\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesLibraryFiles\nprivate final @android.annotation.NonNull long[] mLastPackageUsageTime\nprivate final @android.annotation.NonNull android.content.pm.SigningInfo mSigningInfo\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserState> mUserStates\nprivate final @android.annotation.Nullable java.lang.String mApexModuleName\npublic static com.android.server.pm.pkg.PackageState copy(com.android.server.pm.pkg.PackageStateInternal)\nprivate void setBoolean(int,boolean)\nprivate boolean getBoolean(int)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserState getStateForUser(android.os.UserHandle)\npublic @java.lang.Override boolean isExternalStorage()\npublic @java.lang.Override boolean isForceQueryableOverride()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @java.lang.Override boolean isInstallPermissionsFixed()\npublic @java.lang.Override boolean isOdm()\npublic @java.lang.Override boolean isOem()\npublic @java.lang.Override boolean isPrivileged()\npublic @java.lang.Override boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic @java.lang.Override boolean isSystem()\npublic @java.lang.Override boolean isSystemExt()\npublic @java.lang.Override boolean isUpdateAvailable()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isApkInUpdatedApex()\npublic @java.lang.Override boolean isVendor()\npublic @java.lang.Override long getVersionCode()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override boolean isApex()\nclass PackageStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageState]\nprivate static final int SYSTEM\nprivate static final int EXTERNAL_STORAGE\nprivate static final int PRIVILEGED\nprivate static final int OEM\nprivate static final int VENDOR\nprivate static final int PRODUCT\nprivate static final int SYSTEM_EXT\nprivate static final int REQUIRED_FOR_SYSTEM_USER\nprivate static final int ODM\nprivate static final int FORCE_QUERYABLE_OVERRIDE\nprivate static final int HIDDEN_UNTIL_INSTALLED\nprivate static final int INSTALL_PERMISSIONS_FIXED\nprivate static final int UPDATE_AVAILABLE\nprivate static final int UPDATED_SYSTEM_APP\nprivate static final int APK_IN_UPDATED_APEX\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false)")
- @Deprecated
- private void __metadata() {}
-
-
- //@formatter:on
- // End of generated code
-
-}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
index 6ac7c34d844b..d8c8af6c8fd1 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
@@ -17,6 +17,7 @@
package com.android.server.pm.pkg;
import android.annotation.CurrentTimeMillisLong;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
@@ -45,9 +46,44 @@ import java.util.Objects;
/** @hide */
@DataClass(genConstructor = false, genBuilder = false, genEqualsHashCode = true)
@DataClass.Suppress({"mOverlayPathsLock", "mOverlayPaths", "mSharedLibraryOverlayPathsLock",
- "mSharedLibraryOverlayPaths", "setOverlayPaths", "setCachedOverlayPaths", "getWatchable"})
+ "mSharedLibraryOverlayPaths", "setOverlayPaths", "setCachedOverlayPaths", "getWatchable",
+ "getBooleans"
+})
public class PackageUserStateImpl extends WatchableImpl implements PackageUserStateInternal,
Snappable {
+ // Use a bitset to store boolean data to save memory
+ private static class Booleans {
+ @IntDef({
+ INSTALLED,
+ STOPPED,
+ NOT_LAUNCHED,
+ HIDDEN,
+ INSTANT_APP,
+ VIRTUAL_PRELOADED,
+ })
+ public @interface Flags {
+ }
+ private static final int INSTALLED = 1;
+ private static final int STOPPED = 1 << 1;
+ private static final int NOT_LAUNCHED = 1 << 2;
+ // Is the app restricted by owner / admin
+ private static final int HIDDEN = 1 << 3;
+ private static final int INSTANT_APP = 1 << 4;
+ private static final int VIRTUAL_PRELOADED = 1 << 5;
+ }
+ private int mBooleans;
+
+ private void setBoolean(@Booleans.Flags int flag, boolean value) {
+ if (value) {
+ mBooleans |= flag;
+ } else {
+ mBooleans &= ~flag;
+ }
+ }
+
+ private boolean getBoolean(@Booleans.Flags int flag) {
+ return (mBooleans & flag) != 0;
+ }
@Nullable
protected WatchedArraySet<String> mDisabledComponentsWatched;
@@ -55,13 +91,7 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
protected WatchedArraySet<String> mEnabledComponentsWatched;
private long mCeDataInode;
- private boolean mInstalled = true;
- private boolean mStopped;
- private boolean mNotLaunched;
- private boolean mHidden; // Is the app restricted by owner / admin
private int mDistractionFlags;
- private boolean mInstantApp;
- private boolean mVirtualPreload;
@PackageManager.EnabledState
private int mEnabledState = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
@PackageManager.InstallReason
@@ -122,15 +152,18 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
super();
mWatchable = null;
mSnapshot = makeCache();
+ setBoolean(Booleans.INSTALLED, true);
}
public PackageUserStateImpl(@NonNull Watchable watchable) {
mWatchable = watchable;
mSnapshot = makeCache();
+ setBoolean(Booleans.INSTALLED, true);
}
public PackageUserStateImpl(@NonNull Watchable watchable, PackageUserStateImpl other) {
mWatchable = watchable;
+ mBooleans = other.mBooleans;
mDisabledComponentsWatched = other.mDisabledComponentsWatched == null
? null : other.mDisabledComponentsWatched.snapshot();
mEnabledComponentsWatched = other.mEnabledComponentsWatched == null
@@ -139,13 +172,7 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
mSharedLibraryOverlayPaths = other.mSharedLibraryOverlayPaths == null
? null : other.mSharedLibraryOverlayPaths.snapshot();
mCeDataInode = other.mCeDataInode;
- mInstalled = other.mInstalled;
- mStopped = other.mStopped;
- mNotLaunched = other.mNotLaunched;
- mHidden = other.mHidden;
mDistractionFlags = other.mDistractionFlags;
- mInstantApp = other.mInstantApp;
- mVirtualPreload = other.mVirtualPreload;
mEnabledState = other.mEnabledState;
mInstallReason = other.mInstallReason;
mUninstallReason = other.mUninstallReason;
@@ -418,25 +445,25 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
}
public @NonNull PackageUserStateImpl setInstalled(boolean value) {
- mInstalled = value;
+ setBoolean(Booleans.INSTALLED, value);
onChanged();
return this;
}
public @NonNull PackageUserStateImpl setStopped(boolean value) {
- mStopped = value;
+ setBoolean(Booleans.STOPPED, value);
onChanged();
return this;
}
public @NonNull PackageUserStateImpl setNotLaunched(boolean value) {
- mNotLaunched = value;
+ setBoolean(Booleans.NOT_LAUNCHED, value);
onChanged();
return this;
}
public @NonNull PackageUserStateImpl setHidden(boolean value) {
- mHidden = value;
+ setBoolean(Booleans.HIDDEN, value);
onChanged();
return this;
}
@@ -448,13 +475,13 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
}
public @NonNull PackageUserStateImpl setInstantApp(boolean value) {
- mInstantApp = value;
+ setBoolean(Booleans.INSTANT_APP, value);
onChanged();
return this;
}
public @NonNull PackageUserStateImpl setVirtualPreload(boolean value) {
- mVirtualPreload = value;
+ setBoolean(Booleans.VIRTUAL_PRELOADED, value);
onChanged();
return this;
}
@@ -613,6 +640,38 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
}
+ @Override
+ public boolean isInstalled() {
+ return getBoolean(Booleans.INSTALLED);
+ }
+
+ @Override
+ public boolean isStopped() {
+ return getBoolean(Booleans.STOPPED);
+ }
+
+ @Override
+ public boolean isNotLaunched() {
+ return getBoolean(Booleans.NOT_LAUNCHED);
+ }
+
+ @Override
+ public boolean isHidden() {
+ return getBoolean(Booleans.HIDDEN);
+ }
+
+ @Override
+ public boolean isInstantApp() {
+ return getBoolean(Booleans.INSTANT_APP);
+ }
+
+ @Override
+ public boolean isVirtualPreload() {
+ return getBoolean(Booleans.VIRTUAL_PRELOADED);
+ }
+
+
+
// Code below generated by codegen v1.0.23.
//
@@ -643,41 +702,11 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
}
@DataClass.Generated.Member
- public boolean isInstalled() {
- return mInstalled;
- }
-
- @DataClass.Generated.Member
- public boolean isStopped() {
- return mStopped;
- }
-
- @DataClass.Generated.Member
- public boolean isNotLaunched() {
- return mNotLaunched;
- }
-
- @DataClass.Generated.Member
- public boolean isHidden() {
- return mHidden;
- }
-
- @DataClass.Generated.Member
public int getDistractionFlags() {
return mDistractionFlags;
}
@DataClass.Generated.Member
- public boolean isInstantApp() {
- return mInstantApp;
- }
-
- @DataClass.Generated.Member
- public boolean isVirtualPreload() {
- return mVirtualPreload;
- }
-
- @DataClass.Generated.Member
public @PackageManager.EnabledState int getEnabledState() {
return mEnabledState;
}
@@ -746,6 +775,12 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
}
@DataClass.Generated.Member
+ public @NonNull PackageUserStateImpl setBooleans( int value) {
+ mBooleans = value;
+ return this;
+ }
+
+ @DataClass.Generated.Member
public @NonNull PackageUserStateImpl setDisabledComponentsWatched(@NonNull WatchedArraySet<String> value) {
mDisabledComponentsWatched = value;
return this;
@@ -791,16 +826,11 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
PackageUserStateImpl that = (PackageUserStateImpl) o;
//noinspection PointlessBooleanExpression
return true
+ && mBooleans == that.mBooleans
&& Objects.equals(mDisabledComponentsWatched, that.mDisabledComponentsWatched)
&& Objects.equals(mEnabledComponentsWatched, that.mEnabledComponentsWatched)
&& mCeDataInode == that.mCeDataInode
- && mInstalled == that.mInstalled
- && mStopped == that.mStopped
- && mNotLaunched == that.mNotLaunched
- && mHidden == that.mHidden
&& mDistractionFlags == that.mDistractionFlags
- && mInstantApp == that.mInstantApp
- && mVirtualPreload == that.mVirtualPreload
&& mEnabledState == that.mEnabledState
&& mInstallReason == that.mInstallReason
&& mUninstallReason == that.mUninstallReason
@@ -825,16 +855,11 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
// int fieldNameHashCode() { ... }
int _hash = 1;
+ _hash = 31 * _hash + mBooleans;
_hash = 31 * _hash + Objects.hashCode(mDisabledComponentsWatched);
_hash = 31 * _hash + Objects.hashCode(mEnabledComponentsWatched);
_hash = 31 * _hash + Long.hashCode(mCeDataInode);
- _hash = 31 * _hash + Boolean.hashCode(mInstalled);
- _hash = 31 * _hash + Boolean.hashCode(mStopped);
- _hash = 31 * _hash + Boolean.hashCode(mNotLaunched);
- _hash = 31 * _hash + Boolean.hashCode(mHidden);
_hash = 31 * _hash + mDistractionFlags;
- _hash = 31 * _hash + Boolean.hashCode(mInstantApp);
- _hash = 31 * _hash + Boolean.hashCode(mVirtualPreload);
_hash = 31 * _hash + mEnabledState;
_hash = 31 * _hash + mInstallReason;
_hash = 31 * _hash + mUninstallReason;
@@ -854,10 +879,10 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
}
@DataClass.Generated(
- time = 1689171513404L,
+ time = 1691186062924L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java",
- inputSignatures = "protected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mDisabledComponentsWatched\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mEnabledComponentsWatched\nprivate long mCeDataInode\nprivate boolean mInstalled\nprivate boolean mStopped\nprivate boolean mNotLaunched\nprivate boolean mHidden\nprivate int mDistractionFlags\nprivate boolean mInstantApp\nprivate boolean mVirtualPreload\nprivate @android.content.pm.PackageManager.EnabledState int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.content.pm.PackageManager.UserMinAspectRatio int mMinAspectRatio\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\nprivate @android.annotation.CurrentTimeMillisLong long mFirstInstallTimeMillis\nprivate @android.annotation.Nullable com.android.server.utils.Watchable mWatchable\nprivate @android.annotation.Nullable com.android.server.pm.pkg.ArchiveState mArchiveState\nfinal @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> mSnapshot\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> makeCache()\nprivate void onChanged()\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserStateImpl snapshot()\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponents()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponents()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(java.lang.String,com.android.server.pm.pkg.SuspendParams)\npublic com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setCeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstalled(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setStopped(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setNotLaunched(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHidden(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDistractionFlags(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstantApp(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setVirtualPreload(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setUninstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHarmfulAppWarning(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setLastDisableAppCaller(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSharedLibraryOverlayPaths(android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSplashScreenTheme(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setMinAspectRatio(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSuspendParams(android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setComponentLabelIconOverrideMap(android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setFirstInstallTimeMillis(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setArchiveState(com.android.server.pm.pkg.ArchiveState)\npublic @android.annotation.NonNull @java.lang.Override java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> getSharedLibraryOverlayPaths()\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setWatchable(com.android.server.utils.Watchable)\nprivate boolean watchableEquals(com.android.server.utils.Watchable)\nprivate int watchableHashCode()\nprivate boolean snapshotEquals(com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl>)\nprivate int snapshotHashCode()\nclass PackageUserStateImpl extends com.android.server.utils.WatchableImpl implements [com.android.server.pm.pkg.PackageUserStateInternal, com.android.server.utils.Snappable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
+ inputSignatures = "private int mBooleans\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mDisabledComponentsWatched\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mEnabledComponentsWatched\nprivate long mCeDataInode\nprivate int mDistractionFlags\nprivate @android.content.pm.PackageManager.EnabledState int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.content.pm.PackageManager.UserMinAspectRatio int mMinAspectRatio\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\nprivate @android.annotation.CurrentTimeMillisLong long mFirstInstallTimeMillis\nprivate @android.annotation.Nullable com.android.server.utils.Watchable mWatchable\nprivate @android.annotation.Nullable com.android.server.pm.pkg.ArchiveState mArchiveState\nfinal @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> mSnapshot\nprivate void setBoolean(int,boolean)\nprivate boolean getBoolean(int)\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> makeCache()\nprivate void onChanged()\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserStateImpl snapshot()\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponents()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponents()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(java.lang.String,com.android.server.pm.pkg.SuspendParams)\npublic com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setCeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstalled(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setStopped(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setNotLaunched(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHidden(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDistractionFlags(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstantApp(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setVirtualPreload(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setUninstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHarmfulAppWarning(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setLastDisableAppCaller(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSharedLibraryOverlayPaths(android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSplashScreenTheme(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setMinAspectRatio(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSuspendParams(android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setComponentLabelIconOverrideMap(android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setFirstInstallTimeMillis(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setArchiveState(com.android.server.pm.pkg.ArchiveState)\npublic @android.annotation.NonNull @java.lang.Override java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> getSharedLibraryOverlayPaths()\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setWatchable(com.android.server.utils.Watchable)\nprivate boolean watchableEquals(com.android.server.utils.Watchable)\nprivate int watchableHashCode()\nprivate boolean snapshotEquals(com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl>)\nprivate int snapshotHashCode()\npublic @java.lang.Override boolean isInstalled()\npublic @java.lang.Override boolean isStopped()\npublic @java.lang.Override boolean isNotLaunched()\npublic @java.lang.Override boolean isHidden()\npublic @java.lang.Override boolean isInstantApp()\npublic @java.lang.Override boolean isVirtualPreload()\nclass PackageUserStateImpl extends com.android.server.utils.WatchableImpl implements [com.android.server.pm.pkg.PackageUserStateInternal, com.android.server.utils.Snappable]\nprivate static final int INSTALLED\nprivate static final int STOPPED\nprivate static final int NOT_LAUNCHED\nprivate static final int HIDDEN\nprivate static final int INSTANT_APP\nprivate static final int VIRTUAL_PRELOADED\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 75fcca5eec9a..1e6486a17fe7 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -18,7 +18,6 @@ package com.android.server.power;
import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.policyToString;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
-import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT;
import static android.os.PowerManager.GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF;
import static android.os.PowerManager.GO_TO_SLEEP_REASON_DISPLAY_GROUP_REMOVED;
import static android.os.PowerManager.WAKE_REASON_DISPLAY_GROUP_ADDED;
@@ -1280,7 +1279,7 @@ public final class PowerManagerService extends SystemService
@Override
public void onStart() {
publishBinderService(Context.POWER_SERVICE, mBinderService, /* allowIsolated= */ false,
- DUMP_FLAG_PRIORITY_DEFAULT | DUMP_FLAG_PRIORITY_CRITICAL);
+ DUMP_FLAG_PRIORITY_CRITICAL);
publishLocalService(PowerManagerInternal.class, mLocalService);
Watchdog.getInstance().addMonitor(this);
diff --git a/services/core/java/com/android/server/power/TEST_MAPPING b/services/core/java/com/android/server/power/TEST_MAPPING
index 8374997e3fa2..19086a184068 100644
--- a/services/core/java/com/android/server/power/TEST_MAPPING
+++ b/services/core/java/com/android/server/power/TEST_MAPPING
@@ -17,15 +17,6 @@
]
},
{
- "name": "FrameworksServicesTests",
- "options": [
- {"include-filter": "com.android.server.power"},
- {"exclude-filter": "com.android.server.power.BatteryStatsTests"},
- {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"}
- ]
- },
- {
"name": "PowerServiceTests",
"options": [
{"include-filter": "com.android.server.power"},
@@ -48,15 +39,13 @@
{
"name": "FrameworksServicesTests",
"options": [
- {"include-filter": "com.android.server.power"},
- {"exclude-filter": "com.android.server.power.BatteryStatsTests"}
+ {"include-filter": "com.android.server.power"}
]
},
{
"name": "PowerServiceTests",
"options": [
{"include-filter": "com.android.server.power"},
- {"exclude-filter": "com.android.server.power.BatteryStatsTests"},
{"exclude-annotation": "org.junit.Ignore"}
]
}
diff --git a/services/core/java/com/android/server/power/batterysaver/TEST_MAPPING b/services/core/java/com/android/server/power/batterysaver/TEST_MAPPING
index 17dba7df3f1f..c091b8e68236 100644
--- a/services/core/java/com/android/server/power/batterysaver/TEST_MAPPING
+++ b/services/core/java/com/android/server/power/batterysaver/TEST_MAPPING
@@ -4,7 +4,13 @@
"name": "CtsLocationCoarseTestCases"
},
{
- "name": "CtsLocationFineTestCases"
+ "name": "CtsLocationFineTestCases",
+ "options": [
+ {
+ // TODO: Wait for test to deflake - b/293934372
+ "exclude-filter":"android.location.cts.fine.ScanningSettingsTest"
+ }
+ ]
},
{
"name": "CtsLocationNoneTestCases"
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index 1a91d252c431..8dcf3e06330f 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -304,7 +304,8 @@ public final class HintManagerService extends SystemService {
return mService;
}
- private boolean checkTidValid(int uid, int tgid, int [] tids) {
+ // returns the first invalid tid or null if not found
+ private Integer checkTidValid(int uid, int tgid, int [] tids) {
// Make sure all tids belongs to the same UID (including isolated UID),
// tids can belong to different application processes.
List<Integer> isolatedPids = null;
@@ -326,19 +327,24 @@ public final class HintManagerService extends SystemService {
if (isolatedPids == null) {
// To avoid deadlock, do not call into AMS if the call is from system.
if (uid == Process.SYSTEM_UID) {
- return false;
+ return threadId;
}
isolatedPids = mAmInternal.getIsolatedProcesses(uid);
if (isolatedPids == null) {
- return false;
+ return threadId;
}
}
if (isolatedPids.contains(pidOfThreadId)) {
continue;
}
- return false;
+ return threadId;
}
- return true;
+ return null;
+ }
+
+ private String formatTidCheckErrMsg(int callingUid, int[] tids, Integer invalidTid) {
+ return "Tid" + invalidTid + " from list " + Arrays.toString(tids)
+ + " doesn't belong to the calling application" + callingUid;
}
@VisibleForTesting
@@ -356,8 +362,11 @@ public final class HintManagerService extends SystemService {
final int callingTgid = Process.getThreadGroupLeader(Binder.getCallingPid());
final long identity = Binder.clearCallingIdentity();
try {
- if (!checkTidValid(callingUid, callingTgid, tids)) {
- throw new SecurityException("Some tid doesn't belong to the application");
+ final Integer invalidTid = checkTidValid(callingUid, callingTgid, tids);
+ if (invalidTid != null) {
+ final String errMsg = formatTidCheckErrMsg(callingUid, tids, invalidTid);
+ Slogf.w(TAG, errMsg);
+ throw new SecurityException(errMsg);
}
long halSessionPtr = mNativeWrapper.halCreateHintSession(callingTgid, callingUid,
@@ -561,8 +570,11 @@ public final class HintManagerService extends SystemService {
final int callingTgid = Process.getThreadGroupLeader(Binder.getCallingPid());
final long identity = Binder.clearCallingIdentity();
try {
- if (!checkTidValid(callingUid, callingTgid, tids)) {
- throw new SecurityException("Some tid doesn't belong to the application.");
+ final Integer invalidTid = checkTidValid(callingUid, callingTgid, tids);
+ if (invalidTid != null) {
+ final String errMsg = formatTidCheckErrMsg(callingUid, tids, invalidTid);
+ Slogf.w(TAG, errMsg);
+ throw new SecurityException(errMsg);
}
} finally {
Binder.restoreCallingIdentity(identity);
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 80c21f458cb7..cf4e845a273b 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -78,6 +78,7 @@ import android.telephony.CellSignalStrengthLte;
import android.telephony.CellSignalStrengthNr;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ModemActivityInfo;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.ServiceState;
import android.telephony.ServiceState.RegState;
import android.telephony.SignalStrength;
@@ -181,7 +182,7 @@ public class BatteryStatsImpl extends BatteryStats {
// TODO: remove "tcp" from network methods, since we measure total stats.
// Current on-disk Parcel version. Must be updated when the format of the parcelable changes
- public static final int VERSION = 212;
+ public static final int VERSION = 213;
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -1041,6 +1042,9 @@ public class BatteryStatsImpl extends BatteryStats {
final StopwatchTimer[] mPhoneDataConnectionsTimer =
new StopwatchTimer[NUM_DATA_CONNECTION_TYPES];
+ int mNrState = -1;
+ StopwatchTimer mNrNsaTimer;
+
@RadioAccessTechnology
int mActiveRat = RADIO_ACCESS_TECHNOLOGY_OTHER;
@@ -6092,15 +6096,16 @@ public class BatteryStatsImpl extends BatteryStats {
@GuardedBy("this")
public void notePhoneDataConnectionStateLocked(@NetworkType int dataType, boolean hasData,
- @RegState int serviceType, @ServiceState.FrequencyRange int nrFrequency) {
- notePhoneDataConnectionStateLocked(dataType, hasData, serviceType, nrFrequency,
+ @RegState int serviceType, @NetworkRegistrationInfo.NRState int nrState,
+ @ServiceState.FrequencyRange int nrFrequency) {
+ notePhoneDataConnectionStateLocked(dataType, hasData, serviceType, nrState, nrFrequency,
mClock.elapsedRealtime(), mClock.uptimeMillis());
}
@GuardedBy("this")
public void notePhoneDataConnectionStateLocked(@NetworkType int dataType, boolean hasData,
- @RegState int serviceType, @ServiceState.FrequencyRange int nrFrequency,
- long elapsedRealtimeMs, long uptimeMs) {
+ @RegState int serviceType, @NetworkRegistrationInfo.NRState int nrState,
+ @ServiceState.FrequencyRange int nrFrequency, long elapsedRealtimeMs, long uptimeMs) {
// BatteryStats uses 0 to represent no network type.
// Telephony does not have a concept of no network type, and uses 0 to represent unknown.
// Unknown is included in DATA_CONNECTION_OTHER.
@@ -6123,11 +6128,7 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
- final int newRat = mapNetworkTypeToRadioAccessTechnology(bin);
- if (newRat == RADIO_ACCESS_TECHNOLOGY_NR) {
- // Note possible frequency change for the NR RAT.
- getRatBatteryStatsLocked(newRat).noteFrequencyRange(nrFrequency, elapsedRealtimeMs);
- }
+
if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData);
if (mPhoneDataConnectionType != bin) {
@@ -6138,18 +6139,54 @@ public class BatteryStatsImpl extends BatteryStats {
}
mPhoneDataConnectionType = bin;
mPhoneDataConnectionsTimer[bin].startRunningLocked(elapsedRealtimeMs);
+ }
+
+ if (mNrState != nrState) {
+ mHistory.recordNrStateChangeEvent(elapsedRealtimeMs, uptimeMs, nrState);
+ mNrState = nrState;
+ }
- if (mActiveRat != newRat) {
- getRatBatteryStatsLocked(mActiveRat).noteActive(false, elapsedRealtimeMs);
- mActiveRat = newRat;
+ final boolean newNrNsaActive = isNrNsa(bin, nrState);
+ final boolean nrNsaActive = mNrNsaTimer.isRunningLocked();
+ if (newNrNsaActive != nrNsaActive) {
+ if (newNrNsaActive) {
+ mNrNsaTimer.startRunningLocked(elapsedRealtimeMs);
+ } else {
+ mNrNsaTimer.stopRunningLocked(elapsedRealtimeMs);
}
- final boolean modemActive = mMobileRadioActiveTimer.isRunningLocked();
- getRatBatteryStatsLocked(newRat).noteActive(modemActive, elapsedRealtimeMs);
}
+
+ final int newRat = mapNetworkTypeToRadioAccessTechnology(bin, nrState);
+ if (newRat == RADIO_ACCESS_TECHNOLOGY_NR) {
+ // Note possible frequency change for the NR RAT.
+ getRatBatteryStatsLocked(newRat).noteFrequencyRange(nrFrequency, elapsedRealtimeMs);
+ }
+ if (mActiveRat != newRat) {
+ getRatBatteryStatsLocked(mActiveRat).noteActive(false, elapsedRealtimeMs);
+ mActiveRat = newRat;
+ }
+ final boolean modemActive = mMobileRadioActiveTimer.isRunningLocked();
+ getRatBatteryStatsLocked(newRat).noteActive(modemActive, elapsedRealtimeMs);
+ }
+
+ /**
+ * Non-standalone (NSA) mode for 5G NR will have an LTE network type. If NR state is
+ * connected while on an LTE network, the device is in NR NSA mode.
+ */
+ private static boolean isNrNsa(@NetworkType int dataType,
+ @NetworkRegistrationInfo.NRState int nrState) {
+ return dataType == TelephonyManager.NETWORK_TYPE_LTE
+ && nrState == NetworkRegistrationInfo.NR_STATE_CONNECTED;
}
@RadioAccessTechnology
- private static int mapNetworkTypeToRadioAccessTechnology(@NetworkType int dataType) {
+ private static int mapNetworkTypeToRadioAccessTechnology(@NetworkType int dataType,
+ @NetworkRegistrationInfo.NRState int nrState) {
+ if (isNrNsa(dataType, nrState)) {
+ // Treat an NR NSA connection as RADIO_ACCESS_TECHNOLOGY_NR
+ return RADIO_ACCESS_TECHNOLOGY_NR;
+ }
+
switch (dataType) {
case TelephonyManager.NETWORK_TYPE_NR:
return RADIO_ACCESS_TECHNOLOGY_NR;
@@ -7322,6 +7359,10 @@ public class BatteryStatsImpl extends BatteryStats {
return mPhoneDataConnectionsTimer[dataType];
}
+ @Override public long getNrNsaTime(long elapsedRealtimeUs) {
+ return mNrNsaTimer.getTotalTimeLocked(elapsedRealtimeUs, STATS_SINCE_CHARGED);
+ }
+
@Override public long getActiveRadioDurationMs(@RadioAccessTechnology int rat,
@ServiceState.FrequencyRange int frequencyRange, int signalStrength,
long elapsedRealtimeMs) {
@@ -10955,6 +10996,7 @@ public class BatteryStatsImpl extends BatteryStats {
mPhoneDataConnectionsTimer[i] = new StopwatchTimer(mClock, null, -300 - i, null,
mOnBatteryTimeBase);
}
+ mNrNsaTimer = new StopwatchTimer(mClock, null, -200 + 2, null, mOnBatteryTimeBase);
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
@@ -11578,6 +11620,7 @@ public class BatteryStatsImpl extends BatteryStats {
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
mPhoneDataConnectionsTimer[i].reset(false, elapsedRealtimeUs);
}
+ mNrNsaTimer.reset(false, elapsedRealtimeUs);
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
mNetworkByteActivityCounters[i].reset(false, elapsedRealtimeUs);
mNetworkPacketActivityCounters[i].reset(false, elapsedRealtimeUs);
@@ -15892,6 +15935,7 @@ public class BatteryStatsImpl extends BatteryStats {
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
mPhoneDataConnectionsTimer[i].readSummaryFromParcelLocked(in);
}
+ mNrNsaTimer.readSummaryFromParcelLocked(in);
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
mNetworkByteActivityCounters[i].readSummaryFromParcelLocked(in);
mNetworkPacketActivityCounters[i].readSummaryFromParcelLocked(in);
@@ -16395,6 +16439,7 @@ public class BatteryStatsImpl extends BatteryStats {
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
mPhoneDataConnectionsTimer[i].writeSummaryFromParcelLocked(out, nowRealtime);
}
+ mNrNsaTimer.writeSummaryFromParcelLocked(out, nowRealtime);
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
mNetworkByteActivityCounters[i].writeSummaryFromParcelLocked(out);
mNetworkPacketActivityCounters[i].writeSummaryFromParcelLocked(out);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 614493dca2d8..c909cbe9d4a1 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -6494,6 +6494,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
/**
+ * @return whether the physical display has a fixed orientation and cannot be rotated.
+ */
+ boolean isDisplayOrientationFixed() {
+ return (mDisplayInfo.flags & Display.FLAG_ROTATES_WITH_CONTENT) == 0;
+ }
+
+ /**
* @return whether AOD is showing on this display
*/
boolean isAodShowing() {
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 70edf3a733da..9ef25b6e71b1 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -434,7 +434,8 @@ public class DisplayRotation {
final boolean isTv = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_LEANBACK);
mDefaultFixedToUserRotation =
- (isCar || isTv || mService.mIsPc || mDisplayContent.forceDesktopMode())
+ (isCar || isTv || mService.mIsPc || mDisplayContent.forceDesktopMode()
+ || mDisplayContent.isDisplayOrientationFixed())
// For debug purposes the next line turns this feature off with:
// $ adb shell setprop config.override_forced_orient true
// $ adb shell wm size reset
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 5f3d517b2cdf..02f5c217e5d8 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -81,8 +81,8 @@ class InsetsSourceProvider {
private boolean mIsLeashReadyForDispatching;
private final Rect mSourceFrame = new Rect();
private final Rect mLastSourceFrame = new Rect();
- private final Rect mLastContainerBounds = new Rect();
private @NonNull Insets mInsetsHint = Insets.NONE;
+ private boolean mInsetsHintStale = true;
private @Flags int mFlagsFromFrameProvider;
private @Flags int mFlagsFromServer;
@@ -238,6 +238,10 @@ class InsetsSourceProvider {
mSource.setFlags(mFlagsFromFrameProvider | mFlagsFromServer);
}
updateSourceFrameForServerVisibility();
+ if (!mLastSourceFrame.equals(mSourceFrame)) {
+ mLastSourceFrame.set(mSourceFrame);
+ mInsetsHintStale = true;
+ }
if (mOverrideFrameProviders != null) {
// Not necessary to clear the mOverrideFrames here. It will be cleared every time the
@@ -279,28 +283,29 @@ class InsetsSourceProvider {
// visible. (i.e. No surface, pending insets that were given during layout, etc..)
if (mServerVisible) {
mSource.setFrame(mSourceFrame);
- updateInsetsHint();
} else {
mSource.setFrame(0, 0, 0, 0);
}
}
- // To be called when mSourceFrame or the window container bounds is changed.
- private void updateInsetsHint() {
- if (!mControllable || !mServerVisible) {
- return;
- }
- final Rect bounds = mWindowContainer.getBounds();
- if (mSourceFrame.equals(mLastSourceFrame) && bounds.equals(mLastContainerBounds)) {
- return;
- }
- mLastSourceFrame.set(mSourceFrame);
- mLastContainerBounds.set(bounds);
- mInsetsHint = mSource.calculateInsets(bounds, true /* ignoreVisibility */);
+ void onWindowContainerBoundsChanged() {
+ mInsetsHintStale = true;
}
@VisibleForTesting
Insets getInsetsHint() {
+ if (!mServerVisible) {
+ return mInsetsHint;
+ }
+ final WindowState win = mWindowContainer.asWindowState();
+ if (win != null && win.mGivenInsetsPending) {
+ return mInsetsHint;
+ }
+ if (mInsetsHintStale) {
+ final Rect bounds = mWindowContainer.getBounds();
+ mInsetsHint = mSource.calculateInsets(bounds, true /* ignoreVisibility */);
+ mInsetsHintStale = false;
+ }
return mInsetsHint;
}
@@ -359,8 +364,9 @@ class InsetsSourceProvider {
mSetLeashPositionConsumer.accept(t);
}
}
- if (!mControl.getInsetsHint().equals(mInsetsHint)) {
- mControl.setInsetsHint(mInsetsHint);
+ final Insets insetsHint = getInsetsHint();
+ if (!mControl.getInsetsHint().equals(insetsHint)) {
+ mControl.setInsetsHint(insetsHint);
changed = true;
}
if (changed) {
@@ -494,7 +500,7 @@ class InsetsSourceProvider {
mControlTarget = target;
updateVisibility();
mControl = new InsetsSourceControl(mSource.getId(), mSource.getType(), leash,
- mClientVisible, surfacePosition, mInsetsHint);
+ mClientVisible, surfacePosition, getInsetsHint());
ProtoLog.d(WM_DEBUG_WINDOW_INSETS,
"InsetsSource Control %s for target %s", mControl, mControlTarget);
@@ -605,6 +611,9 @@ class InsetsSourceProvider {
if (mControllable) {
pw.print(prefix + "mInsetsHint=");
pw.print(mInsetsHint);
+ if (mInsetsHintStale) {
+ pw.print(" stale");
+ }
pw.println();
}
pw.print(prefix);
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index e80cbb302424..9af12ad6e766 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -1851,9 +1851,17 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
0 /* launchFlags */);
task.reparent(launchRoot == null ? toDisplayArea : launchRoot, POSITION_TOP);
- // Set the windowing mode to undefined by default to let the root task inherited the
- // windowing mode.
- task.setWindowingMode(WINDOWING_MODE_UNDEFINED);
+ // If the task is going to be reparented to the non-fullscreen root TDA and the task
+ // is set to FULLSCREEN explicitly, we keep the windowing mode as is. Otherwise, the
+ // task will inherit the display windowing mode unexpectedly.
+ final boolean keepWindowingMode = launchRoot == null
+ && task.getRequestedOverrideWindowingMode() == WINDOWING_MODE_FULLSCREEN
+ && toDisplayArea.getWindowingMode() != WINDOWING_MODE_FULLSCREEN;
+ if (!keepWindowingMode) {
+ // Set the windowing mode to undefined to let the root task inherited the
+ // windowing mode.
+ task.setWindowingMode(WINDOWING_MODE_UNDEFINED);
+ }
lastReparentedRootTask = task;
}
// Root task may be removed from this display. Ensure each root task will be processed
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 83949ccae366..d8cc8d386424 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -86,7 +86,6 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.os.IBinder;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.util.DisplayMetrics;
import android.util.Slog;
@@ -1325,14 +1324,12 @@ class TaskFragment extends WindowContainer<WindowContainer> {
}
}
- // Launching this app's activity, make sure the app is no longer
- // considered stopped.
try {
mTaskSupervisor.getActivityMetricsLogger()
.notifyBeforePackageUnstopped(next.packageName);
- mAtmService.getPackageManager().setPackageStoppedState(
- next.packageName, false, next.mUserId); /* TODO: Verify if correct userid */
- } catch (RemoteException e1) {
+ mAtmService.getPackageManagerInternalLocked().notifyComponentUsed(
+ next.packageName, next.mUserId,
+ next.packageName); /* TODO: Verify if correct userid */
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ next.packageName + ": " + e);
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 7a904f810b16..aad17aa16c7f 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -959,20 +959,25 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
}
// Need to update layers on involved displays since they were all paused while
// the animation played. This puts the layers back into the correct order.
- mController.mBuildingFinishLayers = true;
- try {
- for (int i = displays.size() - 1; i >= 0; --i) {
- if (displays.valueAt(i) == null) continue;
- displays.valueAt(i).assignChildLayers(t);
- }
- } finally {
- mController.mBuildingFinishLayers = false;
+ for (int i = displays.size() - 1; i >= 0; --i) {
+ if (displays.valueAt(i) == null) continue;
+ updateDisplayLayers(displays.valueAt(i), t);
}
+
for (int i = 0; i < info.getRootCount(); ++i) {
t.reparent(info.getRoot(i).getLeash(), null);
}
}
+ private static void updateDisplayLayers(DisplayContent dc, SurfaceControl.Transaction t) {
+ dc.mTransitionController.mBuildingFinishLayers = true;
+ try {
+ dc.assignChildLayers(t);
+ } finally {
+ dc.mTransitionController.mBuildingFinishLayers = false;
+ }
+ }
+
/**
* Build a transaction that cleans-up transition-only surfaces (transition root and snapshots).
* This will ALWAYS be applied on transition finish just in-case
@@ -2346,8 +2351,9 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
final WindowContainer<?> wc = sortedTargets.get(i).mContainer;
// Don't include wallpapers since they are in a different DA.
if (isWallpaper(wc)) continue;
- final int endDisplayId = getDisplayId(wc);
- if (endDisplayId < 0) continue;
+ final DisplayContent dc = wc.getDisplayContent();
+ if (dc == null) continue;
+ final int endDisplayId = dc.getDisplayId();
// Check if Root was already created for this display with a higher-Z window
if (outInfo.findRootIndex(endDisplayId) >= 0) continue;
@@ -2369,6 +2375,9 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
final SurfaceControl rootLeash = leashReference.makeAnimationLeash().setName(
"Transition Root: " + leashReference.getName()).build();
rootLeash.setUnreleasedWarningCallSite("Transition.calculateTransitionRoots");
+ // Update layers to start transaction because we prevent assignment during collect, so
+ // the layer of transition root can be correct.
+ updateDisplayLayers(dc, startT);
startT.setLayer(rootLeash, leashReference.getLastLayer());
outInfo.addRootLeash(endDisplayId, rootLeash,
ancestor.getBounds().left, ancestor.getBounds().top);
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index ae05725f81ff..6432ff081c73 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -558,7 +558,9 @@ class TransitionController {
return wc.asWindowState() == null;
}
// Always allow WindowState to assign layers since it won't affect transition.
- return wc.asWindowState() != null || !isPlaying();
+ return wc.asWindowState() != null || (!isPlaying()
+ // Don't assign task while collecting.
+ && !(wc.asTask() != null && isCollecting()));
}
@WindowConfiguration.WindowingMode
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 457a555416c1..dae61da26b68 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1143,6 +1143,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
void onResize() {
+ if (mControllableInsetProvider != null) {
+ mControllableInsetProvider.onWindowContainerBoundsChanged();
+ }
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i);
wc.onParentResize();
@@ -1162,6 +1165,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
void onMovedByResize() {
+ if (mControllableInsetProvider != null) {
+ mControllableInsetProvider.onWindowContainerBoundsChanged();
+ }
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i);
wc.onMovedByResize();
diff --git a/services/core/java/com/android/server/wm/WindowContextListenerController.java b/services/core/java/com/android/server/wm/WindowContextListenerController.java
index 726ae5c61d56..21f251fbc736 100644
--- a/services/core/java/com/android/server/wm/WindowContextListenerController.java
+++ b/services/core/java/com/android/server/wm/WindowContextListenerController.java
@@ -26,7 +26,8 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_ERROR;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.IWindowToken;
+import android.app.servertransaction.WindowContextInfoChangeItem;
+import android.app.servertransaction.WindowContextWindowRemovalItem;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Bundle;
@@ -140,7 +141,7 @@ class WindowContextListenerController {
final WindowContextListenerImpl listener = mListeners.valueAt(i);
if (listener.getWindowContainer().getDisplayContent().getDisplayId() == displayId
&& listener.mHasPendingConfiguration) {
- listener.reportConfigToWindowTokenClient();
+ listener.dispatchWindowContextInfoChange();
}
}
}
@@ -206,7 +207,7 @@ class WindowContextListenerController {
@NonNull
private final WindowProcessController mWpc;
@NonNull
- private final IWindowToken mClientToken;
+ private final IBinder mClientToken;
@NonNull
private WindowContainer<?> mContainer;
/**
@@ -228,7 +229,7 @@ class WindowContextListenerController {
@NonNull IBinder clientToken, @NonNull WindowContainer<?> container,
@WindowType int type, @Nullable Bundle options) {
mWpc = Objects.requireNonNull(wpc);
- mClientToken = IWindowToken.Stub.asInterface(clientToken);
+ mClientToken = clientToken;
mContainer = Objects.requireNonNull(container);
mType = type;
mOptions = options;
@@ -270,7 +271,7 @@ class WindowContextListenerController {
}
private void register(boolean shouldDispatchConfig) {
- final IBinder token = mClientToken.asBinder();
+ final IBinder token = mClientToken;
if (mDeathRecipient == null) {
throw new IllegalStateException("Invalid client token: " + token);
}
@@ -280,7 +281,7 @@ class WindowContextListenerController {
private void unregister() {
mContainer.unregisterWindowContainerListener(this);
- mListeners.remove(mClientToken.asBinder());
+ mListeners.remove(mClientToken);
}
private void clear() {
@@ -290,17 +291,17 @@ class WindowContextListenerController {
@Override
public void onMergedOverrideConfigurationChanged(Configuration mergedOverrideConfig) {
- reportConfigToWindowTokenClient();
+ dispatchWindowContextInfoChange();
}
@Override
public void onDisplayChanged(DisplayContent dc) {
- reportConfigToWindowTokenClient();
+ dispatchWindowContextInfoChange();
}
- private void reportConfigToWindowTokenClient() {
+ private void dispatchWindowContextInfoChange() {
if (mDeathRecipient == null) {
- throw new IllegalStateException("Invalid client token: " + mClientToken.asBinder());
+ throw new IllegalStateException("Invalid client token: " + mClientToken);
}
final DisplayContent dc = mContainer.getDisplayContent();
if (!dc.isReady()) {
@@ -329,19 +330,15 @@ class WindowContextListenerController {
mLastReportedConfig.setTo(config);
mLastReportedDisplay = displayId;
- try {
- // TODO(b/290876897): migrate to dispatch through wpc
- mClientToken.onConfigurationChanged(config, displayId);
- } catch (RemoteException e) {
- ProtoLog.w(WM_ERROR, "Could not report config changes to the window token client.");
- }
+ mWpc.scheduleClientTransactionItem(WindowContextInfoChangeItem.obtain(
+ mClientToken, config, displayId));
mHasPendingConfiguration = false;
}
@Override
public void onRemoved() {
if (mDeathRecipient == null) {
- throw new IllegalStateException("Invalid client token: " + mClientToken.asBinder());
+ throw new IllegalStateException("Invalid client token: " + mClientToken);
}
final WindowToken windowToken = mContainer.asWindowToken();
if (windowToken != null && windowToken.isFromClient()) {
@@ -359,18 +356,13 @@ class WindowContextListenerController {
}
}
mDeathRecipient.unlinkToDeath();
- try {
- // TODO(b/290876897): migrate to dispatch through wpc
- mClientToken.onWindowTokenRemoved();
- } catch (RemoteException e) {
- ProtoLog.w(WM_ERROR, "Could not report token removal to the window token client.");
- }
+ mWpc.scheduleClientTransactionItem(WindowContextWindowRemovalItem.obtain(mClientToken));
unregister();
}
@Override
public String toString() {
- return "WindowContextListenerImpl{clientToken=" + mClientToken.asBinder() + ", "
+ return "WindowContextListenerImpl{clientToken=" + mClientToken + ", "
+ "container=" + mContainer + "}";
}
@@ -384,11 +376,11 @@ class WindowContextListenerController {
}
void linkToDeath() throws RemoteException {
- mClientToken.asBinder().linkToDeath(this, 0);
+ mClientToken.linkToDeath(this, 0);
}
void unlinkToDeath() {
- mClientToken.asBinder().unlinkToDeath(this, 0);
+ mClientToken.unlinkToDeath(this, 0);
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index a84749aa6643..427ab7efed40 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -309,6 +309,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
applyTransaction(wct, -1 /* syncId */, nextTransition, caller,
deferred);
if (needsSetReady) {
+ // TODO(b/294925498): Remove this once we have accurate ready
+ // tracking.
+ if (hasActivityLaunch(wct) && !mService.mRootWindowContainer
+ .allPausedActivitiesComplete()) {
+ // WCT is launching an activity, so we need to wait for its
+ // lifecycle events.
+ return;
+ }
nextTransition.setAllReady();
}
});
@@ -344,6 +352,15 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
}
+ private static boolean hasActivityLaunch(WindowContainerTransaction wct) {
+ for (int i = 0; i < wct.getHierarchyOps().size(); ++i) {
+ if (wct.getHierarchyOps().get(i).getType() == HIERARCHY_OP_TYPE_LAUNCH_TASK) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override
public int startLegacyTransition(int type, @NonNull RemoteAnimationAdapter adapter,
@NonNull IWindowContainerTransactionCallback callback,
@@ -382,18 +399,13 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
@Override
- public int finishTransition(@NonNull IBinder transitionToken,
- @Nullable WindowContainerTransaction t,
- @Nullable IWindowContainerTransactionCallback callback) {
+ public void finishTransition(@NonNull IBinder transitionToken,
+ @Nullable WindowContainerTransaction t) {
enforceTaskPermission("finishTransition()");
final CallerInfo caller = new CallerInfo();
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- int syncId = -1;
- if (t != null && callback != null) {
- syncId = startSyncWithOrganizer(callback);
- }
final Transition transition = Transition.fromBinder(transitionToken);
// apply the incoming transaction before finish in case it alters the visibility
// of the participants.
@@ -402,14 +414,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
// changes of the transition participants will only set visible-requested
// and still let finishTransition handle the participants.
mTransitionController.mFinishingTransition = transition;
- applyTransaction(t, syncId, null /*transition*/, caller, transition);
+ applyTransaction(t, -1 /* syncId */, null /*transition*/, caller, transition);
}
mTransitionController.finishTransition(transition);
mTransitionController.mFinishingTransition = null;
- if (syncId >= 0) {
- setSyncReady(syncId);
- }
- return syncId;
}
} finally {
Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index d7d2b4e9dde2..83e864673fa8 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -55,6 +55,7 @@ import android.app.ActivityThread;
import android.app.BackgroundStartPrivileges;
import android.app.IApplicationThread;
import android.app.ProfilerInfo;
+import android.app.servertransaction.ClientTransactionItem;
import android.app.servertransaction.ConfigurationChangeItem;
import android.content.ComponentName;
import android.content.Context;
@@ -1584,9 +1585,10 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
resolvedConfig.seq = newParentConfig.seq;
}
- void dispatchConfiguration(Configuration config) {
+ void dispatchConfiguration(@NonNull Configuration config) {
mHasPendingConfigurationChange = false;
- if (mThread == null) {
+ final IApplicationThread thread = mThread;
+ if (thread == null) {
if (Build.IS_DEBUGGABLE && mHasImeService) {
// TODO (b/135719017): Temporary log for debugging IME service.
Slog.w(TAG_CONFIGURATION, "Unable to send config for IME proc " + mName
@@ -1611,10 +1613,11 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
}
- scheduleConfigurationChange(mThread, config);
+ scheduleConfigurationChange(thread, config);
}
- private void scheduleConfigurationChange(IApplicationThread thread, Configuration config) {
+ private void scheduleConfigurationChange(@NonNull IApplicationThread thread,
+ @NonNull Configuration config) {
ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending to proc %s new config %s", mName,
config);
if (Build.IS_DEBUGGABLE && mHasImeService) {
@@ -1622,11 +1625,30 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
Slog.v(TAG_CONFIGURATION, "Sending to IME proc " + mName + " new config " + config);
}
mHasCachedConfiguration = false;
+ scheduleClientTransactionItem(thread, ConfigurationChangeItem.obtain(
+ config, mLastTopActivityDeviceId));
+ }
+
+ @VisibleForTesting
+ void scheduleClientTransactionItem(@NonNull ClientTransactionItem transactionItem) {
+ final IApplicationThread thread = mThread;
+ if (thread == null) {
+ if (Build.IS_DEBUGGABLE) {
+ Slog.w(TAG_CONFIGURATION, "Unable to send transaction to client proc " + mName
+ + ": no app thread");
+ }
+ return;
+ }
+ scheduleClientTransactionItem(thread, transactionItem);
+ }
+
+ private void scheduleClientTransactionItem(@NonNull IApplicationThread thread,
+ @NonNull ClientTransactionItem transactionItem) {
try {
- mAtm.getLifecycleManager().scheduleTransaction(thread,
- ConfigurationChangeItem.obtain(config, mLastTopActivityDeviceId));
+ mAtm.getLifecycleManager().scheduleTransaction(thread, transactionItem);
} catch (Exception e) {
- Slog.e(TAG_CONFIGURATION, "Failed to schedule configuration change: " + mOwner, e);
+ Slog.e(TAG_CONFIGURATION, "Failed to schedule ClientTransactionItem="
+ + transactionItem + " owner=" + mOwner, e);
}
}
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index e1de05cf6c7c..11c40d7bcd9b 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -69,7 +69,6 @@
static jclass class_gnssPowerStats;
-static jmethodID method_reportNiNotification;
static jmethodID method_reportGnssPowerStats;
static jmethodID method_reportNfwNotification;
static jmethodID method_isInEmergencySession;
@@ -92,8 +91,6 @@ using android::hardware::hidl_death_recipient;
using android::hardware::gnss::V1_0::GnssLocationFlags;
using android::hardware::gnss::V1_0::IGnssNavigationMessage;
using android::hardware::gnss::V1_0::IGnssNavigationMessageCallback;
-using android::hardware::gnss::V1_0::IGnssNi;
-using android::hardware::gnss::V1_0::IGnssNiCallback;
using android::hardware::gnss::V1_0::IGnssXtra;
using android::hardware::gnss::V1_0::IGnssXtraCallback;
using android::hardware::gnss::V2_0::ElapsedRealtimeFlags;
@@ -127,7 +124,6 @@ using IGnssConfigurationAidl = android::hardware::gnss::IGnssConfiguration;
using GnssLocationAidl = android::hardware::gnss::GnssLocation;
using IGnssAntennaInfoAidl = android::hardware::gnss::IGnssAntennaInfo;
-sp<IGnssNi> gnssNiIface = nullptr;
sp<IGnssPowerIndication> gnssPowerIndicationIface = nullptr;
std::unique_ptr<android::gnss::GnssHal> gnssHal = nullptr;
@@ -195,42 +191,6 @@ Status GnssPowerIndicationCallback::gnssPowerStatsCb(const GnssPowerStats& data)
return Status::ok();
}
-/*
- * GnssNiCallback implements callback methods required by the IGnssNi interface.
- */
-struct GnssNiCallback : public IGnssNiCallback {
- Return<void> niNotifyCb(const IGnssNiCallback::GnssNiNotification& notification)
- override;
-};
-
-Return<void> GnssNiCallback::niNotifyCb(
- const IGnssNiCallback::GnssNiNotification& notification) {
- JNIEnv* env = getJniEnv();
- jstring requestorId = env->NewStringUTF(notification.requestorId.c_str());
- jstring text = env->NewStringUTF(notification.notificationMessage.c_str());
-
- if (requestorId && text) {
- env->CallVoidMethod(mCallbacksObj, method_reportNiNotification,
- notification.notificationId, notification.niType,
- notification.notifyFlags, notification.timeoutSec,
- notification.defaultResponse, requestorId, text,
- notification.requestorIdEncoding,
- notification.notificationIdEncoding);
- } else {
- ALOGE("%s: OOM Error\n", __func__);
- }
-
- if (requestorId) {
- env->DeleteLocalRef(requestorId);
- }
-
- if (text) {
- env->DeleteLocalRef(text);
- }
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Void();
-}
-
/* Initializes the GNSS service handle. */
static void android_location_gnss_hal_GnssNative_set_gps_service_handle() {
gnssHal = std::make_unique<gnss::GnssHal>();
@@ -242,10 +202,6 @@ static void android_location_gnss_hal_GnssNative_class_init_once(JNIEnv* env, jc
android_location_gnss_hal_GnssNative_set_gps_service_handle();
// Cache methodIDs and class IDs.
-
- method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
- "(IIIIILjava/lang/String;Ljava/lang/String;II)V");
-
method_reportNfwNotification = env->GetMethodID(clazz, "reportNfwNotification",
"(Ljava/lang/String;BLjava/lang/String;BLjava/lang/String;BZZ)V");
method_reportGnssPowerStats =
@@ -305,7 +261,6 @@ static void android_location_gnss_hal_GnssNative_init_once(JNIEnv* env, jobject
gnssAntennaInfoIface = gnssHal->getGnssAntennaInfoInterface();
gnssMeasurementCorrectionsIface = gnssHal->getMeasurementCorrectionsInterface();
gnssDebugIface = gnssHal->getGnssDebugInterface();
- gnssNiIface = gnssHal->getGnssNiInterface();
gnssConfigurationIface = gnssHal->getGnssConfigurationInterface();
gnssGeofencingIface = gnssHal->getGnssGeofenceInterface();
gnssBatchingIface = gnssHal->getGnssBatchingInterface();
@@ -376,15 +331,6 @@ static jboolean android_location_gnss_hal_GnssNative_init(JNIEnv* /* env */, jcl
ALOGI("Unable to initialize IGnssGeofencing interface.");
}
- // Set IGnssNi.hal callback.
- sp<IGnssNiCallback> gnssNiCbIface = new GnssNiCallback();
- if (gnssNiIface != nullptr) {
- auto status = gnssNiIface->setCallback(gnssNiCbIface);
- checkHidlReturn(status, "IGnssNi setCallback() failed.");
- } else {
- ALOGI("Unable to initialize IGnssNi interface.");
- }
-
// Set IAGnssRil callback.
if (agnssRilIface == nullptr ||
!agnssRilIface->setCallback(std::make_unique<gnss::AGnssRilCallback>())) {
@@ -592,18 +538,6 @@ static void android_location_gnss_hal_GnssNative_set_agps_server(JNIEnv* env, jc
}
}
-static void android_location_gnss_hal_GnssNative_send_ni_response(JNIEnv* /* env */, jclass,
- jint notifId, jint response) {
- if (gnssNiIface == nullptr) {
- ALOGE("%s: IGnssNi interface not available.", __func__);
- return;
- }
-
- auto result = gnssNiIface->respond(notifId,
- static_cast<IGnssNiCallback::GnssUserResponseType>(response));
- checkHidlReturn(result, "IGnssNi respond() failed.");
-}
-
static jstring android_location_gnss_hal_GnssNative_get_internal_state(JNIEnv* env, jclass) {
/*
* TODO: Create a jobject to represent GnssDebug.
@@ -987,8 +921,6 @@ static const JNINativeMethod sLocationProviderMethods[] = {
reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_set_agps_server)},
{"native_inject_ni_supl_message_data", "([BII)V",
reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_inject_ni_supl_message_data)},
- {"native_send_ni_response", "(II)V",
- reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_send_ni_response)},
{"native_get_internal_state", "()Ljava/lang/String;",
reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_get_internal_state)},
{"native_is_gnss_visibility_control_supported", "()Z",
diff --git a/services/incremental/TEST_MAPPING b/services/incremental/TEST_MAPPING
index cdb1fc6f4079..4af880ded953 100644
--- a/services/incremental/TEST_MAPPING
+++ b/services/incremental/TEST_MAPPING
@@ -27,7 +27,9 @@
},
{
"name": "CtsInstalledLoadingProgressHostTests"
- },
+ }
+ ],
+ "presubmit-large": [
{
"name": "CtsPackageManagerTestCases",
"options": [
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index caa434366a17..57fa12d20de5 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -354,8 +354,6 @@ public final class SystemServer implements Dumpable {
"com.android.server.contentcapture.ContentCaptureManagerService";
private static final String TRANSLATION_MANAGER_SERVICE_CLASS =
"com.android.server.translation.TranslationManagerService";
- private static final String SELECTION_TOOLBAR_MANAGER_SERVICE_CLASS =
- "com.android.server.selectiontoolbar.SelectionToolbarManagerService";
private static final String MUSIC_RECOGNITION_MANAGER_SERVICE_CLASS =
"com.android.server.musicrecognition.MusicRecognitionManagerService";
private static final String AMBIENT_CONTEXT_MANAGER_SERVICE_CLASS =
@@ -2738,13 +2736,6 @@ public final class SystemServer implements Dumpable {
Slog.d(TAG, "TranslationService not defined by OEM");
}
- if (!isTv) {
- // Selection toolbar service
- t.traceBegin("StartSelectionToolbarManagerService");
- mSystemServiceManager.startService(SELECTION_TOOLBAR_MANAGER_SERVICE_CLASS);
- t.traceEnd();
- }
-
// NOTE: ClipboardService depends on ContentCapture and Autofill
t.traceBegin("StartClipboardService");
mSystemServiceManager.startService(ClipboardService.class);
diff --git a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
index 6a349e237ffe..17474fbe1de4 100644
--- a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
@@ -26,7 +26,6 @@ import com.android.server.permission.access.collection.* // ktlint-disable no-wi
import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports
import com.android.server.permission.access.immutable.IndexedMap
import com.android.server.permission.access.permission.AppIdPermissionPolicy
-import com.android.server.permission.access.permission.DevicePermissionPolicy
import com.android.server.permission.access.util.attributeInt
import com.android.server.permission.access.util.attributeInterned
import com.android.server.permission.access.util.forEachTag
@@ -47,7 +46,6 @@ class AccessPolicy private constructor(
getOrPut(policy.subjectScheme) { MutableIndexedMap() }[policy.objectScheme] = policy
}
addPolicy(AppIdPermissionPolicy())
- addPolicy(DevicePermissionPolicy())
addPolicy(AppIdAppOpPolicy())
addPolicy(PackageAppOpPolicy())
} as IndexedMap<String, IndexedMap<String, SchemePolicy>>
diff --git a/services/permission/java/com/android/server/permission/access/AccessState.kt b/services/permission/java/com/android/server/permission/access/AccessState.kt
index 94c878a453c9..4ec32ea53f28 100644
--- a/services/permission/java/com/android/server/permission/access/AccessState.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessState.kt
@@ -329,18 +329,6 @@ typealias MutableAppIdPermissionFlags =
private typealias AppIdPermissionFlagsReference =
MutableReference<AppIdPermissionFlags, MutableAppIdPermissionFlags>
-
-typealias DevicePermissionFlags =
- IndexedReferenceMap<String, IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
-typealias MutableDevicePermissionFlags =
- MutableIndexedReferenceMap<String, IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
-typealias AppIdDevicePermissionFlags =
- IntReferenceMap<DevicePermissionFlags, MutableDevicePermissionFlags>
-typealias MutableAppIdDevicePermissionFlags =
- MutableIntReferenceMap<DevicePermissionFlags, MutableDevicePermissionFlags>
-private typealias AppIdDevicePermissionFlagsReference =
- MutableReference<AppIdDevicePermissionFlags, MutableAppIdDevicePermissionFlags>
-
typealias AppIdAppOpModes =
IntReferenceMap<IndexedMap<String, Int>, MutableIndexedMap<String, Int>>
typealias MutableAppIdAppOpModes =
@@ -358,7 +346,6 @@ private typealias PackageAppOpModesReference =
sealed class UserState(
internal val packageVersionsReference: PackageVersionsReference,
internal val appIdPermissionFlagsReference: AppIdPermissionFlagsReference,
- internal val appIdDevicePermissionFlagsReference: AppIdDevicePermissionFlagsReference,
internal val appIdAppOpModesReference: AppIdAppOpModesReference,
internal val packageAppOpModesReference: PackageAppOpModesReference,
defaultPermissionGrantFingerprint: String?,
@@ -370,9 +357,6 @@ sealed class UserState(
val appIdPermissionFlags: AppIdPermissionFlags
get() = appIdPermissionFlagsReference.get()
- val appIdDevicePermissionFlags: AppIdDevicePermissionFlags
- get() = appIdDevicePermissionFlagsReference.get()
-
val appIdAppOpModes: AppIdAppOpModes
get() = appIdAppOpModesReference.get()
@@ -391,7 +375,6 @@ sealed class UserState(
class MutableUserState private constructor(
packageVersionsReference: PackageVersionsReference,
appIdPermissionFlagsReference: AppIdPermissionFlagsReference,
- appIdDevicePermissionFlagsReference: AppIdDevicePermissionFlagsReference,
appIdAppOpModesReference: AppIdAppOpModesReference,
packageAppOpModesReference: PackageAppOpModesReference,
defaultPermissionGrantFingerprint: String?,
@@ -399,7 +382,6 @@ class MutableUserState private constructor(
) : UserState(
packageVersionsReference,
appIdPermissionFlagsReference,
- appIdDevicePermissionFlagsReference,
appIdAppOpModesReference,
packageAppOpModesReference,
defaultPermissionGrantFingerprint,
@@ -408,7 +390,6 @@ class MutableUserState private constructor(
constructor() : this(
PackageVersionsReference(MutableIndexedMap<String, Int>()),
AppIdPermissionFlagsReference(MutableAppIdPermissionFlags()),
- AppIdDevicePermissionFlagsReference(MutableAppIdDevicePermissionFlags()),
AppIdAppOpModesReference(MutableAppIdAppOpModes()),
PackageAppOpModesReference(MutablePackageAppOpModes()),
null,
@@ -418,7 +399,6 @@ class MutableUserState private constructor(
internal constructor(userState: UserState) : this(
userState.packageVersionsReference.toImmutable(),
userState.appIdPermissionFlagsReference.toImmutable(),
- userState.appIdDevicePermissionFlagsReference.toImmutable(),
userState.appIdAppOpModesReference.toImmutable(),
userState.packageAppOpModesReference.toImmutable(),
userState.defaultPermissionGrantFingerprint,
@@ -430,9 +410,6 @@ class MutableUserState private constructor(
fun mutateAppIdPermissionFlags(): MutableAppIdPermissionFlags =
appIdPermissionFlagsReference.mutate()
- fun mutateAppIdDevicePermissionFlags(): MutableAppIdDevicePermissionFlags =
- appIdDevicePermissionFlagsReference.mutate()
-
fun mutateAppIdAppOpModes(): MutableAppIdAppOpModes = appIdAppOpModesReference.mutate()
fun mutatePackageAppOpModes(): MutablePackageAppOpModes = packageAppOpModesReference.mutate()
diff --git a/services/permission/java/com/android/server/permission/access/AccessUri.kt b/services/permission/java/com/android/server/permission/access/AccessUri.kt
index 1d46ca71fe0f..d1abc0455245 100644
--- a/services/permission/java/com/android/server/permission/access/AccessUri.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessUri.kt
@@ -65,17 +65,6 @@ data class PermissionUri(
}
}
-data class DevicePermissionUri(
- val permissionName: String,
- val deviceId: Int
-) : AccessUri(SCHEME) {
- override fun toString(): String = "$scheme:///$permissionName/$deviceId"
-
- companion object {
- const val SCHEME = "device-permission"
- }
-}
-
data class UidUri(
val uid: Int
) : AccessUri(SCHEME) {
diff --git a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPersistence.kt b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPersistence.kt
deleted file mode 100644
index 37a4a90f8f80..000000000000
--- a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPersistence.kt
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.permission.access.permission
-
-import android.util.Slog
-import com.android.modules.utils.BinaryXmlPullParser
-import com.android.modules.utils.BinaryXmlSerializer
-import com.android.server.permission.access.AccessState
-import com.android.server.permission.access.DevicePermissionFlags
-import com.android.server.permission.access.MutableAccessState
-import com.android.server.permission.access.MutableAppIdDevicePermissionFlags
-import com.android.server.permission.access.MutableDevicePermissionFlags
-import com.android.server.permission.access.WriteMode
-import com.android.server.permission.access.immutable.IndexedMap
-import com.android.server.permission.access.immutable.MutableIndexedMap
-import com.android.server.permission.access.immutable.forEachIndexed
-import com.android.server.permission.access.immutable.forEachReversedIndexed
-import com.android.server.permission.access.immutable.set
-import com.android.server.permission.access.util.andInv
-import com.android.server.permission.access.util.attributeInt
-import com.android.server.permission.access.util.attributeInterned
-import com.android.server.permission.access.util.forEachTag
-import com.android.server.permission.access.util.getAttributeIntOrThrow
-import com.android.server.permission.access.util.getAttributeValueOrThrow
-import com.android.server.permission.access.util.hasBits
-import com.android.server.permission.access.util.tag
-import com.android.server.permission.access.util.tagName
-
-class DevicePermissionPersistence {
- fun BinaryXmlPullParser.parseUserState(state: MutableAccessState, userId: Int) {
- when (tagName) {
- TAG_APP_ID_DEVICE_PERMISSIONS -> parseAppIdDevicePermissions(state, userId)
- else -> {}
- }
- }
-
- private fun BinaryXmlPullParser.parseAppIdDevicePermissions(
- state: MutableAccessState,
- userId: Int
- ) {
- val userState = state.mutateUserState(userId, WriteMode.NONE)!!
- val appIdDevicePermissionFlags = userState.mutateAppIdDevicePermissionFlags()
- forEachTag {
- when (tagName) {
- TAG_APP_ID -> parseAppId(appIdDevicePermissionFlags)
- else -> Slog.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state")
- }
- }
-
- appIdDevicePermissionFlags.forEachReversedIndexed { appIdIndex, appId, _ ->
- if (appId !in state.externalState.appIdPackageNames) {
- Slog.w(LOG_TAG, "Dropping unknown app ID $appId when parsing permission state")
- appIdDevicePermissionFlags.removeAt(appIdIndex)
- userState.requestWriteMode(WriteMode.ASYNCHRONOUS)
- }
- }
- }
-
- private fun BinaryXmlPullParser.parseAppId(
- appIdPermissionFlags: MutableAppIdDevicePermissionFlags
- ) {
- val appId = getAttributeIntOrThrow(ATTR_ID)
- val devicePermissionFlags = MutableDevicePermissionFlags()
- appIdPermissionFlags[appId] = devicePermissionFlags
- forEachTag {
- when (tagName) {
- TAG_DEVICE -> parseDevice(devicePermissionFlags)
- else -> {
- Slog.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state")
- }
- }
- }
- }
-
- private fun BinaryXmlPullParser.parseDevice(
- deviceIdPermissionFlags: MutableDevicePermissionFlags
- ) {
- val deviceId = getAttributeValueOrThrow(ATTR_ID)
- val permissionFlags = MutableIndexedMap<String, Int>()
- deviceIdPermissionFlags.put(deviceId, permissionFlags)
- forEachTag {
- when (tagName) {
- TAG_PERMISSION -> parsePermission(permissionFlags)
- else -> Slog.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state")
- }
- }
- }
-
- private fun BinaryXmlPullParser.parsePermission(
- permissionFlags: MutableIndexedMap<String, Int>
- ) {
- val name = getAttributeValueOrThrow(ATTR_NAME).intern()
- val flags = getAttributeIntOrThrow(ATTR_FLAGS)
- permissionFlags[name] = flags
- }
-
- fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) {
- val appIdDevicePermissionFlags = state.userStates[userId]!!.appIdDevicePermissionFlags
- tag(TAG_APP_ID_DEVICE_PERMISSIONS) {
- appIdDevicePermissionFlags.forEachIndexed { _, appId, devicePermissionFlags ->
- serializeAppId(appId, devicePermissionFlags)
- }
- }
- }
-
- private fun BinaryXmlSerializer.serializeAppId(
- appId: Int,
- devicePermissionFlags: DevicePermissionFlags
- ) {
- tag(TAG_APP_ID) {
- attributeInt(ATTR_ID, appId)
- devicePermissionFlags.forEachIndexed { _, deviceId, permissionFlags ->
- serializeDevice(deviceId, permissionFlags)
- }
- }
- }
-
- private fun BinaryXmlSerializer.serializeDevice(
- deviceId: String,
- permissionFlags: IndexedMap<String, Int>
- ) {
- tag(TAG_DEVICE) {
- attributeInterned(ATTR_ID, deviceId)
- permissionFlags.forEachIndexed { _, name, flags ->
- serializePermission(name, flags)
- }
- }
- }
-
- private fun BinaryXmlSerializer.serializePermission(name: String, flags: Int) {
- tag(TAG_PERMISSION) {
- attributeInterned(ATTR_NAME, name)
- // Never serialize one-time permissions as granted.
- val serializedFlags = if (flags.hasBits(PermissionFlags.ONE_TIME)) {
- flags andInv PermissionFlags.RUNTIME_GRANTED
- } else {
- flags
- }
- attributeInt(ATTR_FLAGS, serializedFlags)
- }
- }
-
- companion object {
- private val LOG_TAG = DevicePermissionPersistence::class.java.simpleName
-
- private const val TAG_APP_ID_DEVICE_PERMISSIONS = "app-id-device-permissions"
- private const val TAG_APP_ID = "app-id"
- private const val TAG_DEVICE = "device"
- private const val TAG_PERMISSION = "permission"
-
- private const val ATTR_ID = "id"
- private const val ATTR_NAME = "name"
- private const val ATTR_FLAGS = "flags"
- }
-} \ No newline at end of file
diff --git a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
deleted file mode 100644
index c0d7546180bf..000000000000
--- a/services/permission/java/com/android/server/permission/access/permission/DevicePermissionPolicy.kt
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.permission.access.permission
-
-import android.util.Slog
-import com.android.modules.utils.BinaryXmlPullParser
-import com.android.modules.utils.BinaryXmlSerializer
-import com.android.server.permission.access.AccessState
-import com.android.server.permission.access.DevicePermissionUri
-import com.android.server.permission.access.GetStateScope
-import com.android.server.permission.access.MutableAccessState
-import com.android.server.permission.access.MutateStateScope
-import com.android.server.permission.access.SchemePolicy
-import com.android.server.permission.access.UidUri
-import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
-import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports
-import com.android.server.permission.access.util.andInv
-import com.android.server.pm.pkg.PackageState
-
-class DevicePermissionPolicy : SchemePolicy() {
- private val persistence = DevicePermissionPersistence()
-
- @Volatile
- private var listeners: IndexedListSet<OnDevicePermissionFlagsChangedListener> =
- MutableIndexedListSet()
- private val listenersLock = Any()
-
- override val subjectScheme: String
- get() = UidUri.SCHEME
-
- override val objectScheme: String
- get() = DevicePermissionUri.SCHEME
-
- override fun GetStateScope.onStateMutated() {
- listeners.forEachIndexed { _, it -> it.onStateMutated() }
- }
-
- override fun MutateStateScope.onAppIdRemoved(appId: Int) {
- newState.userStates.forEachIndexed { userStateIndex, _, userState ->
- if (appId in userState.appIdDevicePermissionFlags) {
- newState.mutateUserStateAt(userStateIndex)
- .mutateAppIdDevicePermissionFlags() -= appId
- }
- }
- }
-
- override fun MutateStateScope.onStorageVolumeMounted(
- volumeUuid: String?,
- packageNames: List<String>,
- isSystemUpdated: Boolean
- ) {
- packageNames.forEachIndexed { _, packageName ->
- val packageState = newState.externalState.packageStates[packageName]!!
- trimPermissionStates(packageState.appId)
- }
- }
-
- override fun MutateStateScope.onPackageAdded(packageState: PackageState) {
- trimPermissionStates(packageState.appId)
- }
-
- override fun MutateStateScope.onPackageRemoved(packageName: String, appId: Int) {
- if (appId in newState.externalState.appIdPackageNames) {
- trimPermissionStates(appId)
- }
- }
-
- override fun MutateStateScope.onPackageUninstalled(
- packageName: String,
- appId: Int,
- userId: Int
- ) {
- resetPermissionStates(packageName, userId)
- }
-
- private fun MutateStateScope.resetPermissionStates(packageName: String, userId: Int) {
- // It's okay to skip resetting permissions for packages that are removed,
- // because their states will be trimmed in onPackageRemoved()/onAppIdRemoved()
- val packageState = newState.externalState.packageStates[packageName] ?: return
- val androidPackage = packageState.androidPackage ?: return
- val appId = packageState.appId
- val appIdPermissionFlags = newState.userStates[userId]!!.appIdDevicePermissionFlags
- androidPackage.requestedPermissions.forEach { permissionName ->
- val isRequestedByOtherPackages = anyPackageInAppId(appId) {
- it.packageName != packageName &&
- permissionName in it.androidPackage!!.requestedPermissions
- }
- if (isRequestedByOtherPackages) {
- return@forEach
- }
- appIdPermissionFlags[appId]?.forEachIndexed { _, deviceId, _ ->
- setPermissionFlags(appId, deviceId, userId, permissionName, 0)
- }
- }
- }
-
- private fun MutateStateScope.trimPermissionStates(appId: Int) {
- val requestedPermissions = MutableIndexedSet<String>()
- forEachPackageInAppId(appId) {
- requestedPermissions += it.androidPackage!!.requestedPermissions
- }
- newState.userStates.forEachIndexed { _, userId, userState ->
- userState.appIdDevicePermissionFlags[appId]?.forEachReversedIndexed {
- _, deviceId, permissionFlags ->
- permissionFlags.forEachReversedIndexed { _, permissionName, _ ->
- if (permissionName !in requestedPermissions) {
- setPermissionFlags(appId, deviceId, userId, permissionName, 0)
- }
- }
- }
- }
- }
-
- private inline fun MutateStateScope.anyPackageInAppId(
- appId: Int,
- state: AccessState = newState,
- predicate: (PackageState) -> Boolean
- ): Boolean {
- val packageNames = state.externalState.appIdPackageNames[appId]!!
- return packageNames.anyIndexed { _, packageName ->
- val packageState = state.externalState.packageStates[packageName]!!
- packageState.androidPackage != null && predicate(packageState)
- }
- }
-
- private inline fun MutateStateScope.forEachPackageInAppId(
- appId: Int,
- state: AccessState = newState,
- action: (PackageState) -> Unit
- ) {
- val packageNames = state.externalState.appIdPackageNames[appId]!!
- packageNames.forEachIndexed { _, packageName ->
- val packageState = state.externalState.packageStates[packageName]!!
- if (packageState.androidPackage != null) {
- action(packageState)
- }
- }
- }
-
- override fun BinaryXmlPullParser.parseUserState(state: MutableAccessState, userId: Int) {
- with(persistence) { this@parseUserState.parseUserState(state, userId) }
- }
-
- override fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) {
- with(persistence) { this@serializeUserState.serializeUserState(state, userId) }
- }
-
- fun GetStateScope.getPermissionFlags(
- appId: Int,
- deviceId: String,
- userId: Int,
- permissionName: String
- ): Int =
- state.userStates[userId]?.appIdDevicePermissionFlags?.get(appId)?.get(deviceId)
- ?.getWithDefault(permissionName, 0) ?: 0
-
- fun MutateStateScope.setPermissionFlags(
- appId: Int,
- deviceId: String,
- userId: Int,
- permissionName: String,
- flags: Int
- ): Boolean =
- updatePermissionFlags(
- appId, deviceId, userId, permissionName, PermissionFlags.MASK_ALL, flags
- )
-
- private fun MutateStateScope.updatePermissionFlags(
- appId: Int,
- deviceId: String,
- userId: Int,
- permissionName: String,
- flagMask: Int,
- flagValues: Int
- ): Boolean {
- if (!isDeviceAwarePermission(permissionName)) {
- Slog.w(LOG_TAG, "$permissionName is not a device aware permission.")
- return false
- }
- val oldFlags = newState.userStates[userId]!!.appIdDevicePermissionFlags[appId]
- ?.get(deviceId).getWithDefault(permissionName, 0)
- val newFlags = (oldFlags andInv flagMask) or (flagValues and flagMask)
- if (oldFlags == newFlags) {
- return false
- }
- val appIdDevicePermissionFlags =
- newState.mutateUserState(userId)!!.mutateAppIdDevicePermissionFlags()
- val devicePermissionFlags = appIdDevicePermissionFlags.mutateOrPut(appId) {
- MutableIndexedReferenceMap()
- }
- val permissionFlags = devicePermissionFlags.mutateOrPut(deviceId) { MutableIndexedMap() }
- permissionFlags.putWithDefault(permissionName, newFlags, 0)
- if (permissionFlags.isEmpty()) {
- devicePermissionFlags -= deviceId
- if (devicePermissionFlags.isEmpty()) {
- appIdDevicePermissionFlags -= appId
- }
- }
- listeners.forEachIndexed { _, it ->
- it.onDevicePermissionFlagsChanged(
- appId, userId, deviceId, permissionName, oldFlags, newFlags
- )
- }
- return true
- }
-
- fun addOnPermissionFlagsChangedListener(listener: OnDevicePermissionFlagsChangedListener) {
- synchronized(listenersLock) {
- listeners = listeners + listener
- }
- }
-
- fun removeOnPermissionFlagsChangedListener(listener: OnDevicePermissionFlagsChangedListener) {
- synchronized(listenersLock) {
- listeners = listeners - listener
- }
- }
-
- private fun isDeviceAwarePermission(permissionName: String): Boolean =
- DEVICE_SUPPORTED_PERMISSIONS.contains(permissionName)
-
- companion object {
- private val LOG_TAG = DevicePermissionPolicy::class.java.simpleName
-
- /**
- * These permissions are supported for virtual devices.
- */
- private val DEVICE_SUPPORTED_PERMISSIONS = indexedSetOf(
- android.Manifest.permission.CAMERA,
- android.Manifest.permission.RECORD_AUDIO
- )
- }
-
- /**
- * TODO: b/289355341 - implement listener for permission changes
- * Listener for permission flags changes.
- */
- abstract class OnDevicePermissionFlagsChangedListener {
- /**
- * Called when a permission flags change has been made to the upcoming new state.
- *
- * Implementations should keep this method fast to avoid stalling the locked state mutation,
- * and only call external code after [onStateMutated] when the new state has actually become
- * the current state visible to external code.
- */
- abstract fun onDevicePermissionFlagsChanged(
- appId: Int,
- userId: Int,
- deviceId: String,
- permissionName: String,
- oldFlags: Int,
- newFlags: Int
- )
-
- /**
- * Called when the upcoming new state has become the current state.
- *
- * Implementations should keep this method fast to avoid stalling the locked state mutation.
- */
- abstract fun onStateMutated()
- }
-} \ No newline at end of file
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index d9f179a6c11b..edacf188b333 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -64,11 +64,9 @@ import com.android.server.LocalServices
import com.android.server.PermissionThread
import com.android.server.ServiceThread
import com.android.server.SystemConfig
-import com.android.server.companion.virtual.VirtualDeviceManagerInternal
import com.android.server.permission.access.AccessCheckingService
import com.android.server.permission.access.AccessState
import com.android.server.permission.access.AppOpUri
-import com.android.server.permission.access.DevicePermissionUri
import com.android.server.permission.access.GetStateScope
import com.android.server.permission.access.MutateStateScope
import com.android.server.permission.access.PermissionUri
@@ -112,9 +110,6 @@ class PermissionService(
private val policy =
service.getSchemePolicy(UidUri.SCHEME, PermissionUri.SCHEME) as AppIdPermissionPolicy
- private val devicePolicy =
- service.getSchemePolicy(UidUri.SCHEME, DevicePermissionUri.SCHEME) as DevicePermissionPolicy
-
private val context = service.context
private lateinit var metricsLogger: MetricsLogger
private lateinit var packageManagerInternal: PackageManagerInternal
@@ -137,8 +132,6 @@ class PermissionService(
private lateinit var permissionControllerManager: PermissionControllerManager
- private lateinit var virtualDeviceManagerInternal: VirtualDeviceManagerInternal
-
/**
* A permission backup might contain apps that are not installed. In this case we delay the
* restoration until the app is installed.
@@ -159,8 +152,6 @@ class PermissionService(
systemConfig = SystemConfig.getInstance()
userManagerInternal = LocalServices.getService(UserManagerInternal::class.java)
userManagerService = UserManagerService.getInstance()
- virtualDeviceManagerInternal =
- LocalServices.getService(VirtualDeviceManagerInternal::class.java)
// The package info cache is the cache for package and permission information.
// Disable the package info and package permission caches locally but leave the
@@ -469,7 +460,7 @@ class PermissionService(
return size
}
- override fun checkUidPermission(uid: Int, permissionName: String, deviceId: Int): Int {
+ override fun checkUidPermission(uid: Int, permissionName: String): Int {
val userId = UserHandle.getUserId(uid)
if (!userManagerInternal.exists(userId)) {
return PackageManager.PERMISSION_DENIED
@@ -491,7 +482,7 @@ class PermissionService(
return PackageManager.PERMISSION_DENIED
}
val isPermissionGranted = service.getState {
- isPermissionGranted(packageState, userId, permissionName, deviceId)
+ isPermissionGranted(packageState, userId, permissionName)
}
return if (isPermissionGranted) {
PackageManager.PERMISSION_GRANTED
@@ -524,12 +515,7 @@ class PermissionService(
return false
}
- override fun checkPermission(
- packageName: String,
- permissionName: String,
- deviceId: Int,
- userId: Int
- ): Int {
+ override fun checkPermission(packageName: String, permissionName: String, userId: Int): Int {
if (!userManagerInternal.exists(userId)) {
return PackageManager.PERMISSION_DENIED
}
@@ -538,7 +524,7 @@ class PermissionService(
.use { it.getPackageState(packageName) } ?: return PackageManager.PERMISSION_DENIED
val isPermissionGranted = service.getState {
- isPermissionGranted(packageState, userId, permissionName, deviceId)
+ isPermissionGranted(packageState, userId, permissionName)
}
return if (isPermissionGranted) {
PackageManager.PERMISSION_GRANTED
@@ -556,21 +542,19 @@ class PermissionService(
private fun GetStateScope.isPermissionGranted(
packageState: PackageState,
userId: Int,
- permissionName: String,
- deviceId: Int
+ permissionName: String
): Boolean {
val appId = packageState.appId
// Note that instant apps can't have shared UIDs, so we only need to check the current
// package state.
val isInstantApp = packageState.getUserStateOrDefault(userId).isInstantApp
- if (isSinglePermissionGranted(appId, userId, isInstantApp, permissionName, deviceId)) {
+ if (isSinglePermissionGranted(appId, userId, isInstantApp, permissionName)) {
return true
}
val fullerPermissionName = FULLER_PERMISSIONS[permissionName]
if (fullerPermissionName != null &&
- isSinglePermissionGranted(appId, userId, isInstantApp, fullerPermissionName, deviceId)
- ) {
+ isSinglePermissionGranted(appId, userId, isInstantApp, fullerPermissionName)) {
return true
}
@@ -584,10 +568,9 @@ class PermissionService(
appId: Int,
userId: Int,
isInstantApp: Boolean,
- permissionName: String,
- deviceId: Int,
+ permissionName: String
): Boolean {
- val flags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
+ val flags = with(policy) { getPermissionFlags(appId, userId, permissionName) }
if (!PermissionFlags.isPermissionGranted(flags)) {
return false
}
@@ -618,8 +601,7 @@ class PermissionService(
?: return emptySet()
return permissionFlags.mapNotNullIndexedTo(ArraySet()) { _, permissionName, _ ->
- if (isPermissionGranted(
- packageState, userId, permissionName, Context.DEVICE_ID_DEFAULT)) {
+ if (isPermissionGranted(packageState, userId, permissionName)) {
permissionName
} else {
null
@@ -658,26 +640,18 @@ class PermissionService(
}
}
- override fun grantRuntimePermission(
- packageName: String,
- permissionName: String,
- deviceId: Int,
- userId: Int
- ) {
- setRuntimePermissionGranted(
- packageName, userId, permissionName, deviceId, isGranted = true
- )
+ override fun grantRuntimePermission(packageName: String, permissionName: String, userId: Int) {
+ setRuntimePermissionGranted(packageName, userId, permissionName, isGranted = true)
}
override fun revokeRuntimePermission(
packageName: String,
permissionName: String,
- deviceId: Int,
userId: Int,
reason: String?
) {
setRuntimePermissionGranted(
- packageName, userId, permissionName, deviceId, isGranted = false, revokeReason = reason
+ packageName, userId, permissionName, isGranted = false, revokeReason = reason
)
}
@@ -686,8 +660,8 @@ class PermissionService(
userId: Int
) {
setRuntimePermissionGranted(
- packageName, userId, Manifest.permission.POST_NOTIFICATIONS, Context.DEVICE_ID_DEFAULT,
- isGranted = false, skipKillUid = true
+ packageName, userId, Manifest.permission.POST_NOTIFICATIONS, isGranted = false,
+ skipKillUid = true
)
}
@@ -699,7 +673,6 @@ class PermissionService(
packageName: String,
userId: Int,
permissionName: String,
- deviceId: Int,
isGranted: Boolean,
skipKillUid: Boolean = false,
revokeReason: String? = null
@@ -775,7 +748,7 @@ class PermissionService(
}
setRuntimePermissionGranted(
- packageState, userId, permissionName, deviceId, isGranted, canManageRolePermission,
+ packageState, userId, permissionName, isGranted, canManageRolePermission,
overridePolicyFixed, reportError = true, methodName
)
}
@@ -809,16 +782,14 @@ class PermissionService(
if (permissionState ==
PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED) {
setRuntimePermissionGranted(
- packageState, userId, permissionName, Context.DEVICE_ID_DEFAULT,
- isGranted = true, canManageRolePermission = false,
- overridePolicyFixed = false, reportError = false,
- "setRequestedPermissionStates"
+ packageState, userId, permissionName, isGranted = true,
+ canManageRolePermission = false, overridePolicyFixed = false,
+ reportError = false, "setRequestedPermissionStates"
)
updatePermissionFlags(
packageState.appId, userId, permissionName,
- Context.DEVICE_ID_DEFAULT,
PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED or
- PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, 0,
+ PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, 0,
canUpdateSystemFlags = false,
reportErrorForUnknownPermission = false,
isPermissionRequested = true, "setRequestedPermissionStates",
@@ -845,7 +816,6 @@ class PermissionService(
packageState: PackageState,
userId: Int,
permissionName: String,
- deviceId: Int,
isGranted: Boolean,
canManageRolePermission: Boolean,
overridePolicyFixed: Boolean,
@@ -901,7 +871,7 @@ class PermissionService(
}
val appId = packageState.appId
- val oldFlags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
+ val oldFlags = with(policy) { getPermissionFlags(appId, userId, permissionName) }
if (permissionName !in androidPackage.requestedPermissions && oldFlags == 0) {
if (reportError) {
@@ -964,7 +934,7 @@ class PermissionService(
return
}
- setPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId, newFlags)
+ with(policy) { setPermissionFlags(appId, userId, permissionName, newFlags) }
if (permission.isRuntime) {
val action = if (isGranted) {
@@ -993,12 +963,7 @@ class PermissionService(
with(appOpPolicy) { setAppOpMode(packageState.appId, userId, appOpName, mode) }
}
- override fun getPermissionFlags(
- packageName: String,
- permissionName: String,
- deviceId: Int,
- userId: Int,
- ): Int {
+ override fun getPermissionFlags(packageName: String, permissionName: String, userId: Int): Int {
if (!userManagerInternal.exists(userId)) {
Slog.w(LOG_TAG, "getPermissionFlags: Unknown user $userId")
return 0
@@ -1029,8 +994,7 @@ class PermissionService(
}
val flags =
- getPermissionFlagsWithPolicy(packageState.appId, userId, permissionName, deviceId)
-
+ with(policy) { getPermissionFlags(packageState.appId, userId, permissionName) }
return PermissionFlags.toApiFlags(flags)
}
}
@@ -1038,7 +1002,6 @@ class PermissionService(
override fun isPermissionRevokedByPolicy(
packageName: String,
permissionName: String,
- deviceId: Int,
userId: Int
): Boolean {
if (!userManagerInternal.exists(userId)) {
@@ -1055,13 +1018,13 @@ class PermissionService(
.use { it.getPackageState(packageName) } ?: return false
service.getState {
- if (isPermissionGranted(packageState, userId, permissionName, deviceId)) {
+ if (isPermissionGranted(packageState, userId, permissionName)) {
return false
}
- val flags =
- getPermissionFlagsWithPolicy(packageState.appId, userId, permissionName, deviceId)
-
+ val flags = with(policy) {
+ getPermissionFlags(packageState.appId, userId, permissionName)
+ }
return flags.hasBits(PermissionFlags.POLICY_FIXED)
}
}
@@ -1083,8 +1046,7 @@ class PermissionService(
override fun shouldShowRequestPermissionRationale(
packageName: String,
permissionName: String,
- deviceId: Int,
- userId: Int,
+ userId: Int
): Boolean {
if (!userManagerInternal.exists(userId)) {
Slog.w(LOG_TAG, "shouldShowRequestPermissionRationale: Unknown user $userId")
@@ -1106,11 +1068,11 @@ class PermissionService(
val flags: Int
service.getState {
- if (isPermissionGranted(packageState, userId, permissionName, deviceId)) {
+ if (isPermissionGranted(packageState, userId, permissionName)) {
return false
}
- flags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
+ flags = with(policy) { getPermissionFlags(appId, userId, permissionName) }
}
if (flags.hasAnyBit(UNREQUESTABLE_MASK)) {
return false
@@ -1142,7 +1104,6 @@ class PermissionService(
flagMask: Int,
flagValues: Int,
enforceAdjustPolicyPermission: Boolean,
- deviceId: Int,
userId: Int
) {
val callingUid = Binder.getCallingUid()
@@ -1238,7 +1199,7 @@ class PermissionService(
val appId = packageState.appId
service.mutateState {
updatePermissionFlags(
- appId, userId, permissionName, deviceId, flagMask, flagValues, canUpdateSystemFlags,
+ appId, userId, permissionName, flagMask, flagValues, canUpdateSystemFlags,
reportErrorForUnknownPermission = true, isPermissionRequested,
"updatePermissionFlags", packageName
)
@@ -1287,9 +1248,8 @@ class PermissionService(
val androidPackage = packageState.androidPackage ?: return@forEach
androidPackage.requestedPermissions.forEach { permissionName ->
updatePermissionFlags(
- packageState.appId, userId, permissionName, Context.DEVICE_ID_DEFAULT,
- flagMask, flagValues, canUpdateSystemFlags,
- reportErrorForUnknownPermission = false,
+ packageState.appId, userId, permissionName, flagMask, flagValues,
+ canUpdateSystemFlags, reportErrorForUnknownPermission = false,
isPermissionRequested = true, "updatePermissionFlagsForAllApps", packageName
)
}
@@ -1304,7 +1264,6 @@ class PermissionService(
appId: Int,
userId: Int,
permissionName: String,
- deviceId: Int,
flagMask: Int,
flagValues: Int,
canUpdateSystemFlags: Boolean,
@@ -1339,7 +1298,7 @@ class PermissionService(
return
}
- val oldFlags = getPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId)
+ val oldFlags = with(policy) { getPermissionFlags(appId, userId, permissionName) }
if (!isPermissionRequested && oldFlags == 0) {
Slog.w(
LOG_TAG, "$methodName: Permission $permissionName isn't requested by package" +
@@ -1349,7 +1308,7 @@ class PermissionService(
}
val newFlags = PermissionFlags.updateFlags(permission, oldFlags, flagMask, flagValues)
- setPermissionFlagsWithPolicy(appId, userId, permissionName, deviceId, newFlags)
+ with(policy) { setPermissionFlags(appId, userId, permissionName, newFlags) }
}
override fun getAllowlistedRestrictedPermissions(
@@ -1406,49 +1365,6 @@ class PermissionService(
)
}
- private fun GetStateScope.getPermissionFlagsWithPolicy(
- appId: Int,
- userId: Int,
- permissionName: String,
- deviceId: Int,
- ): Int =
- if (deviceId == Context.DEVICE_ID_DEFAULT) {
- with(policy) { getPermissionFlags(appId, userId, permissionName) }
- } else {
- val persistentDeviceId = virtualDeviceManagerInternal.getPersistentIdForDevice(deviceId)
- if (persistentDeviceId != null) {
- with(devicePolicy) {
- getPermissionFlags(appId, persistentDeviceId, userId, permissionName)
- }
- } else {
- Slog.e(LOG_TAG, "Invalid deviceId $deviceId, no persistent device ID found.")
- 0
- }
- }
-
- private fun MutateStateScope.setPermissionFlagsWithPolicy(
- appId: Int,
- userId: Int,
- permissionName: String,
- deviceId: Int,
- flags: Int
- ): Boolean =
- if (deviceId == Context.DEVICE_ID_DEFAULT) {
- with(policy) {
- setPermissionFlags(appId, userId, permissionName, flags)
- }
- } else {
- val persistentDeviceId = virtualDeviceManagerInternal.getPersistentIdForDevice(deviceId)
- if (persistentDeviceId != null) {
- with(devicePolicy) {
- setPermissionFlags(appId, persistentDeviceId, userId, permissionName, flags)
- }
- } else {
- Slog.e(LOG_TAG, "Invalid deviceId $deviceId, no cdm association found.")
- false
- }
- }
-
/**
* This method does not enforce checks on the caller, should only be called after
* required checks.
@@ -1623,7 +1539,8 @@ class PermissionService(
) {
service.mutateState {
with(policy) {
- val permissionsFlags = getUidPermissionFlags(appId, userId) ?: return@mutateState
+ val permissionsFlags =
+ getUidPermissionFlags(appId, userId) ?: return@mutateState
val permissions = getPermissions()
androidPackage.requestedPermissions.forEachIndexed { _, requestedPermission ->
@@ -1744,6 +1661,8 @@ class PermissionService(
)
}
+
+
override fun getAppOpPermissionPackages(permissionName: String): Array<String> {
requireNotNull(permissionName) { "permissionName cannot be null" }
val packageNames = ArraySet<String>()
@@ -1960,7 +1879,7 @@ class PermissionService(
println("Permissions:")
withIndent {
userState.appIdPermissionFlags[appId]?.forEachIndexed {
- _, permissionName, flags ->
+ _, permissionName, flags ->
val isGranted = PermissionFlags.isPermissionGranted(flags)
println(
"$permissionName: granted=$isGranted, flags=" +
@@ -1969,20 +1888,6 @@ class PermissionService(
}
}
- userState.appIdDevicePermissionFlags[appId]?.forEachIndexed {
- _, deviceId, devicePermissionFlags ->
- println("Permissions (Device $deviceId):")
- withIndent {
- devicePermissionFlags.forEachIndexed { _, permissionName, flags ->
- val isGranted = PermissionFlags.isPermissionGranted(flags)
- println(
- "$permissionName: granted=$isGranted, flags=" +
- PermissionFlags.toString(flags)
- )
- }
- }
- }
-
println("App ops:")
withIndent {
userState.appIdAppOpModes[appId]?.forEachIndexed {_, appOpName, appOpMode ->
@@ -2507,7 +2412,7 @@ class PermissionService(
}
private fun isAppBackupAndRestoreRunning(uid: Int): Boolean {
- if (checkUidPermission(uid, Manifest.permission.BACKUP, Context.DEVICE_ID_DEFAULT) !=
+ if (checkUidPermission(uid, Manifest.permission.BACKUP) !=
PackageManager.PERMISSION_GRANTED) {
return false
}
diff --git a/services/selectiontoolbar/Android.bp b/services/selectiontoolbar/Android.bp
deleted file mode 100644
index cc6405f97bc3..000000000000
--- a/services/selectiontoolbar/Android.bp
+++ /dev/null
@@ -1,22 +0,0 @@
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-filegroup {
- name: "services.selectiontoolbar-sources",
- srcs: ["java/**/*.java"],
- path: "java",
- visibility: ["//frameworks/base/services"],
-}
-
-java_library_static {
- name: "services.selectiontoolbar",
- defaults: ["platform_service_defaults"],
- srcs: [":services.selectiontoolbar-sources"],
- libs: ["services.core"],
-}
diff --git a/services/selectiontoolbar/OWNERS b/services/selectiontoolbar/OWNERS
deleted file mode 100644
index ed9425cc26c9..000000000000
--- a/services/selectiontoolbar/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include /core/java/android/view/selectiontoolbar/OWNERS
diff --git a/services/selectiontoolbar/java/com/android/server/selectiontoolbar/RemoteSelectionToolbarRenderService.java b/services/selectiontoolbar/java/com/android/server/selectiontoolbar/RemoteSelectionToolbarRenderService.java
deleted file mode 100644
index ae4227bd4f23..000000000000
--- a/services/selectiontoolbar/java/com/android/server/selectiontoolbar/RemoteSelectionToolbarRenderService.java
+++ /dev/null
@@ -1,84 +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.server.selectiontoolbar;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.os.IBinder;
-import android.service.selectiontoolbar.ISelectionToolbarRenderService;
-import android.service.selectiontoolbar.SelectionToolbarRenderService;
-import android.util.Slog;
-import android.view.selectiontoolbar.ISelectionToolbarCallback;
-import android.view.selectiontoolbar.ShowInfo;
-
-import com.android.internal.infra.AbstractRemoteService;
-import com.android.internal.infra.ServiceConnector;
-
-final class RemoteSelectionToolbarRenderService extends
- ServiceConnector.Impl<ISelectionToolbarRenderService> {
- private static final String TAG = "RemoteSelectionToolbarRenderService";
-
- private static final long TIMEOUT_IDLE_UNBIND_MS =
- AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS;
-
- private final ComponentName mComponentName;
- private final IBinder mRemoteCallback;
-
- RemoteSelectionToolbarRenderService(Context context, ComponentName serviceName, int userId,
- IBinder callback) {
- super(context, new Intent(SelectionToolbarRenderService.SERVICE_INTERFACE).setComponent(
- serviceName), 0, userId, ISelectionToolbarRenderService.Stub::asInterface);
- mComponentName = serviceName;
- mRemoteCallback = callback;
- // Bind right away.
- connect();
- }
-
- @Override // from AbstractRemoteService
- protected long getAutoDisconnectTimeoutMs() {
- return TIMEOUT_IDLE_UNBIND_MS;
- }
-
- @Override // from ServiceConnector.Impl
- protected void onServiceConnectionStatusChanged(ISelectionToolbarRenderService service,
- boolean connected) {
- try {
- if (connected) {
- service.onConnected(mRemoteCallback);
- }
- } catch (Exception e) {
- Slog.w(TAG, "Exception calling onConnected().", e);
- }
- }
-
- public ComponentName getComponentName() {
- return mComponentName;
- }
-
- public void onShow(int callingUid, ShowInfo showInfo, ISelectionToolbarCallback callback) {
- run((s) -> s.onShow(callingUid, showInfo, callback));
- }
-
- public void onHide(long widgetToken) {
- run((s) -> s.onHide(widgetToken));
- }
-
- public void onDismiss(int callingUid, long widgetToken) {
- run((s) -> s.onDismiss(callingUid, widgetToken));
- }
-}
diff --git a/services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarManagerService.java b/services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarManagerService.java
deleted file mode 100644
index 3bdf55ccb5c8..000000000000
--- a/services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarManagerService.java
+++ /dev/null
@@ -1,104 +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.server.selectiontoolbar;
-
-import android.content.Context;
-import android.util.Slog;
-import android.view.selectiontoolbar.ISelectionToolbarCallback;
-import android.view.selectiontoolbar.ISelectionToolbarManager;
-import android.view.selectiontoolbar.ShowInfo;
-
-import com.android.internal.util.DumpUtils;
-import com.android.server.infra.AbstractMasterSystemService;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Entry point service for selection toolbar management.
- */
-public final class SelectionToolbarManagerService extends
- AbstractMasterSystemService<SelectionToolbarManagerService,
- SelectionToolbarManagerServiceImpl> {
-
- private static final String TAG = "SelectionToolbarManagerService";
-
- @Override
- public void onStart() {
- publishBinderService(Context.SELECTION_TOOLBAR_SERVICE,
- new SelectionToolbarManagerService.SelectionToolbarManagerServiceStub());
- }
-
- public SelectionToolbarManagerService(Context context) {
- super(context, new SelectionToolbarServiceNameResolver(), /* disallowProperty= */
- null, PACKAGE_UPDATE_POLICY_REFRESH_EAGER);
- }
-
- @Override
- protected SelectionToolbarManagerServiceImpl newServiceLocked(int resolvedUserId,
- boolean disabled) {
- return new SelectionToolbarManagerServiceImpl(this, mLock, resolvedUserId);
- }
-
- final class SelectionToolbarManagerServiceStub extends ISelectionToolbarManager.Stub {
-
- @Override
- public void showToolbar(ShowInfo showInfo, ISelectionToolbarCallback callback, int userId) {
- synchronized (mLock) {
- SelectionToolbarManagerServiceImpl service = getServiceForUserLocked(userId);
- if (service != null) {
- service.showToolbar(showInfo, callback);
- } else {
- Slog.v(TAG, "showToolbar(): no service for " + userId);
- }
- }
- }
-
- @Override
- public void hideToolbar(long widgetToken, int userId) {
- synchronized (mLock) {
- SelectionToolbarManagerServiceImpl service = getServiceForUserLocked(userId);
- if (service != null) {
- service.hideToolbar(widgetToken);
- } else {
- Slog.v(TAG, "hideToolbar(): no service for " + userId);
- }
- }
- }
-
- @Override
- public void dismissToolbar(long widgetToken, int userId) {
- synchronized (mLock) {
- SelectionToolbarManagerServiceImpl service = getServiceForUserLocked(userId);
- if (service != null) {
- service.dismissToolbar(widgetToken);
- } else {
- Slog.v(TAG, "dismissToolbar(): no service for " + userId);
- }
- }
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
-
- synchronized (mLock) {
- dumpLocked("", pw);
- }
- }
- }
-}
diff --git a/services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarManagerServiceImpl.java b/services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarManagerServiceImpl.java
deleted file mode 100644
index c8d153ad37a5..000000000000
--- a/services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarManagerServiceImpl.java
+++ /dev/null
@@ -1,151 +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.server.selectiontoolbar;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.app.AppGlobals;
-import android.content.ComponentName;
-import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.service.selectiontoolbar.ISelectionToolbarRenderServiceCallback;
-import android.util.Slog;
-import android.view.selectiontoolbar.ISelectionToolbarCallback;
-import android.view.selectiontoolbar.ShowInfo;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.server.LocalServices;
-import com.android.server.infra.AbstractPerUserSystemService;
-import com.android.server.input.InputManagerInternal;
-
-final class SelectionToolbarManagerServiceImpl extends
- AbstractPerUserSystemService<SelectionToolbarManagerServiceImpl,
- SelectionToolbarManagerService> {
-
- private static final String TAG = "SelectionToolbarManagerServiceImpl";
-
- @GuardedBy("mLock")
- @Nullable
- private RemoteSelectionToolbarRenderService mRemoteService;
-
- InputManagerInternal mInputManagerInternal;
- private final SelectionToolbarRenderServiceRemoteCallback mRemoteServiceCallback =
- new SelectionToolbarRenderServiceRemoteCallback();
-
- protected SelectionToolbarManagerServiceImpl(@NonNull SelectionToolbarManagerService master,
- @NonNull Object lock, int userId) {
- super(master, lock, userId);
- mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
- updateRemoteServiceLocked();
- }
-
- @GuardedBy("mLock")
- @Override // from PerUserSystemService
- protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
- throws PackageManager.NameNotFoundException {
- return getServiceInfoOrThrow(serviceComponent, mUserId);
- }
-
- @GuardedBy("mLock")
- @Override // from PerUserSystemService
- protected boolean updateLocked(boolean disabled) {
- final boolean enabledChanged = super.updateLocked(disabled);
- updateRemoteServiceLocked();
- return enabledChanged;
- }
-
- /**
- * Updates the reference to the remote service.
- */
- @GuardedBy("mLock")
- private void updateRemoteServiceLocked() {
- if (mRemoteService != null) {
- Slog.d(TAG, "updateRemoteService(): destroying old remote service");
- mRemoteService.unbind();
- mRemoteService = null;
- }
- }
-
- @GuardedBy("mLock")
- void showToolbar(ShowInfo showInfo, ISelectionToolbarCallback callback) {
- final RemoteSelectionToolbarRenderService remoteService = ensureRemoteServiceLocked();
- if (remoteService != null) {
- remoteService.onShow(Binder.getCallingUid(), showInfo, callback);
- }
- }
-
- @GuardedBy("mLock")
- void hideToolbar(long widgetToken) {
- final RemoteSelectionToolbarRenderService remoteService = ensureRemoteServiceLocked();
- if (remoteService != null) {
- remoteService.onHide(widgetToken);
- }
- }
-
- @GuardedBy("mLock")
- void dismissToolbar(long widgetToken) {
- final RemoteSelectionToolbarRenderService remoteService = ensureRemoteServiceLocked();
- if (remoteService != null) {
- remoteService.onDismiss(Binder.getCallingUid(), widgetToken);
- }
- }
-
- @GuardedBy("mLock")
- @Nullable
- private RemoteSelectionToolbarRenderService ensureRemoteServiceLocked() {
- if (mRemoteService == null) {
- final String serviceName = getComponentNameLocked();
- final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
- mRemoteService = new RemoteSelectionToolbarRenderService(getContext(), serviceComponent,
- mUserId, mRemoteServiceCallback);
- }
- return mRemoteService;
- }
-
- private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, @UserIdInt int userId)
- throws PackageManager.NameNotFoundException {
- int flags = PackageManager.GET_META_DATA;
-
- ServiceInfo si = null;
- try {
- si = AppGlobals.getPackageManager().getServiceInfo(comp, flags, userId);
- } catch (RemoteException e) {
- }
- if (si == null) {
- throw new PackageManager.NameNotFoundException("Could not get serviceInfo for "
- + comp.flattenToShortString());
- }
- return si;
- }
-
- private void transferTouchFocus(IBinder source, IBinder target) {
- mInputManagerInternal.transferTouchFocus(source, target);
- }
-
- private final class SelectionToolbarRenderServiceRemoteCallback extends
- ISelectionToolbarRenderServiceCallback.Stub {
-
- @Override
- public void transferTouch(IBinder source, IBinder target) {
- transferTouchFocus(source, target);
- }
- }
-}
diff --git a/services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarServiceNameResolver.java b/services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarServiceNameResolver.java
deleted file mode 100644
index 99b0f25c0a4e..000000000000
--- a/services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarServiceNameResolver.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.server.selectiontoolbar;
-
-import android.service.selectiontoolbar.DefaultSelectionToolbarRenderService;
-
-import com.android.server.infra.ServiceNameResolver;
-
-import java.io.PrintWriter;
-
-final class SelectionToolbarServiceNameResolver implements ServiceNameResolver {
-
- // TODO: move to SysUi or ExtServices
- private static final String SELECTION_TOOLBAR_SERVICE_NAME =
- "android/" + DefaultSelectionToolbarRenderService.class.getName();
-
- @Override
- public String getDefaultServiceName(int userId) {
- return SELECTION_TOOLBAR_SERVICE_NAME;
- }
-
- @Override
- public void dumpShort(PrintWriter pw) {
- pw.print("service="); pw.print(SELECTION_TOOLBAR_SERVICE_NAME);
- }
-
- @Override
- public void dumpShort(PrintWriter pw, int userId) {
- pw.print("defaultService="); pw.print(getDefaultServiceName(userId));
- }
-}
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
index dc92376263a6..74dc8532f163 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
@@ -966,9 +966,11 @@ public class PackageManagerTests extends AndroidTestCase {
}
private static void assertUninstalled(ApplicationInfo info) throws Exception {
- File nativeLibraryFile = new File(info.nativeLibraryDir);
- assertFalse("Native library directory " + info.nativeLibraryDir
- + " should be erased", nativeLibraryFile.exists());
+ if (info.nativeLibraryDir != null) {
+ File nativeLibraryFile = new File(info.nativeLibraryDir);
+ assertFalse("Native library directory " + info.nativeLibraryDir
+ + " should be erased", nativeLibraryFile.exists());
+ }
}
public void deleteFromRawResource(int iFlags, int dFlags) throws Exception {
@@ -2883,14 +2885,15 @@ public class PackageManagerTests extends AndroidTestCase {
break;
}
}
- assertNotNull("activities should not be null", packageInfo.activities);
- assertNotNull("configPreferences should not be null", packageInfo.configPreferences);
- assertNotNull("instrumentation should not be null", packageInfo.instrumentation);
- assertNotNull("permissions should not be null", packageInfo.permissions);
- assertNotNull("providers should not be null", packageInfo.providers);
- assertNotNull("receivers should not be null", packageInfo.receivers);
- assertNotNull("services should not be null", packageInfo.services);
- assertNotNull("signatures should not be null", packageInfo.signatures);
+ assertNotNull("applicationInfo should not be null", packageInfo.applicationInfo);
+ assertNull("activities should be null", packageInfo.activities);
+ assertNull("configPreferences should be null", packageInfo.configPreferences);
+ assertNull("instrumentation should be null", packageInfo.instrumentation);
+ assertNull("permissions should be null", packageInfo.permissions);
+ assertNull("providers should be null", packageInfo.providers);
+ assertNull("receivers should be null", packageInfo.receivers);
+ assertNull("services should be null", packageInfo.services);
+ assertNotNull("signingInfo should not be null", packageInfo.signingInfo);
} finally {
cleanUpInstall(ip);
}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
index 5a733c7ea117..d217d63c5b44 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
@@ -29,7 +29,6 @@ import com.android.server.pm.PackageSettingBuilder
import com.android.server.pm.parsing.pkg.PackageImpl
import com.android.server.pm.pkg.AndroidPackage
import com.android.server.pm.pkg.PackageState
-import com.android.server.pm.pkg.PackageStateImpl
import com.android.server.pm.pkg.PackageUserState
import com.android.server.pm.pkg.PackageUserStateImpl
import com.android.server.pm.pkg.component.ParsedActivity
@@ -125,7 +124,7 @@ class PackageStateTest {
fillMissingData(packageState, pkg as PackageImpl)
- visitType(seenTypes, emptyList(), PackageStateImpl.copy(packageState),
+ visitType(seenTypes, emptyList(), PackageSetting(packageState, true),
PackageState::class.starProjectedType)
visitType(seenTypes, emptyList(), pkg, AndroidPackage::class.starProjectedType)
visitType(seenTypes, emptyList(), packageState.getUserStateOrDefault(0),
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
index da7a6a10895a..d9338a9b12bf 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -22,8 +22,10 @@ import static com.android.server.display.utils.DeviceConfigParsingUtils.displayB
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
@@ -32,6 +34,7 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.hardware.display.DisplayManagerInternal;
import android.os.Temperature;
import android.util.SparseArray;
import android.util.Spline;
@@ -74,8 +77,7 @@ public final class DisplayDeviceConfigTest {
private static final int[] HIGH_AMBIENT_THRESHOLD_OF_PEAK_REFRESH_RATE = new int[]{-1, 30000};
private static final float[] NITS = {2, 500, 800};
private static final float[] BRIGHTNESS = {0, 0.62f, 1};
- private static final Spline NITS_TO_BRIGHTNESS_SPLINE =
- Spline.createSpline(NITS, BRIGHTNESS);
+ private static final Spline NITS_TO_BRIGHTNESS_SPLINE = Spline.createSpline(NITS, BRIGHTNESS);
private DisplayDeviceConfig mDisplayDeviceConfig;
private static final float ZERO_DELTA = 0.0f;
@@ -178,40 +180,174 @@ public final class DisplayDeviceConfigTest {
assertEquals(82, mDisplayDeviceConfig.getDefaultRefreshRateInHbmHdr());
assertEquals(83, mDisplayDeviceConfig.getDefaultRefreshRateInHbmSunlight());
- assertEquals("sensor_12345",
- mDisplayDeviceConfig.getScreenOffBrightnessSensor().type);
- assertEquals("Sensor 12345",
- mDisplayDeviceConfig.getScreenOffBrightnessSensor().name);
+ assertNotNull(mDisplayDeviceConfig.getHostUsiVersion());
+ assertEquals(mDisplayDeviceConfig.getHostUsiVersion().getMajorVersion(), 2);
+ assertEquals(mDisplayDeviceConfig.getHostUsiVersion().getMinorVersion(), 0);
+ }
- assertArrayEquals(new int[]{-1, 10, 20, 30, 40},
- mDisplayDeviceConfig.getScreenOffBrightnessSensorValueToLux());
+ @Test
+ public void testConfigValuesFromConfigResource() {
+ setupDisplayDeviceConfigFromConfigResourceFile();
+ verifyConfigValuesFromConfigResource();
+ }
+
+ @Test
+ public void testThermalRefreshRateThrottlingFromDisplayConfig() throws IOException {
+ setupDisplayDeviceConfigFromDisplayConfigFile();
+
+ SparseArray<SurfaceControl.RefreshRateRange> defaultMap =
+ mDisplayDeviceConfig.getThermalRefreshRateThrottlingData(null);
+ assertNotNull(defaultMap);
+ assertEquals(2, defaultMap.size());
+ assertEquals(30, defaultMap.get(Temperature.THROTTLING_CRITICAL).min, SMALL_DELTA);
+ assertEquals(60, defaultMap.get(Temperature.THROTTLING_CRITICAL).max, SMALL_DELTA);
+ assertEquals(0, defaultMap.get(Temperature.THROTTLING_SHUTDOWN).min, SMALL_DELTA);
+ assertEquals(30, defaultMap.get(Temperature.THROTTLING_SHUTDOWN).max, SMALL_DELTA);
+
+ SparseArray<SurfaceControl.RefreshRateRange> testMap =
+ mDisplayDeviceConfig.getThermalRefreshRateThrottlingData("test");
+ assertNotNull(testMap);
+ assertEquals(1, testMap.size());
+ assertEquals(60, testMap.get(Temperature.THROTTLING_EMERGENCY).min, SMALL_DELTA);
+ assertEquals(90, testMap.get(Temperature.THROTTLING_EMERGENCY).max, SMALL_DELTA);
+ }
+
+ @Test
+ public void testValidLuxThrottling() throws Exception {
+ setupDisplayDeviceConfigFromDisplayConfigFile();
+
+ Map<DisplayDeviceConfig.BrightnessLimitMapType, Map<Float, Float>> luxThrottlingData =
+ mDisplayDeviceConfig.getLuxThrottlingData();
+ assertEquals(2, luxThrottlingData.size());
+
+ Map<Float, Float> adaptiveOnBrightnessPoints = luxThrottlingData.get(
+ DisplayDeviceConfig.BrightnessLimitMapType.ADAPTIVE);
+ assertEquals(2, adaptiveOnBrightnessPoints.size());
+ assertEquals(0.3f, adaptiveOnBrightnessPoints.get(1000f), SMALL_DELTA);
+ assertEquals(0.5f, adaptiveOnBrightnessPoints.get(5000f), SMALL_DELTA);
+
+ Map<Float, Float> adaptiveOffBrightnessPoints = luxThrottlingData.get(
+ DisplayDeviceConfig.BrightnessLimitMapType.DEFAULT);
+ assertEquals(2, adaptiveOffBrightnessPoints.size());
+ assertEquals(0.35f, adaptiveOffBrightnessPoints.get(1500f), SMALL_DELTA);
+ assertEquals(0.55f, adaptiveOffBrightnessPoints.get(5500f), SMALL_DELTA);
+ }
+
+ @Test
+ public void testInvalidLuxThrottling() throws Exception {
+ setupDisplayDeviceConfigFromDisplayConfigFile(
+ getContent(getInvalidLuxThrottling(), getValidProxSensor()));
+
+ Map<DisplayDeviceConfig.BrightnessLimitMapType, Map<Float, Float>> luxThrottlingData =
+ mDisplayDeviceConfig.getLuxThrottlingData();
+ assertEquals(1, luxThrottlingData.size());
+
+ Map<Float, Float> adaptiveOnBrightnessPoints = luxThrottlingData.get(
+ DisplayDeviceConfig.BrightnessLimitMapType.ADAPTIVE);
+ assertEquals(1, adaptiveOnBrightnessPoints.size());
+ assertEquals(0.3f, adaptiveOnBrightnessPoints.get(1000f), SMALL_DELTA);
+ }
+
+ @Test
+ public void testFallbackToConfigResource() throws IOException {
+ setupDisplayDeviceConfigFromConfigResourceFile();
+
+ // Empty display config file
+ setupDisplayDeviceConfigFromDisplayConfigFile(
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<displayConfiguration />\n");
+
+ // We should fall back to the config resource
+ verifyConfigValuesFromConfigResource();
+ }
+
+ @Test
+ public void testDensityMappingFromDisplayConfig() throws IOException {
+ setupDisplayDeviceConfigFromDisplayConfigFile();
+
+ assertEquals(120, mDisplayDeviceConfig.getDensityMapping()
+ .getDensityForResolution(720, 480));
+ assertEquals(213, mDisplayDeviceConfig.getDensityMapping()
+ .getDensityForResolution(1280, 720));
+ assertEquals(320, mDisplayDeviceConfig.getDensityMapping()
+ .getDensityForResolution(1920, 1080));
+ assertEquals(640, mDisplayDeviceConfig.getDensityMapping()
+ .getDensityForResolution(3840, 2160));
+ }
+
+ @Test
+ public void testHighBrightnessModeDataFromDisplayConfig() throws IOException {
+ setupDisplayDeviceConfigFromDisplayConfigFile();
+
+ DisplayDeviceConfig.HighBrightnessModeData hbmData =
+ mDisplayDeviceConfig.getHighBrightnessModeData();
+ assertNotNull(hbmData);
+ assertEquals(BRIGHTNESS[1], hbmData.transitionPoint, ZERO_DELTA);
+ assertEquals(10000, hbmData.minimumLux, ZERO_DELTA);
+ assertEquals(1800 * 1000, hbmData.timeWindowMillis);
+ assertEquals(300 * 1000, hbmData.timeMaxMillis);
+ assertEquals(60 * 1000, hbmData.timeMinMillis);
+ assertFalse(hbmData.allowInLowPowerMode);
+ assertEquals(0.6f, hbmData.minimumHdrPercentOfScreen, ZERO_DELTA);
+
+ List<DisplayManagerInternal.RefreshRateLimitation> refreshRateLimitations =
+ mDisplayDeviceConfig.getRefreshRateLimitations();
+ assertEquals(1, refreshRateLimitations.size());
+ assertEquals(DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE,
+ refreshRateLimitations.get(0).type);
+ assertEquals(120, refreshRateLimitations.get(0).range.min, ZERO_DELTA);
+ assertEquals(120, refreshRateLimitations.get(0).range.max, ZERO_DELTA);
+
+ // Max desired Hdr/SDR ratio upper-bounds the HDR brightness.
+ assertTrue(mDisplayDeviceConfig.hasSdrToHdrRatioSpline());
+ assertEquals(NITS_TO_BRIGHTNESS_SPLINE.interpolate(500 * 1.6f),
+ mDisplayDeviceConfig.getHdrBrightnessFromSdr(
+ NITS_TO_BRIGHTNESS_SPLINE.interpolate(500), Float.POSITIVE_INFINITY),
+ ZERO_DELTA);
+ assertEquals(NITS_TO_BRIGHTNESS_SPLINE.interpolate(500),
+ mDisplayDeviceConfig.getHdrBrightnessFromSdr(
+ NITS_TO_BRIGHTNESS_SPLINE.interpolate(500), 1.0f),
+ ZERO_DELTA);
+ assertEquals(NITS_TO_BRIGHTNESS_SPLINE.interpolate(500 * 1.25f),
+ mDisplayDeviceConfig.getHdrBrightnessFromSdr(
+ NITS_TO_BRIGHTNESS_SPLINE.interpolate(500), 1.25f),
+ SMALL_DELTA);
+ assertEquals(NITS_TO_BRIGHTNESS_SPLINE.interpolate(2 * 4),
+ mDisplayDeviceConfig.getHdrBrightnessFromSdr(
+ NITS_TO_BRIGHTNESS_SPLINE.interpolate(2), Float.POSITIVE_INFINITY),
+ SMALL_DELTA);
+ }
+
+ @Test
+ public void testThermalBrightnessThrottlingDataFromDisplayConfig() throws IOException {
+ setupDisplayDeviceConfigFromDisplayConfigFile();
List<DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel>
defaultThrottlingLevels = new ArrayList<>();
defaultThrottlingLevels.add(
new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel(
- DisplayDeviceConfig.convertThermalStatus(ThermalStatus.light), 0.4f
- ));
+ DisplayDeviceConfig.convertThermalStatus(ThermalStatus.light), 0.4f
+ ));
defaultThrottlingLevels.add(
new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel(
- DisplayDeviceConfig.convertThermalStatus(ThermalStatus.moderate), 0.3f
- ));
+ DisplayDeviceConfig.convertThermalStatus(ThermalStatus.moderate), 0.3f
+ ));
defaultThrottlingLevels.add(
new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel(
- DisplayDeviceConfig.convertThermalStatus(ThermalStatus.severe), 0.2f
- ));
+ DisplayDeviceConfig.convertThermalStatus(ThermalStatus.severe), 0.2f
+ ));
defaultThrottlingLevels.add(
new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel(
- DisplayDeviceConfig.convertThermalStatus(ThermalStatus.critical), 0.1f
- ));
+ DisplayDeviceConfig.convertThermalStatus(ThermalStatus.critical), 0.1f
+ ));
defaultThrottlingLevels.add(
new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel(
- DisplayDeviceConfig.convertThermalStatus(ThermalStatus.emergency), 0.05f
- ));
+ DisplayDeviceConfig.convertThermalStatus(ThermalStatus.emergency), 0.05f
+ ));
defaultThrottlingLevels.add(
new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel(
- DisplayDeviceConfig.convertThermalStatus(ThermalStatus.shutdown), 0.025f
- ));
+ DisplayDeviceConfig.convertThermalStatus(ThermalStatus.shutdown), 0.025f
+ ));
DisplayDeviceConfig.ThermalBrightnessThrottlingData defaultThrottlingData =
new DisplayDeviceConfig.ThermalBrightnessThrottlingData(defaultThrottlingLevels);
@@ -220,28 +356,28 @@ public final class DisplayDeviceConfigTest {
concurrentThrottlingLevels = new ArrayList<>();
concurrentThrottlingLevels.add(
new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel(
- DisplayDeviceConfig.convertThermalStatus(ThermalStatus.light), 0.2f
- ));
+ DisplayDeviceConfig.convertThermalStatus(ThermalStatus.light), 0.2f
+ ));
concurrentThrottlingLevels.add(
new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel(
- DisplayDeviceConfig.convertThermalStatus(ThermalStatus.moderate), 0.15f
- ));
+ DisplayDeviceConfig.convertThermalStatus(ThermalStatus.moderate), 0.15f
+ ));
concurrentThrottlingLevels.add(
new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel(
- DisplayDeviceConfig.convertThermalStatus(ThermalStatus.severe), 0.1f
- ));
+ DisplayDeviceConfig.convertThermalStatus(ThermalStatus.severe), 0.1f
+ ));
concurrentThrottlingLevels.add(
new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel(
- DisplayDeviceConfig.convertThermalStatus(ThermalStatus.critical), 0.05f
- ));
+ DisplayDeviceConfig.convertThermalStatus(ThermalStatus.critical), 0.05f
+ ));
concurrentThrottlingLevels.add(
new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel(
- DisplayDeviceConfig.convertThermalStatus(ThermalStatus.emergency), 0.025f
- ));
+ DisplayDeviceConfig.convertThermalStatus(ThermalStatus.emergency), 0.025f
+ ));
concurrentThrottlingLevels.add(
new DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel(
- DisplayDeviceConfig.convertThermalStatus(ThermalStatus.shutdown), 0.0125f
- ));
+ DisplayDeviceConfig.convertThermalStatus(ThermalStatus.shutdown), 0.0125f
+ ));
DisplayDeviceConfig.ThermalBrightnessThrottlingData concurrentThrottlingData =
new DisplayDeviceConfig.ThermalBrightnessThrottlingData(concurrentThrottlingLevels);
@@ -252,29 +388,87 @@ public final class DisplayDeviceConfigTest {
assertEquals(throttlingDataMap,
mDisplayDeviceConfig.getThermalBrightnessThrottlingDataMapByThrottlingId());
+ }
- assertNotNull(mDisplayDeviceConfig.getHostUsiVersion());
- assertEquals(mDisplayDeviceConfig.getHostUsiVersion().getMajorVersion(), 2);
- assertEquals(mDisplayDeviceConfig.getHostUsiVersion().getMinorVersion(), 0);
+ @Test
+ public void testAmbientLightSensorFromDisplayConfig() throws IOException {
+ setupDisplayDeviceConfigFromDisplayConfigFile();
- // Max desired Hdr/SDR ratio upper-bounds the HDR brightness.
- assertEquals(1.0f,
- mDisplayDeviceConfig.getHdrBrightnessFromSdr(0.62f, Float.POSITIVE_INFINITY),
- ZERO_DELTA);
- assertEquals(0.62f,
- mDisplayDeviceConfig.getHdrBrightnessFromSdr(0.62f, 1.0f),
- ZERO_DELTA);
- assertEquals(0.77787f,
- mDisplayDeviceConfig.getHdrBrightnessFromSdr(0.62f, 1.25f),
- SMALL_DELTA);
+ assertEquals("test_light_sensor",
+ mDisplayDeviceConfig.getAmbientLightSensor().type);
+ assertEquals("Test Ambient Light Sensor",
+ mDisplayDeviceConfig.getAmbientLightSensor().name);
+ assertEquals(60, mDisplayDeviceConfig.getAmbientLightSensor().minRefreshRate, ZERO_DELTA);
+ assertEquals(120, mDisplayDeviceConfig.getAmbientLightSensor().maxRefreshRate, ZERO_DELTA);
+ }
+
+ @Test
+ public void testScreenOffBrightnessSensorFromDisplayConfig() throws IOException {
+ setupDisplayDeviceConfigFromDisplayConfigFile();
+
+ assertEquals("test_binned_brightness_sensor",
+ mDisplayDeviceConfig.getScreenOffBrightnessSensor().type);
+ assertEquals("Test Binned Brightness Sensor",
+ mDisplayDeviceConfig.getScreenOffBrightnessSensor().name);
- // Todo: Add asserts for DensityMapping,
- // HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor.
+ assertArrayEquals(new int[]{ -1, 10, 20, 30, 40 },
+ mDisplayDeviceConfig.getScreenOffBrightnessSensorValueToLux());
}
@Test
- public void testConfigValuesFromConfigResource() {
+ public void testProximitySensorFromDisplayConfig() throws IOException {
+ setupDisplayDeviceConfigFromDisplayConfigFile();
+
+ assertEquals("test_proximity_sensor",
+ mDisplayDeviceConfig.getProximitySensor().type);
+ assertEquals("Test Proximity Sensor",
+ mDisplayDeviceConfig.getProximitySensor().name);
+ }
+
+ @Test
+ public void testProximitySensorWithEmptyValuesFromDisplayConfig() throws IOException {
+ setupDisplayDeviceConfigFromDisplayConfigFile(
+ getContent(getValidLuxThrottling(), getProxSensorWithEmptyValues()));
+ assertNull(mDisplayDeviceConfig.getProximitySensor());
+ }
+
+ @Test
+ public void testBlockingZoneThresholdsFromDisplayConfig() throws IOException {
+ setupDisplayDeviceConfigFromDisplayConfigFile();
+
+ assertArrayEquals(new float[]{ NITS_TO_BRIGHTNESS_SPLINE.interpolate(50),
+ NITS_TO_BRIGHTNESS_SPLINE.interpolate(300),
+ NITS_TO_BRIGHTNESS_SPLINE.interpolate(300), -1},
+ mDisplayDeviceConfig.getLowDisplayBrightnessThresholds(), SMALL_DELTA);
+ assertArrayEquals(new float[]{50, 60, -1, 60},
+ mDisplayDeviceConfig.getLowAmbientBrightnessThresholds(), ZERO_DELTA);
+ assertArrayEquals(new float[]{ NITS_TO_BRIGHTNESS_SPLINE.interpolate(80),
+ NITS_TO_BRIGHTNESS_SPLINE.interpolate(100),
+ NITS_TO_BRIGHTNESS_SPLINE.interpolate(100), -1},
+ mDisplayDeviceConfig.getHighDisplayBrightnessThresholds(), SMALL_DELTA);
+ assertArrayEquals(new float[]{70, 80, -1, 80},
+ mDisplayDeviceConfig.getHighAmbientBrightnessThresholds(), ZERO_DELTA);
+ }
+
+ @Test
+ public void testBlockingZoneThresholdsFromConfigResource() {
setupDisplayDeviceConfigFromConfigResourceFile();
+
+ assertArrayEquals(displayBrightnessThresholdsIntToFloat(
+ LOW_BRIGHTNESS_THRESHOLD_OF_PEAK_REFRESH_RATE),
+ mDisplayDeviceConfig.getLowDisplayBrightnessThresholds(), SMALL_DELTA);
+ assertArrayEquals(ambientBrightnessThresholdsIntToFloat(
+ LOW_AMBIENT_THRESHOLD_OF_PEAK_REFRESH_RATE),
+ mDisplayDeviceConfig.getLowAmbientBrightnessThresholds(), ZERO_DELTA);
+ assertArrayEquals(displayBrightnessThresholdsIntToFloat(
+ HIGH_BRIGHTNESS_THRESHOLD_OF_PEAK_REFRESH_RATE),
+ mDisplayDeviceConfig.getHighDisplayBrightnessThresholds(), SMALL_DELTA);
+ assertArrayEquals(ambientBrightnessThresholdsIntToFloat(
+ HIGH_AMBIENT_THRESHOLD_OF_PEAK_REFRESH_RATE),
+ mDisplayDeviceConfig.getHighAmbientBrightnessThresholds(), ZERO_DELTA);
+ }
+
+ private void verifyConfigValuesFromConfigResource() {
assertNull(mDisplayDeviceConfig.getName());
assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsNits(), new
float[]{2.0f, 200.0f, 600.0f}, ZERO_DELTA);
@@ -342,100 +536,8 @@ public final class DisplayDeviceConfigTest {
assertEquals(mDisplayDeviceConfig.getDefaultRefreshRateInHbmHdr(),
DEFAULT_REFRESH_RATE_IN_HBM_HDR);
- // Todo: Add asserts for ThermalBrightnessThrottlingData, DensityMapping,
- // HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor.
- }
-
- @Test
- public void testThermalRefreshRateThrottlingFromDisplayConfig() throws IOException {
- setupDisplayDeviceConfigFromDisplayConfigFile();
-
- SparseArray<SurfaceControl.RefreshRateRange> defaultMap =
- mDisplayDeviceConfig.getThermalRefreshRateThrottlingData(null);
- assertNotNull(defaultMap);
- assertEquals(2, defaultMap.size());
- assertEquals(30, defaultMap.get(Temperature.THROTTLING_CRITICAL).min, SMALL_DELTA);
- assertEquals(60, defaultMap.get(Temperature.THROTTLING_CRITICAL).max, SMALL_DELTA);
- assertEquals(0, defaultMap.get(Temperature.THROTTLING_SHUTDOWN).min, SMALL_DELTA);
- assertEquals(30, defaultMap.get(Temperature.THROTTLING_SHUTDOWN).max, SMALL_DELTA);
-
- SparseArray<SurfaceControl.RefreshRateRange> testMap =
- mDisplayDeviceConfig.getThermalRefreshRateThrottlingData("test");
- assertNotNull(testMap);
- assertEquals(1, testMap.size());
- assertEquals(60, testMap.get(Temperature.THROTTLING_EMERGENCY).min, SMALL_DELTA);
- assertEquals(90, testMap.get(Temperature.THROTTLING_EMERGENCY).max, SMALL_DELTA);
- }
-
- @Test
- public void testValidLuxThrottling() throws Exception {
- setupDisplayDeviceConfigFromDisplayConfigFile();
-
- Map<DisplayDeviceConfig.BrightnessLimitMapType, Map<Float, Float>> luxThrottlingData =
- mDisplayDeviceConfig.getLuxThrottlingData();
- assertEquals(2, luxThrottlingData.size());
-
- Map<Float, Float> adaptiveOnBrightnessPoints = luxThrottlingData.get(
- DisplayDeviceConfig.BrightnessLimitMapType.ADAPTIVE);
- assertEquals(2, adaptiveOnBrightnessPoints.size());
- assertEquals(0.3f, adaptiveOnBrightnessPoints.get(1000f), SMALL_DELTA);
- assertEquals(0.5f, adaptiveOnBrightnessPoints.get(5000f), SMALL_DELTA);
-
- Map<Float, Float> adaptiveOffBrightnessPoints = luxThrottlingData.get(
- DisplayDeviceConfig.BrightnessLimitMapType.DEFAULT);
- assertEquals(2, adaptiveOffBrightnessPoints.size());
- assertEquals(0.35f, adaptiveOffBrightnessPoints.get(1500f), SMALL_DELTA);
- assertEquals(0.55f, adaptiveOffBrightnessPoints.get(5500f), SMALL_DELTA);
- }
-
- @Test
- public void testInvalidLuxThrottling() throws Exception {
- setupDisplayDeviceConfigFromDisplayConfigFile(getContent(getInvalidLuxThrottling()));
-
- Map<DisplayDeviceConfig.BrightnessLimitMapType, Map<Float, Float>> luxThrottlingData =
- mDisplayDeviceConfig.getLuxThrottlingData();
- assertEquals(1, luxThrottlingData.size());
-
- Map<Float, Float> adaptiveOnBrightnessPoints = luxThrottlingData.get(
- DisplayDeviceConfig.BrightnessLimitMapType.ADAPTIVE);
- assertEquals(1, adaptiveOnBrightnessPoints.size());
- assertEquals(0.3f, adaptiveOnBrightnessPoints.get(1000f), SMALL_DELTA);
- }
-
- @Test
- public void testBlockingZoneThresholdsFromDisplayConfig() throws IOException {
- setupDisplayDeviceConfigFromDisplayConfigFile();
-
- assertArrayEquals(new float[]{ NITS_TO_BRIGHTNESS_SPLINE.interpolate(50),
- NITS_TO_BRIGHTNESS_SPLINE.interpolate(300),
- NITS_TO_BRIGHTNESS_SPLINE.interpolate(300), -1},
- mDisplayDeviceConfig.getLowDisplayBrightnessThresholds(), SMALL_DELTA);
- assertArrayEquals(new float[]{50, 60, -1, 60},
- mDisplayDeviceConfig.getLowAmbientBrightnessThresholds(), ZERO_DELTA);
- assertArrayEquals(new float[]{ NITS_TO_BRIGHTNESS_SPLINE.interpolate(80),
- NITS_TO_BRIGHTNESS_SPLINE.interpolate(100),
- NITS_TO_BRIGHTNESS_SPLINE.interpolate(100), -1},
- mDisplayDeviceConfig.getHighDisplayBrightnessThresholds(), SMALL_DELTA);
- assertArrayEquals(new float[]{70, 80, -1, 80},
- mDisplayDeviceConfig.getHighAmbientBrightnessThresholds(), ZERO_DELTA);
- }
-
- @Test
- public void testBlockingZoneThresholdsFromConfigResource() {
- setupDisplayDeviceConfigFromConfigResourceFile();
-
- assertArrayEquals(displayBrightnessThresholdsIntToFloat(
- LOW_BRIGHTNESS_THRESHOLD_OF_PEAK_REFRESH_RATE),
- mDisplayDeviceConfig.getLowDisplayBrightnessThresholds(), SMALL_DELTA);
- assertArrayEquals(ambientBrightnessThresholdsIntToFloat(
- LOW_AMBIENT_THRESHOLD_OF_PEAK_REFRESH_RATE),
- mDisplayDeviceConfig.getLowAmbientBrightnessThresholds(), ZERO_DELTA);
- assertArrayEquals(displayBrightnessThresholdsIntToFloat(
- HIGH_BRIGHTNESS_THRESHOLD_OF_PEAK_REFRESH_RATE),
- mDisplayDeviceConfig.getHighDisplayBrightnessThresholds(), SMALL_DELTA);
- assertArrayEquals(ambientBrightnessThresholdsIntToFloat(
- HIGH_AMBIENT_THRESHOLD_OF_PEAK_REFRESH_RATE),
- mDisplayDeviceConfig.getHighAmbientBrightnessThresholds(), ZERO_DELTA);
+ assertEquals("test_light_sensor", mDisplayDeviceConfig.getAmbientLightSensor().type);
+ assertEquals("", mDisplayDeviceConfig.getAmbientLightSensor().name);
}
private String getValidLuxThrottling() {
@@ -541,14 +643,50 @@ public final class DisplayDeviceConfigTest {
+ "</refreshRateThrottlingMap>\n";
}
+ private String getValidProxSensor() {
+ return "<proxSensor>\n"
+ + "<type>test_proximity_sensor</type>\n"
+ + "<name>Test Proximity Sensor</name>\n"
+ + "</proxSensor>\n";
+ }
+
+ private String getProxSensorWithEmptyValues() {
+ return "<proxSensor>\n"
+ + "<type></type>\n"
+ + "<name></name>\n"
+ + "</proxSensor>\n";
+ }
+
private String getContent() {
- return getContent(getValidLuxThrottling());
+ return getContent(getValidLuxThrottling(), getValidProxSensor());
}
- private String getContent(String brightnessCapConfig) {
+ private String getContent(String brightnessCapConfig, String proxSensor) {
return "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ "<displayConfiguration>\n"
- + "<name>Example Display</name>"
+ + "<name>Example Display</name>\n"
+ + "<densityMapping>\n"
+ + "<density>\n"
+ + "<height>480</height>\n"
+ + "<width>720</width>\n"
+ + "<density>120</density>\n"
+ + "</density>\n"
+ + "<density>\n"
+ + "<height>720</height>\n"
+ + "<width>1280</width>\n"
+ + "<density>213</density>\n"
+ + "</density>\n"
+ + "<density>\n"
+ + "<height>1080</height>\n"
+ + "<width>1920</width>\n"
+ + "<density>320</density>\n"
+ + "</density>\n"
+ + "<density>\n"
+ + "<height>2160</height>\n"
+ + "<width>3840</width>\n"
+ + "<density>640</density>\n"
+ + "</density>\n"
+ + "</densityMapping>\n"
+ "<screenBrightnessMap>\n"
+ "<point>\n"
+ "<value>" + BRIGHTNESS[0] + "</value>\n"
@@ -578,7 +716,7 @@ public final class DisplayDeviceConfigTest {
+ "</displayBrightnessMapping>\n"
+ "</autoBrightness>\n"
+ "<highBrightnessMode enabled=\"true\">\n"
- + "<transitionPoint>0.62</transitionPoint>\n"
+ + "<transitionPoint>" + BRIGHTNESS[1] + "</transitionPoint>\n"
+ "<minimumLux>10000</minimumLux>\n"
+ "<timing>\n"
+ "<!-- allow for 5 minutes out of every 30 minutes -->\n"
@@ -590,8 +728,8 @@ public final class DisplayDeviceConfigTest {
+ "<minimum>120</minimum>\n"
+ "<maximum>120</maximum>\n"
+ "</refreshRate>\n"
- + "<thermalStatusLimit>light</thermalStatusLimit>\n"
+ "<allowInLowPowerMode>false</allowInLowPowerMode>\n"
+ + "<minimumHdrPercentOfScreen>0.6</minimumHdrPercentOfScreen>\n"
+ "<sdrHdrRatioMap>\n"
+ "<point>\n"
+ "<sdrNits>2.000</sdrNits>\n"
@@ -604,10 +742,19 @@ public final class DisplayDeviceConfigTest {
+ "</sdrHdrRatioMap>\n"
+ "</highBrightnessMode>\n"
+ brightnessCapConfig
+ + "<lightSensor>\n"
+ + "<type>test_light_sensor</type>\n"
+ + "<name>Test Ambient Light Sensor</name>\n"
+ + "<refreshRate>\n"
+ + "<minimum>60</minimum>\n"
+ + "<maximum>120</maximum>\n"
+ + "</refreshRate>\n"
+ + "</lightSensor>\n"
+ "<screenOffBrightnessSensor>\n"
- + "<type>sensor_12345</type>\n"
- + "<name>Sensor 12345</name>\n"
+ + "<type>test_binned_brightness_sensor</type>\n"
+ + "<name>Test Binned Brightness Sensor</name>\n"
+ "</screenOffBrightnessSensor>\n"
+ + proxSensor
+ "<ambientBrightnessChangeThresholds>\n"
+ "<brighteningThresholds>\n"
+ "<minimum>10</minimum>\n"
@@ -946,9 +1093,9 @@ public final class DisplayDeviceConfigTest {
when(mResources.getInteger(R.integer.config_defaultRefreshRate))
.thenReturn(DEFAULT_REFRESH_RATE);
when(mResources.getInteger(R.integer.config_fixedRefreshRateInHighZone))
- .thenReturn(DEFAULT_HIGH_BLOCKING_ZONE_REFRESH_RATE);
+ .thenReturn(DEFAULT_HIGH_BLOCKING_ZONE_REFRESH_RATE);
when(mResources.getInteger(R.integer.config_defaultRefreshRateInZone))
- .thenReturn(DEFAULT_LOW_BLOCKING_ZONE_REFRESH_RATE);
+ .thenReturn(DEFAULT_LOW_BLOCKING_ZONE_REFRESH_RATE);
when(mResources.getIntArray(R.array.config_brightnessThresholdsOfPeakRefreshRate))
.thenReturn(LOW_BRIGHTNESS_THRESHOLD_OF_PEAK_REFRESH_RATE);
when(mResources.getIntArray(R.array.config_ambientThresholdsOfPeakRefreshRate))
@@ -960,11 +1107,14 @@ public final class DisplayDeviceConfigTest {
R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate))
.thenReturn(HIGH_AMBIENT_THRESHOLD_OF_PEAK_REFRESH_RATE);
when(mResources.getInteger(
- R.integer.config_defaultRefreshRateInHbmHdr))
- .thenReturn(DEFAULT_REFRESH_RATE_IN_HBM_HDR);
+ R.integer.config_defaultRefreshRateInHbmHdr))
+ .thenReturn(DEFAULT_REFRESH_RATE_IN_HBM_HDR);
when(mResources.getInteger(
- R.integer.config_defaultRefreshRateInHbmSunlight))
- .thenReturn(DEFAULT_REFRESH_RATE_IN_HBM_SUNLIGHT);
+ R.integer.config_defaultRefreshRateInHbmSunlight))
+ .thenReturn(DEFAULT_REFRESH_RATE_IN_HBM_SUNLIGHT);
+
+ when(mResources.getString(com.android.internal.R.string.config_displayLightSensorType))
+ .thenReturn("test_light_sensor");
mDisplayDeviceConfig = DisplayDeviceConfig.create(mContext, true);
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index bf2311761891..979676e5f1be 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -479,6 +479,41 @@ public class DisplayManagerServiceTest {
}
@Test
+ public void testCreateVirtualRotatesWithContent() throws RemoteException {
+ DisplayManagerService displayManager =
+ new DisplayManagerService(mContext, mBasicInjector);
+ registerDefaultDisplays(displayManager);
+
+ // This is effectively the DisplayManager service published to ServiceManager.
+ DisplayManagerService.BinderService bs = displayManager.new BinderService();
+
+ String uniqueId = "uniqueId --- Rotates with Content Test";
+ int width = 600;
+ int height = 800;
+ int dpi = 320;
+ int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT;
+
+ when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
+ final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
+ VIRTUAL_DISPLAY_NAME, width, height, dpi);
+ builder.setFlags(flags);
+ builder.setUniqueId(uniqueId);
+ int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken,
+ /* projection= */ null, PACKAGE_NAME);
+ verify(mMockProjectionService, never()).setContentRecordingSession(any(),
+ nullable(IMediaProjection.class));
+
+ displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
+
+ // flush the handler
+ displayManager.getDisplayHandler().runWithScissors(() -> {}, /* now= */ 0);
+
+ DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
+ assertNotNull(ddi);
+ assertTrue((ddi.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0);
+ }
+
+ @Test
public void testCreateVirtualDisplayOwnFocus() throws RemoteException {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mBasicInjector);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
index 20654797a5d2..c0128ae38a28 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
@@ -69,7 +69,6 @@ public class LogicalDisplayTest {
mDisplayDeviceInfo.copyFrom(new DisplayDeviceInfo());
mDisplayDeviceInfo.width = DISPLAY_WIDTH;
mDisplayDeviceInfo.height = DISPLAY_HEIGHT;
- mDisplayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
mDisplayDeviceInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
mDisplayDeviceInfo.modeId = MODE_ID;
mDisplayDeviceInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID,
@@ -112,8 +111,18 @@ public class LogicalDisplayTest {
mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false);
assertEquals(expectedPosition, mLogicalDisplay.getDisplayPosition());
- expectedPosition.set(40, -20);
DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.logicalWidth = DISPLAY_WIDTH;
+ displayInfo.logicalHeight = DISPLAY_HEIGHT;
+ // Rotation doesn't matter when the FLAG_ROTATES_WITH_CONTENT is absent.
+ displayInfo.rotation = Surface.ROTATION_90;
+ mLogicalDisplay.setDisplayInfoOverrideFromWindowManagerLocked(displayInfo);
+ mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false);
+ assertEquals(expectedPosition, mLogicalDisplay.getDisplayPosition());
+
+ expectedPosition.set(40, -20);
+ mDisplayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
+ mLogicalDisplay.updateLocked(mDeviceRepo);
displayInfo.logicalWidth = DISPLAY_HEIGHT;
displayInfo.logicalHeight = DISPLAY_WIDTH;
displayInfo.rotation = Surface.ROTATION_90;
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index 88f3b2eb12f8..525bfd75269b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -48,7 +48,6 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
@@ -83,6 +82,7 @@ import android.os.PowerManager;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.SystemClock;
+import android.os.WearModeManagerInternal;
import android.provider.DeviceConfig;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
@@ -147,6 +147,8 @@ public class DeviceIdleControllerTest {
private TelephonyManager mTelephonyManager;
@Mock
private Sensor mOffBodySensor;
+ @Mock
+ private WearModeManagerInternal mWearModeManagerInternal;
class InjectorForTest extends DeviceIdleController.Injector {
ConnectivityManager connectivityManager;
@@ -348,6 +350,9 @@ public class DeviceIdleControllerTest {
mAnyMotionDetector = new AnyMotionDetectorForTest();
mInjector = new InjectorForTest(getContext());
+ doReturn(mWearModeManagerInternal)
+ .when(() -> LocalServices.getService(WearModeManagerInternal.class));
+
setupDeviceIdleController();
}
@@ -2413,22 +2418,20 @@ public class DeviceIdleControllerTest {
}
@Test
- public void testLowLatencyBodyDetection_NoBodySensor() {
- mConstants.USE_BODY_SENSOR = true;
- doReturn(null).when(mSensorManager).getDefaultSensor(
- eq(Sensor.TYPE_LOW_LATENCY_OFFBODY_DETECT), anyBoolean());
+ public void testModeManager_NoModeManagerLocalService_AddListenerNotCalled() {
+ mConstants.USE_MODE_MANAGER = true;
+ doReturn(null)
+ .when(() -> LocalServices.getService(WearModeManagerInternal.class));
cleanupDeviceIdleController();
setupDeviceIdleController();
- verify(mSensorManager, never())
- .registerListener(any(), any(), anyInt());
+ verify(mWearModeManagerInternal, never()).addActiveStateChangeListener(
+ eq(WearModeManagerInternal.QUICK_DOZE_REQUEST_IDENTIFIER), any(),
+ eq(mDeviceIdleController.mModeManagerQuickDozeRequestConsumer));
}
@Test
- public void testLowLatencyBodyDetection_NoBatterySaver_QuickDoze() {
- mConstants.USE_BODY_SENSOR = true;
- doReturn(mOffBodySensor)
- .when(mSensorManager)
- .getDefaultSensor(eq(Sensor.TYPE_LOW_LATENCY_OFFBODY_DETECT), anyBoolean());
+ public void testModeManager_NoBatterySaver_QuickDoze() {
+ mConstants.USE_MODE_MANAGER = true;
PowerSaveState powerSaveState = new PowerSaveState.Builder().setBatterySaverEnabled(
false).build();
when(mPowerManagerInternal.getLowPowerState(anyInt()))
@@ -2436,32 +2439,19 @@ public class DeviceIdleControllerTest {
cleanupDeviceIdleController();
setupDeviceIdleController();
- ArgumentCaptor<SensorEventListener> listenerCaptor =
- ArgumentCaptor.forClass(SensorEventListener.class);
- verify(mSensorManager)
- .registerListener(listenerCaptor.capture(), eq(mOffBodySensor),
- eq(SensorManager.SENSOR_DELAY_NORMAL));
- final SensorEventListener listener = listenerCaptor.getValue();
- // Set the device as off body
- float[] valsZero = {0.0f};
- SensorEvent offbodyEvent = new SensorEvent(mOffBodySensor, 1, 1L, valsZero);
- listener.onSensorChanged(offbodyEvent);
+ // Mode manager quick doze request: true.
+ mDeviceIdleController.mModeManagerQuickDozeRequestConsumer.accept(true);
assertTrue(mDeviceIdleController.isQuickDozeEnabled());
- // Set the device as on body
- float[] valsNonZero = {1.0f};
- SensorEvent onbodyEvent = new SensorEvent(mOffBodySensor, 1, 1L, valsNonZero);
- listener.onSensorChanged(onbodyEvent);
+ // Mode manager quick doze request: false.
+ mDeviceIdleController.mModeManagerQuickDozeRequestConsumer.accept(false);
assertFalse(mDeviceIdleController.isQuickDozeEnabled());
verifyStateConditions(STATE_ACTIVE);
}
@Test
- public void testLowLatencyBodyDetection_WithBatterySaver_QuickDoze() {
- mConstants.USE_BODY_SENSOR = true;
- doReturn(mOffBodySensor)
- .when(mSensorManager)
- .getDefaultSensor(eq(Sensor.TYPE_LOW_LATENCY_OFFBODY_DETECT), anyBoolean());
+ public void testModeManager_WithBatterySaver_QuickDoze() {
+ mConstants.USE_MODE_MANAGER = true;
PowerSaveState powerSaveState = new PowerSaveState.Builder().setBatterySaverEnabled(
true).build();
when(mPowerManagerInternal.getLowPowerState(anyInt()))
@@ -2469,22 +2459,13 @@ public class DeviceIdleControllerTest {
cleanupDeviceIdleController();
setupDeviceIdleController();
- ArgumentCaptor<SensorEventListener> listenerCaptor =
- ArgumentCaptor.forClass(SensorEventListener.class);
- verify(mSensorManager)
- .registerListener(listenerCaptor.capture(), eq(mOffBodySensor),
- eq(SensorManager.SENSOR_DELAY_NORMAL));
- final SensorEventListener listener = listenerCaptor.getValue();
- // Set the device as off body
- float[] valsZero = {0.0f};
- SensorEvent offbodyEvent = new SensorEvent(mOffBodySensor, 1, 1L, valsZero);
- listener.onSensorChanged(offbodyEvent);
+ // Mode manager quick doze request: true.
+ mDeviceIdleController.mModeManagerQuickDozeRequestConsumer.accept(true);
assertTrue(mDeviceIdleController.isQuickDozeEnabled());
- // Set the device as on body. Quick doze should remain enabled because battery saver is on.
- float[] valsNonZero = {1.0f};
- SensorEvent onbodyEvent = new SensorEvent(mOffBodySensor, 1, 1L, valsNonZero);
- listener.onSensorChanged(onbodyEvent);
+ // Mode manager quick doze request: false.
+ // Quick doze should remain enabled because battery saver is on.
+ mDeviceIdleController.mModeManagerQuickDozeRequestConsumer.accept(false);
assertTrue(mDeviceIdleController.isQuickDozeEnabled());
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 1f4563fb2682..b4a66bd75a6e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -105,6 +105,7 @@ import com.android.server.wm.ActivityServiceConnectionsHolder;
import com.android.server.wm.ActivityTaskManagerService;
import com.android.server.wm.WindowProcessController;
+import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -206,8 +207,10 @@ public class MockingOomAdjusterTests {
setFieldValue(AppProfiler.class, profiler, "mProfilerLock", new Object());
doReturn(new ActivityManagerService.ProcessChangeItem()).when(pr)
.enqueueProcessChangeItemLocked(anyInt(), anyInt());
- sService.mOomAdjuster = new OomAdjuster(sService, sService.mProcessList,
- new ActiveUids(sService, false));
+ sService.mOomAdjuster = sService.mConstants.ENABLE_NEW_OOMADJ
+ ? new OomAdjusterModernImpl(sService, sService.mProcessList,
+ new ActiveUids(sService, false))
+ : new OomAdjuster(sService, sService.mProcessList, new ActiveUids(sService, false));
sService.mOomAdjuster.mAdjSeq = 10000;
sService.mWakefulness = new AtomicInteger(PowerManagerInternal.WAKEFULNESS_AWAKE);
if (sService.mConstants.USE_TIERED_CACHED_ADJ) {
@@ -220,6 +223,11 @@ public class MockingOomAdjusterTests {
LocalServices.removeServiceForTest(PackageManagerInternal.class);
}
+ @After
+ public void tearDown() {
+ sService.mOomAdjuster.resetInternal();
+ }
+
private static <T> void setFieldValue(Class clazz, Object obj, String fieldName, T val) {
try {
Field field = clazz.getDeclaredField(fieldName);
@@ -245,10 +253,14 @@ public class MockingOomAdjusterTests {
* Replace the process LRU with the given processes.
* @param apps
*/
+ @SuppressWarnings("GuardedBy")
private void setProcessesToLru(ProcessRecord... apps) {
ArrayList<ProcessRecord> lru = sService.mProcessList.getLruProcessesLOSP();
lru.clear();
Collections.addAll(lru, apps);
+ for (ProcessRecord app : apps) {
+ sService.mOomAdjuster.onProcessBeginLocked(app);
+ }
}
/**
@@ -259,6 +271,7 @@ public class MockingOomAdjusterTests {
@SuppressWarnings("GuardedBy")
private void updateOomAdj(ProcessRecord... apps) {
if (apps.length == 1) {
+ sService.mOomAdjuster.onProcessBeginLocked(apps[0]);
sService.mOomAdjuster.updateOomAdjLocked(apps[0], OOM_ADJ_REASON_NONE);
} else {
setProcessesToLru(apps);
@@ -600,10 +613,13 @@ public class MockingOomAdjusterTests {
s.lastTopAlmostPerceptibleBindRequestUptimeMs = nowUptime;
s.getConnections().clear();
app.mServices.updateHasTopStartedAlmostPerceptibleServices();
+ sService.mOomAdjuster.onProcessBeginLocked(system);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2, app.mState.getSetAdj());
+
+ sService.mOomAdjuster.resetInternal();
}
// Out of grace period but valid binding allows the adjustment.
@@ -620,10 +636,13 @@ public class MockingOomAdjusterTests {
s.lastTopAlmostPerceptibleBindRequestUptimeMs =
nowUptime - 2 * sService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
app.mServices.updateHasTopStartedAlmostPerceptibleServices();
+ sService.mOomAdjuster.onProcessBeginLocked(system);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2, app.mState.getSetAdj());
+
+ sService.mOomAdjuster.resetInternal();
}
// Out of grace period and no valid binding so no adjustment.
@@ -641,10 +660,13 @@ public class MockingOomAdjusterTests {
nowUptime - 2 * sService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
s.getConnections().clear();
app.mServices.updateHasTopStartedAlmostPerceptibleServices();
+ sService.mOomAdjuster.onProcessBeginLocked(system);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertNotEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2, app.mState.getSetAdj());
+
+ sService.mOomAdjuster.resetInternal();
}
}
@@ -657,11 +679,12 @@ public class MockingOomAdjusterTests {
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, true));
system.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
system.mState.setHasTopUi(true);
+ sService.mOomAdjuster.onProcessBeginLocked(system);
// Simulate the system starting and binding to a service in the app.
ServiceRecord s = bindService(app, system,
null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- sService.mOomAdjuster.updateOomAdjLocked(app, OOM_ADJ_REASON_NONE);
+ updateOomAdj(system, app);
assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND,
PERCEPTIBLE_APP_ADJ + 1, SCHED_GROUP_DEFAULT);
@@ -850,6 +873,7 @@ public class MockingOomAdjusterTests {
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+ client.mServices.setTreatLikeActivity(true);
bindService(app, client, null, Context.BIND_WAIVE_PRIORITY
| Context.BIND_TREAT_LIKE_ACTIVITY, mock(IBinder.class));
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
@@ -1006,7 +1030,7 @@ public class MockingOomAdjusterTests {
bindService(app, client, null, Context.BIND_NOT_FOREGROUND, mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- updateOomAdj(app);
+ updateOomAdj(client, app);
assertEquals(PROCESS_STATE_TRANSIENT_BACKGROUND, app.mState.getSetProcState());
assertNoBfsl(app);
@@ -1132,7 +1156,7 @@ public class MockingOomAdjusterTests {
assertNoBfsl(app);
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- updateOomAdj(app);
+ updateOomAdj(client, app);
assertEquals(PERSISTENT_SERVICE_ADJ, app.mState.getSetAdj());
assertBfsl(app);
@@ -1148,7 +1172,7 @@ public class MockingOomAdjusterTests {
bindService(app, client, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
client.mState.setRunningRemoteAnimation(true);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- updateOomAdj(app);
+ updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_LOW_APP_ADJ, app.mState.getSetAdj());
}
@@ -1199,6 +1223,8 @@ public class MockingOomAdjusterTests {
updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_MEDIUM_APP_ADJ + 2, app.mState.getSetAdj());
+
+ sService.mOomAdjuster.resetInternal();
}
{
@@ -1217,6 +1243,8 @@ public class MockingOomAdjusterTests {
doReturn(false).when(wpc).isHeavyWeightProcess();
assertEquals(PERCEPTIBLE_MEDIUM_APP_ADJ + 2, app.mState.getSetAdj());
+
+ sService.mOomAdjuster.resetInternal();
}
{
@@ -1229,9 +1257,11 @@ public class MockingOomAdjusterTests {
mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- sService.mOomAdjuster.updateOomAdjLocked(app, OOM_ADJ_REASON_NONE);
+ updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_APP_ADJ + 1, app.mState.getSetAdj());
+
+ sService.mOomAdjuster.resetInternal();
}
{
@@ -1246,10 +1276,12 @@ public class MockingOomAdjusterTests {
mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- sService.mOomAdjuster.updateOomAdjLocked(app, OOM_ADJ_REASON_NONE);
+ updateOomAdj(client, app);
doReturn(false).when(wpc).isHeavyWeightProcess();
assertEquals(PERCEPTIBLE_APP_ADJ + 1, app.mState.getSetAdj());
+
+ sService.mOomAdjuster.resetInternal();
}
}
@@ -1849,7 +1881,7 @@ public class MockingOomAdjusterTests {
bindService(app1, client1, null, Context.BIND_SCHEDULE_LIKE_TOP_APP, mock(IBinder.class));
bindService(app2, client2, null, Context.BIND_SCHEDULE_LIKE_TOP_APP, mock(IBinder.class));
- updateOomAdj(app1, app2);
+ updateOomAdj(client1, client2, app1, app2);
assertProcStates(app1, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
SCHED_GROUP_TOP_APP);
@@ -1899,6 +1931,8 @@ public class MockingOomAdjusterTests {
s1.getConnections().clear();
s2.getConnections().clear();
+ client1.mServices.removeAllConnections();
+ client2.mServices.removeAllConnections();
client1.mState.setMaxAdj(UNKNOWN_ADJ);
client2.mState.setMaxAdj(UNKNOWN_ADJ);
client1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
@@ -1909,7 +1943,7 @@ public class MockingOomAdjusterTests {
bindService(app2, client2, s2, Context.BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE,
mock(IBinder.class));
- updateOomAdj(app1, app2);
+ updateOomAdj(client1, client2, app1, app2);
// VISIBLE_APP_ADJ is the max oom-adj for BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE.
assertProcStates(app1, PROCESS_STATE_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
@@ -1922,7 +1956,7 @@ public class MockingOomAdjusterTests {
doReturn(client2).when(sService).getTopApp();
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- sService.mOomAdjuster.updateOomAdjLocked(app2, OOM_ADJ_REASON_NONE);
+ updateOomAdj(client2, app2);
assertProcStates(app2, PROCESS_STATE_BOUND_TOP, VISIBLE_APP_ADJ,
SCHED_GROUP_DEFAULT);
}
@@ -1977,6 +2011,7 @@ public class MockingOomAdjusterTests {
app.setPendingFinishAttach(true);
app.mState.setHasForegroundActivities(false);
+ sService.mOomAdjuster.onProcessBeginLocked(app);
sService.mOomAdjuster.setAttachingProcessStatesLSP(app);
updateOomAdj(app);
@@ -1991,7 +2026,9 @@ public class MockingOomAdjusterTests {
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
app.setPendingFinishAttach(true);
app.mState.setHasForegroundActivities(true);
+ doReturn(app).when(sService).getTopApp();
+ sService.mOomAdjuster.onProcessBeginLocked(app);
sService.mOomAdjuster.setAttachingProcessStatesLSP(app);
updateOomAdj(app);
@@ -2088,7 +2125,7 @@ public class MockingOomAdjusterTests {
anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
doNothing().when(sService.mServices)
.scheduleServiceTimeoutLocked(any(ProcessRecord.class));
- sService.mOomAdjuster.updateOomAdjLocked(client1, OOM_ADJ_REASON_NONE);
+ updateOomAdj(client1, client2, app1, app2, app3);
assertEquals(PROCESS_STATE_CACHED_EMPTY, client1.mState.getSetProcState());
assertEquals(PROCESS_STATE_SERVICE, app1.mState.getSetProcState());
@@ -2426,6 +2463,8 @@ public class MockingOomAdjusterTests {
lru.clear();
lru.add(app2);
lru.add(app);
+ sService.mOomAdjuster.onProcessBeginLocked(app2);
+ sService.mOomAdjuster.onProcessBeginLocked(app);
final ComponentName cn = ComponentName.unflattenFromString(
MOCKAPP_PACKAGENAME + "/.TestService");
@@ -2528,7 +2567,7 @@ public class MockingOomAdjusterTests {
doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
doReturn(app).when(sService).getTopApp();
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- sService.mOomAdjuster.updateOomAdjLocked(app, OOM_ADJ_REASON_NONE);
+ updateOomAdj(app);
assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java
index 2d962acfe665..1a8b12a00714 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java
@@ -686,9 +686,6 @@ public final class FakeGnssHal extends GnssNative.GnssHal {
}
@Override
- protected void sendNiResponse(int notificationId, int userResponse) {}
-
- @Override
protected void requestPowerStats() {
Objects.requireNonNull(mGnssNative).reportGnssPowerStats(mState.mPowerStats);
}
diff --git a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
index 0b1e3386cbac..d6d5264257e6 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -141,7 +141,7 @@ import java.util.concurrent.atomic.AtomicReference;
* Tests for {@link com.android.server.power.PowerManagerService}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:PowerManagerServiceTest
+ * atest PowerServiceTests:PowerManagerServiceTest
*/
@SuppressWarnings("GuardedBy")
@RunWith(TestParameterInjector.class)
@@ -240,6 +240,10 @@ public class PowerManagerServiceTest {
cr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
when(mContextSpy.getContentResolver()).thenReturn(cr);
+ when(mResourcesSpy.getBoolean(com.android.internal.R.bool.config_dreamsSupported))
+ .thenReturn(true);
+ when(mResourcesSpy.getBoolean(com.android.internal.R.bool.config_dreamsEnabledByDefault))
+ .thenReturn(true);
Settings.Global.putInt(mContextSpy.getContentResolver(),
Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
Settings.Secure.putInt(mContextSpy.getContentResolver(),
@@ -1084,13 +1088,9 @@ public class PowerManagerServiceTest {
@SuppressWarnings("GuardedBy")
@Test
public void testScreensaverActivateOnSleepEnabled_powered_afterTimeout_goesToDreaming() {
- when(mResourcesSpy.getBoolean(com.android.internal.R.bool.config_dreamsSupported))
- .thenReturn(true);
when(mBatteryManagerInternalMock.isPowered(anyInt())).thenReturn(true);
Settings.Secure.putInt(mContextSpy.getContentResolver(),
Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1);
- Settings.Secure.putInt(mContextSpy.getContentResolver(),
- Settings.Secure.SCREENSAVER_ENABLED, 1);
doAnswer(inv -> {
when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
@@ -1112,8 +1112,6 @@ public class PowerManagerServiceTest {
public void testAmbientSuppression_disablesDreamingAndWakesDevice() {
Settings.Secure.putInt(mContextSpy.getContentResolver(),
Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1);
- Settings.Secure.putInt(mContextSpy.getContentResolver(),
- Settings.Secure.SCREENSAVER_ENABLED, 1);
setDreamsDisabledByAmbientModeSuppressionConfig(true);
setMinimumScreenOffTimeoutConfig(10000);
@@ -1141,8 +1139,6 @@ public class PowerManagerServiceTest {
public void testAmbientSuppressionDisabled_shouldNotWakeDevice() {
Settings.Secure.putInt(mContextSpy.getContentResolver(),
Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1);
- Settings.Secure.putInt(mContextSpy.getContentResolver(),
- Settings.Secure.SCREENSAVER_ENABLED, 1);
setDreamsDisabledByAmbientModeSuppressionConfig(false);
setMinimumScreenOffTimeoutConfig(10000);
@@ -1169,8 +1165,6 @@ public class PowerManagerServiceTest {
public void testAmbientSuppression_doesNotAffectDreamForcing() {
Settings.Secure.putInt(mContextSpy.getContentResolver(),
Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1);
- Settings.Secure.putInt(mContextSpy.getContentResolver(),
- Settings.Secure.SCREENSAVER_ENABLED, 1);
setDreamsDisabledByAmbientModeSuppressionConfig(true);
setMinimumScreenOffTimeoutConfig(10000);
@@ -1196,8 +1190,6 @@ public class PowerManagerServiceTest {
public void testBatteryDrainDuringDream() {
Settings.Secure.putInt(mContextSpy.getContentResolver(),
Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1);
- Settings.Secure.putInt(mContextSpy.getContentResolver(),
- Settings.Secure.SCREENSAVER_ENABLED, 1);
setMinimumScreenOffTimeoutConfig(100);
setDreamsBatteryLevelDrainConfig(5);
diff --git a/services/tests/powerstatstests/Android.bp b/services/tests/powerstatstests/Android.bp
new file mode 100644
index 000000000000..05acd9b8eeb1
--- /dev/null
+++ b/services/tests/powerstatstests/Android.bp
@@ -0,0 +1,52 @@
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "PowerStatsTests",
+
+ // Include all test java files.
+ srcs: [
+ "src/**/*.java",
+ ],
+
+ static_libs: [
+ "services.core",
+ "coretests-aidl",
+ "platformprotosnano",
+ "junit",
+ "truth-prebuilt",
+ "androidx.test.runner",
+ "androidx.test.ext.junit",
+ "androidx.test.ext.truth",
+ "androidx.test.uiautomator_uiautomator",
+ "mockito-target-minus-junit4",
+ "servicestests-utils",
+ ],
+
+ libs: [
+ "android.test.base",
+ ],
+
+ resource_dirs: ["res/"],
+
+ data: [
+ ":BstatsTestApp",
+ ],
+
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+
+ platform_apis: true,
+
+ certificate: "platform",
+
+ dxflags: ["--multi-dex"],
+
+ optimize: {
+ enabled: false,
+ },
+}
diff --git a/services/tests/powerstatstests/AndroidManifest.xml b/services/tests/powerstatstests/AndroidManifest.xml
new file mode 100644
index 000000000000..d3a88d2bc38c
--- /dev/null
+++ b/services/tests/powerstatstests/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.powerstatstests">
+
+ <uses-permission android:name="android.permission.BATTERY_STATS" />
+ <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+ <uses-permission android:name="android.permission.MANAGE_USERS"/>
+
+ <queries>
+ <package android:name="com.android.coretests.apps.bstatstestapp" />
+ </queries>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.powerstatstests"
+ android:label="BatteryStats and PowerStats Services Tests"/>
+</manifest>
diff --git a/services/tests/powerstatstests/AndroidTest.xml b/services/tests/powerstatstests/AndroidTest.xml
new file mode 100644
index 000000000000..79b07e812b28
--- /dev/null
+++ b/services/tests/powerstatstests/AndroidTest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs Power Stats Tests.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="install-arg" value="-t" />
+ <option name="test-file-name" value="PowerStatsTests.apk" />
+ <option name="test-file-name" value="BstatsTestApp.apk" />
+ </target_preparer>
+
+ <option name="test-tag" value="PowerStatsTests" />
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.frameworks.powerstatstests" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
+ </test>
+</configuration>
diff --git a/core/tests/coretests/BstatsTestApp/Android.bp b/services/tests/powerstatstests/BstatsTestApp/Android.bp
index c82da9e7b449..c82da9e7b449 100644
--- a/core/tests/coretests/BstatsTestApp/Android.bp
+++ b/services/tests/powerstatstests/BstatsTestApp/Android.bp
diff --git a/core/tests/coretests/BstatsTestApp/AndroidManifest.xml b/services/tests/powerstatstests/BstatsTestApp/AndroidManifest.xml
index fcb1e71cc3f5..fcb1e71cc3f5 100644
--- a/core/tests/coretests/BstatsTestApp/AndroidManifest.xml
+++ b/services/tests/powerstatstests/BstatsTestApp/AndroidManifest.xml
diff --git a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/BaseCmdReceiver.java b/services/tests/powerstatstests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/BaseCmdReceiver.java
index 2601f3571b98..2601f3571b98 100644
--- a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/BaseCmdReceiver.java
+++ b/services/tests/powerstatstests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/BaseCmdReceiver.java
diff --git a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/Common.java b/services/tests/powerstatstests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/Common.java
index d192fbd66c89..c731e536d032 100644
--- a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/Common.java
+++ b/services/tests/powerstatstests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/Common.java
@@ -15,8 +15,6 @@
*/
package com.android.coretests.apps.bstatstestapp;
-import com.android.frameworks.coretests.aidl.ICmdCallback;
-
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
@@ -24,6 +22,8 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
+import com.android.frameworks.coretests.aidl.ICmdCallback;
+
public class Common {
private static final String EXTRA_KEY_CMD_RECEIVER = "cmd_receiver";
diff --git a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/IsolatedTestService.java b/services/tests/powerstatstests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/IsolatedTestService.java
index 892f60e8530f..892f60e8530f 100644
--- a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/IsolatedTestService.java
+++ b/services/tests/powerstatstests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/IsolatedTestService.java
diff --git a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestActivity.java b/services/tests/powerstatstests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestActivity.java
index 5c551d54b4d5..5c551d54b4d5 100644
--- a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestActivity.java
+++ b/services/tests/powerstatstests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestActivity.java
diff --git a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java b/services/tests/powerstatstests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java
index 0cd0643ee8c0..0cd0643ee8c0 100644
--- a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java
+++ b/services/tests/powerstatstests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java
diff --git a/services/tests/servicestests/src/com/android/server/powerstats/OWNERS b/services/tests/powerstatstests/OWNERS
index 12f13ea63db0..9ed0e051738d 100644
--- a/services/tests/servicestests/src/com/android/server/powerstats/OWNERS
+++ b/services/tests/powerstatstests/OWNERS
@@ -1 +1,4 @@
+# Bug component: 987260
+
+include /BATTERY_STATS_OWNERS
include /services/core/java/com/android/server/powerstats/OWNERS
diff --git a/services/tests/powerstatstests/TEST_MAPPING b/services/tests/powerstatstests/TEST_MAPPING
new file mode 100644
index 000000000000..e1eb1e4fc0db
--- /dev/null
+++ b/services/tests/powerstatstests/TEST_MAPPING
@@ -0,0 +1,22 @@
+{
+ "presubmit": [
+ {
+ "name": "PowerStatsTests",
+ "options": [
+ {"include-filter": "com.android.server.power.stats"},
+ {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
+ {"exclude-annotation": "androidx.test.filters.FlakyTest"},
+ {"exclude-annotation": "org.junit.Ignore"}
+ ]
+ }
+ ],
+ "postsubmit": [
+ {
+ "name": "PowerStatsTests",
+ "options": [
+ {"include-filter": "com.android.server.power.stats"},
+ {"exclude-annotation": "org.junit.Ignore"}
+ ]
+ }
+ ]
+}
diff --git a/services/tests/servicestests/res/xml/irq_device_map_1.xml b/services/tests/powerstatstests/res/xml/irq_device_map_1.xml
index 1f1a77b437ab..1f1a77b437ab 100644
--- a/services/tests/servicestests/res/xml/irq_device_map_1.xml
+++ b/services/tests/powerstatstests/res/xml/irq_device_map_1.xml
diff --git a/services/tests/servicestests/res/xml/irq_device_map_2.xml b/services/tests/powerstatstests/res/xml/irq_device_map_2.xml
index 508c98d871da..508c98d871da 100644
--- a/services/tests/servicestests/res/xml/irq_device_map_2.xml
+++ b/services/tests/powerstatstests/res/xml/irq_device_map_2.xml
diff --git a/services/tests/servicestests/res/xml/irq_device_map_3.xml b/services/tests/powerstatstests/res/xml/irq_device_map_3.xml
index fd55428c48df..fd55428c48df 100644
--- a/services/tests/servicestests/res/xml/irq_device_map_3.xml
+++ b/services/tests/powerstatstests/res/xml/irq_device_map_3.xml
diff --git a/services/tests/servicestests/res/xml/power_profile_test_legacy_modem.xml b/services/tests/powerstatstests/res/xml/power_profile_test_legacy_modem.xml
index 5335f9640738..5335f9640738 100644
--- a/services/tests/servicestests/res/xml/power_profile_test_legacy_modem.xml
+++ b/services/tests/powerstatstests/res/xml/power_profile_test_legacy_modem.xml
diff --git a/services/tests/servicestests/res/xml/power_profile_test_modem_calculator.xml b/services/tests/powerstatstests/res/xml/power_profile_test_modem_calculator.xml
index f57bc0f70b5d..f57bc0f70b5d 100644
--- a/services/tests/servicestests/res/xml/power_profile_test_modem_calculator.xml
+++ b/services/tests/powerstatstests/res/xml/power_profile_test_modem_calculator.xml
diff --git a/services/tests/servicestests/res/xml/power_profile_test_modem_calculator_multiactive.xml b/services/tests/powerstatstests/res/xml/power_profile_test_modem_calculator_multiactive.xml
index 4f5e674c60f5..4f5e674c60f5 100644
--- a/services/tests/servicestests/res/xml/power_profile_test_modem_calculator_multiactive.xml
+++ b/services/tests/powerstatstests/res/xml/power_profile_test_modem_calculator_multiactive.xml
diff --git a/services/tests/servicestests/res/xml/power_profile_test_modem_default.xml b/services/tests/powerstatstests/res/xml/power_profile_test_modem_default.xml
index ab016fbb1f5d..ab016fbb1f5d 100644
--- a/services/tests/servicestests/res/xml/power_profile_test_modem_default.xml
+++ b/services/tests/powerstatstests/res/xml/power_profile_test_modem_default.xml
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/AmbientDisplayPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/AmbientDisplayPowerCalculatorTest.java
index 319a280d10cc..319a280d10cc 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/AmbientDisplayPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/AmbientDisplayPowerCalculatorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/AudioPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/AudioPowerCalculatorTest.java
index fb367b24168e..fb367b24168e 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/AudioPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/AudioPowerCalculatorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryChargeCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryChargeCalculatorTest.java
index 4ea0805ffaa7..4ea0805ffaa7 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryChargeCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryChargeCalculatorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java
index 5a2d2e3d33fd..5a2d2e3d33fd 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsBackgroundStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsBackgroundStatsTest.java
index 4d3fcb611f24..4d3fcb611f24 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsBackgroundStatsTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsBackgroundStatsTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsBinderCallStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsBinderCallStatsTest.java
index 3f101a96d36c..3f101a96d36c 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsBinderCallStatsTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsBinderCallStatsTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsCounterTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsCounterTest.java
index 326639c54495..326639c54495 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsCounterTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsCounterTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsCpuTimesTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsCpuTimesTest.java
index 55ffa1a15a6b..55ffa1a15a6b 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsCpuTimesTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsCpuTimesTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsDualTimerTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsDualTimerTest.java
index d6acf8da7431..d6acf8da7431 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsDualTimerTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsDualTimerTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsDurationTimerTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsDurationTimerTest.java
index 99520cd6fbad..99520cd6fbad 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsDurationTimerTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsDurationTimerTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java
index 4fde73bd8408..4fde73bd8408 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
index eb3bd0ebb536..48ba765c3968 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
@@ -30,6 +30,7 @@ import android.os.BatteryStats.CpuUsageDetails;
import android.os.BatteryStats.EnergyConsumerDetails;
import android.os.BatteryStats.HistoryItem;
import android.os.Parcel;
+import android.telephony.NetworkRegistrationInfo;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
@@ -66,6 +67,7 @@ public class BatteryStatsHistoryTest {
private File mHistoryDir;
private final Clock mClock = new MockClock();
private BatteryStatsHistory mHistory;
+ private BatteryStats.HistoryPrinter mHistoryPrinter;
@Mock
private BatteryStatsHistory.TraceDelegate mTracer;
@Mock
@@ -89,6 +91,9 @@ public class BatteryStatsHistoryTest {
when(mStepDetailsCalculator.getHistoryStepDetails())
.thenReturn(new BatteryStats.HistoryStepDetails());
+
+
+ mHistoryPrinter = new BatteryStats.HistoryPrinter();
}
@Test
@@ -379,11 +384,112 @@ public class BatteryStatsHistoryTest {
assertThat(checkin).contains("XC,10321,400,500,600");
}
+ @Test
+ public void testNrState_dump() {
+ mHistory.forceRecordAllHistory();
+ mHistory.startRecordingHistory(0, 0, /* reset */ true);
+ mHistory.setBatteryState(true /* charging */, BatteryManager.BATTERY_STATUS_CHARGING, 80,
+ 1234);
+
+ mHistory.recordNrStateChangeEvent(200, 200,
+ NetworkRegistrationInfo.NR_STATE_RESTRICTED);
+ mHistory.recordNrStateChangeEvent(300, 300,
+ NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED);
+ mHistory.recordNrStateChangeEvent(400, 400,
+ NetworkRegistrationInfo.NR_STATE_CONNECTED);
+ mHistory.recordNrStateChangeEvent(500, 500,
+ NetworkRegistrationInfo.NR_STATE_NONE);
+
+ BatteryStatsHistoryIterator iterator = mHistory.iterate();
+ BatteryStats.HistoryItem item = new BatteryStats.HistoryItem();
+ assertThat(item = iterator.next()).isNotNull(); // First item contains current time only
+
+ assertThat(item = iterator.next()).isNotNull();
+ String dump = toString(item, /* checkin */ false);
+ assertThat(dump).contains("+200ms");
+ assertThat(dump).contains("nr_state=restricted");
+
+ assertThat(item = iterator.next()).isNotNull();
+ dump = toString(item, /* checkin */ false);
+ assertThat(dump).contains("+300ms");
+ assertThat(dump).contains("nr_state=not_restricted");
+
+ assertThat(item = iterator.next()).isNotNull();
+ dump = toString(item, /* checkin */ false);
+ assertThat(dump).contains("+400ms");
+ assertThat(dump).contains("nr_state=connected");
+
+ assertThat(item = iterator.next()).isNotNull();
+ dump = toString(item, /* checkin */ false);
+ assertThat(dump).contains("+500ms");
+ assertThat(dump).contains("nr_state=none");
+ }
+
+ @Test
+ public void testNrState_checkin() {
+ mHistory.forceRecordAllHistory();
+ mHistory.startRecordingHistory(0, 0, /* reset */ true);
+ mHistory.setBatteryState(true /* charging */, BatteryManager.BATTERY_STATUS_CHARGING, 80,
+ 1234);
+
+ mHistory.recordNrStateChangeEvent(200, 200,
+ NetworkRegistrationInfo.NR_STATE_RESTRICTED);
+ mHistory.recordNrStateChangeEvent(300, 300,
+ NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED);
+ mHistory.recordNrStateChangeEvent(400, 400,
+ NetworkRegistrationInfo.NR_STATE_CONNECTED);
+ mHistory.recordNrStateChangeEvent(500, 500,
+ NetworkRegistrationInfo.NR_STATE_NONE);
+
+ BatteryStatsHistoryIterator iterator = mHistory.iterate();
+ BatteryStats.HistoryItem item = new BatteryStats.HistoryItem();
+ assertThat(item = iterator.next()).isNotNull(); // First item contains current time only
+
+ assertThat(item = iterator.next()).isNotNull();
+ String dump = toString(item, /* checkin */ true);
+ assertThat(dump).contains("nrs=1");
+
+ assertThat(item = iterator.next()).isNotNull();
+ dump = toString(item, /* checkin */ true);
+ assertThat(dump).contains("nrs=2");
+
+ assertThat(item = iterator.next()).isNotNull();
+ dump = toString(item, /* checkin */ true);
+ assertThat(dump).contains("nrs=3");
+
+ assertThat(item = iterator.next()).isNotNull();
+ dump = toString(item, /* checkin */ true);
+ assertThat(dump).contains("nrs=0");
+ }
+
+ @Test
+ public void testNrState_aTrace() {
+ InOrder inOrder = Mockito.inOrder(mTracer);
+ Mockito.when(mTracer.tracingEnabled()).thenReturn(true);
+
+ mHistory.recordNrStateChangeEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(),
+ NetworkRegistrationInfo.NR_STATE_RESTRICTED);
+ mHistory.recordNrStateChangeEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(),
+ NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED);
+ mHistory.recordNrStateChangeEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(),
+ NetworkRegistrationInfo.NR_STATE_CONNECTED);
+ mHistory.recordNrStateChangeEvent(mClock.elapsedRealtime(), mClock.uptimeMillis(),
+ NetworkRegistrationInfo.NR_STATE_NONE);
+
+ inOrder.verify(mTracer).traceCounter("battery_stats.nr_state",
+ NetworkRegistrationInfo.NR_STATE_RESTRICTED);
+ inOrder.verify(mTracer).traceCounter("battery_stats.nr_state",
+ NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED);
+ inOrder.verify(mTracer).traceCounter("battery_stats.nr_state",
+ NetworkRegistrationInfo.NR_STATE_CONNECTED);
+ inOrder.verify(mTracer).traceCounter("battery_stats.nr_state",
+ NetworkRegistrationInfo.NR_STATE_NONE);
+ }
+
private String toString(BatteryStats.HistoryItem item, boolean checkin) {
- BatteryStats.HistoryPrinter printer = new BatteryStats.HistoryPrinter();
StringWriter writer = new StringWriter();
PrintWriter pw = new PrintWriter(writer);
- printer.printNextItem(pw, item, 0, checkin, /* verbose */ true);
+ mHistoryPrinter.printNextItem(pw, item, 0, checkin, /* verbose */ true);
pw.flush();
return writer.toString();
}
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsImplTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java
index f20f061230e2..5ebc6ca3f558 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsImplTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java
@@ -267,7 +267,7 @@ public class BatteryStatsImplTest {
final long[][] delta3 = {
{98545, 95768795, 76586, 548945, 57846},
{788876, 586, 578459, 8776984, 9578923},
- {3049509483598l, 4597834, 377654, 94589035, 7854},
+ {3049509483598L, 4597834, 377654, 94589035, 7854},
{9493, 784, 99895, 8974893, 9879843}
};
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsManagerTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsManagerTest.java
index 7ae111711b6b..7ae111711b6b 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsManagerTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsManagerTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsNoteTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java
index 090c8c8c2c3c..88b9522d4cb1 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsNoteTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java
@@ -44,6 +44,7 @@ import android.telephony.Annotation;
import android.telephony.CellSignalStrength;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ModemActivityInfo;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.util.Log;
@@ -2461,14 +2462,26 @@ public class BatteryStatsNoteTest extends TestCase {
@BatteryStats.RadioAccessTechnology int rat) {
currentNetworkDataType = dataType;
currentRat = rat;
+ final int nrState;
+ if (currentNetworkDataType == TelephonyManager.NETWORK_TYPE_NR) {
+ nrState = NetworkRegistrationInfo.NR_STATE_CONNECTED;
+ } else {
+ nrState = NetworkRegistrationInfo.NR_STATE_NONE;
+ }
mBsi.notePhoneDataConnectionStateLocked(dataType, true, ServiceState.STATE_IN_SERVICE,
- currentFrequencyRange);
+ nrState, currentFrequencyRange);
}
void setFrequencyRange(@ServiceState.FrequencyRange int frequency) {
currentFrequencyRange = frequency;
+ final int nrState;
+ if (currentNetworkDataType == TelephonyManager.NETWORK_TYPE_NR) {
+ nrState = NetworkRegistrationInfo.NR_STATE_CONNECTED;
+ } else {
+ nrState = NetworkRegistrationInfo.NR_STATE_NONE;
+ }
mBsi.notePhoneDataConnectionStateLocked(currentNetworkDataType, true,
- ServiceState.STATE_IN_SERVICE, frequency);
+ ServiceState.STATE_IN_SERVICE, nrState, frequency);
}
void setSignalStrength(@BatteryStats.RadioAccessTechnology int rat, int strength) {
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsResetTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java
index a0fb631812f4..a0fb631812f4 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsResetTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsSamplingTimerTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsSamplingTimerTest.java
index 784d673ed3f0..ee68bf8ae53c 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsSamplingTimerTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsSamplingTimerTest.java
@@ -1,17 +1,17 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package com.android.server.power.stats;
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsSensorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsSensorTest.java
index b8f0ce3456f8..9c70f376ca14 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsSensorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsSensorTest.java
@@ -1,17 +1,17 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package com.android.server.power.stats;
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsServTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsServTest.java
index 200eb1d0ad15..200eb1d0ad15 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsServTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsServTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsStopwatchTimerTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsStopwatchTimerTest.java
index fcae42a76f1b..18a366c178fd 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsStopwatchTimerTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsStopwatchTimerTest.java
@@ -1,17 +1,17 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package com.android.server.power.stats;
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsTimeBaseTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsTimeBaseTest.java
index 5b47423f0d59..5b47423f0d59 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsTimeBaseTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsTimeBaseTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsTimerTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsTimerTest.java
index 14c5c5db5c1c..14c5c5db5c1c 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsTimerTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsTimerTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsUserLifecycleTests.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsUserLifecycleTests.java
index face849620d7..face849620d7 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsUserLifecycleTests.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsUserLifecycleTests.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
index 5df0acb65249..5df0acb65249 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryUsageStatsRule.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
index 534aa89e1699..534aa89e1699 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryUsageStatsStoreTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsStoreTest.java
index b846e3a36656..b846e3a36656 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryUsageStatsStoreTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsStoreTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryUsageStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java
index 266a22632a6d..266a22632a6d 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryUsageStatsTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BluetoothPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BluetoothPowerCalculatorTest.java
index 4d4337c16757..4d4337c16757 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BluetoothPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BluetoothPowerCalculatorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BstatsCpuTimesValidationTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BstatsCpuTimesValidationTest.java
index ccace40bb056..ccace40bb056 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BstatsCpuTimesValidationTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BstatsCpuTimesValidationTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/CameraPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/CameraPowerCalculatorTest.java
index 5fce32f0598a..5fce32f0598a 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/CameraPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/CameraPowerCalculatorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/CpuPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerCalculatorTest.java
index 888bc623f669..888bc623f669 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/CpuPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerCalculatorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/CustomEnergyConsumerPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/CustomEnergyConsumerPowerCalculatorTest.java
index 245faaf15cc8..245faaf15cc8 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/CustomEnergyConsumerPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/CustomEnergyConsumerPowerCalculatorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/EnergyConsumerSnapshotTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/EnergyConsumerSnapshotTest.java
index 28f4799656b7..28f4799656b7 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/EnergyConsumerSnapshotTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/EnergyConsumerSnapshotTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/FlashlightPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/FlashlightPowerCalculatorTest.java
index 0f85fdc375fb..0f85fdc375fb 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/FlashlightPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/FlashlightPowerCalculatorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/GnssPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/GnssPowerCalculatorTest.java
index 3f2a6d04c1e6..3f2a6d04c1e6 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/GnssPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/GnssPowerCalculatorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/IdlePowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/IdlePowerCalculatorTest.java
index 3d150af711f1..3d150af711f1 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/IdlePowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/IdlePowerCalculatorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/KernelWakelockReaderTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/KernelWakelockReaderTest.java
index c0f3c775ffe5..2edfc8e1e408 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/KernelWakelockReaderTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/KernelWakelockReaderTest.java
@@ -1,17 +1,17 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package com.android.server.power.stats;
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/LongSamplingCounterArrayTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/LongSamplingCounterArrayTest.java
index 2e962c364ed2..2e962c364ed2 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/LongSamplingCounterArrayTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/LongSamplingCounterArrayTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/LongSamplingCounterTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/LongSamplingCounterTest.java
index 0eac625051fc..0eac625051fc 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/LongSamplingCounterTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/LongSamplingCounterTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/MemoryPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MemoryPowerCalculatorTest.java
index 2cce449c6c05..2cce449c6c05 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/MemoryPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MemoryPowerCalculatorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java
index d3ec0d7e3f6e..888a1688c2a1 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java
@@ -46,7 +46,7 @@ import android.telephony.TelephonyManager;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.frameworks.servicestests.R;
+import com.android.frameworks.powerstatstests.R;
import com.google.common.collect.Range;
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/MockBatteryStatsImpl.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
index 6d3f1f27b572..6d3f1f27b572 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/MockClock.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MockClock.java
index 5e57cc36797b..5e57cc36797b 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/MockClock.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MockClock.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/OWNERS b/services/tests/powerstatstests/src/com/android/server/power/stats/OWNERS
index 9a7db1cb4fe4..9a7db1cb4fe4 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/OWNERS
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/ScreenPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/ScreenPowerCalculatorTest.java
index 372307985f04..372307985f04 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/ScreenPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/ScreenPowerCalculatorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/SensorPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/SensorPowerCalculatorTest.java
index 474527040839..474527040839 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/SensorPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/SensorPowerCalculatorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/SystemServerCpuThreadReaderTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServerCpuThreadReaderTest.java
index 80cbe0da402e..80cbe0da402e 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/SystemServerCpuThreadReaderTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServerCpuThreadReaderTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java
index 4dae2d548057..4dae2d548057 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/UserPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/UserPowerCalculatorTest.java
index f14745ef2daa..f14745ef2daa 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/UserPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/UserPowerCalculatorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/VideoPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/VideoPowerCalculatorTest.java
index f578aa3b46be..f578aa3b46be 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/VideoPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/VideoPowerCalculatorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/WakelockPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerCalculatorTest.java
index f1961855f12f..f1961855f12f 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/WakelockPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerCalculatorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/WifiPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerCalculatorTest.java
index 113be8b19518..113be8b19518 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/WifiPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/WifiPowerCalculatorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/wakeups/CpuWakeupStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/wakeups/CpuWakeupStatsTest.java
index b81b776019f9..0dc836ba0400 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/wakeups/CpuWakeupStatsTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/wakeups/CpuWakeupStatsTest.java
@@ -34,7 +34,7 @@ import android.util.SparseIntArray;
import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
-import com.android.frameworks.servicestests.R;
+import com.android.frameworks.powerstatstests.R;
import com.android.server.power.stats.wakeups.CpuWakeupStats.Wakeup;
import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/wakeups/IrqDeviceMapTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/wakeups/IrqDeviceMapTest.java
index 47a8f49e7025..9af288496bb9 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/wakeups/IrqDeviceMapTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/wakeups/IrqDeviceMapTest.java
@@ -23,7 +23,7 @@ import android.content.Context;
import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
-import com.android.frameworks.servicestests.R;
+import com.android.frameworks.powerstatstests.R;
import com.android.internal.util.CollectionUtils;
import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/wakeups/WakingActivityHistoryTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/wakeups/WakingActivityHistoryTest.java
index 99bc25abc4a1..99bc25abc4a1 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/wakeups/WakingActivityHistoryTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/wakeups/WakingActivityHistoryTest.java
diff --git a/services/tests/servicestests/src/com/android/server/powerstats/IntervalRandomNoiseGeneratorTest.java b/services/tests/powerstatstests/src/com/android/server/powerstats/IntervalRandomNoiseGeneratorTest.java
index 99621460f360..99621460f360 100644
--- a/services/tests/servicestests/src/com/android/server/powerstats/IntervalRandomNoiseGeneratorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/powerstats/IntervalRandomNoiseGeneratorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java b/services/tests/powerstatstests/src/com/android/server/powerstats/PowerStatsServiceTest.java
index 2ffe4aacda73..2ffe4aacda73 100644
--- a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/powerstats/PowerStatsServiceTest.java
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 173c5f5dd40f..92ff7ab86247 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -112,7 +112,6 @@ android_test {
},
data: [
- ":BstatsTestApp",
":JobTestApp",
":SimpleServiceTestApp1",
":SimpleServiceTestApp2",
@@ -134,7 +133,6 @@ java_library {
name: "servicestests-core-utils",
srcs: [
"src/com/android/server/am/DeviceConfigSession.java",
- "src/com/android/server/display/TestUtils.java",
"src/com/android/server/pm/PackageSettingBuilder.java",
"src/com/android/server/pm/parsing/TestPackageParser2.kt",
],
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index fbb0ca108ecd..b1d50399416a 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -28,7 +28,6 @@
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="install-arg" value="-t" />
- <option name="test-file-name" value="BstatsTestApp.apk" />
<option name="test-file-name" value="FrameworksServicesTests.apk" />
<option name="test-file-name" value="JobTestApp.apk" />
<option name="test-file-name" value="SuspendTestApp.apk" />
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index fc62e75b7d59..e79ac0986dc8 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -16,6 +16,7 @@
package com.android.server.biometrics;
+import static android.hardware.biometrics.BiometricAuthenticator.TYPE_CREDENTIAL;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricManager.Authenticators;
@@ -116,9 +117,9 @@ public class BiometricServiceTest {
private static final String ERROR_LOCKOUT = "error_lockout";
private static final String FACE_SUBTITLE = "face_subtitle";
private static final String FINGERPRINT_SUBTITLE = "fingerprint_subtitle";
+ private static final String CREDENTIAL_SUBTITLE = "credential_subtitle";
private static final String DEFAULT_SUBTITLE = "default_subtitle";
-
private static final String FINGERPRINT_ACQUIRED_SENSOR_DIRTY = "sensor_dirty";
private static final int SENSOR_ID_FINGERPRINT = 0;
@@ -143,6 +144,8 @@ public class BiometricServiceTest {
@Mock
IBiometricAuthenticator mFaceAuthenticator;
@Mock
+ IBiometricAuthenticator mCredentialAuthenticator;
+ @Mock
ITrustManager mTrustManager;
@Mock
DevicePolicyManager mDevicePolicyManager;
@@ -196,10 +199,12 @@ public class BiometricServiceTest {
.thenReturn(ERROR_NOT_RECOGNIZED);
when(mResources.getString(R.string.biometric_error_user_canceled))
.thenReturn(ERROR_USER_CANCELED);
- when(mContext.getString(R.string.biometric_dialog_face_subtitle))
+ when(mContext.getString(R.string.face_dialog_default_subtitle))
.thenReturn(FACE_SUBTITLE);
- when(mContext.getString(R.string.biometric_dialog_fingerprint_subtitle))
+ when(mContext.getString(R.string.fingerprint_dialog_default_subtitle))
.thenReturn(FINGERPRINT_SUBTITLE);
+ when(mContext.getString(R.string.screen_lock_dialog_default_subtitle))
+ .thenReturn(CREDENTIAL_SUBTITLE);
when(mContext.getString(R.string.biometric_dialog_default_subtitle))
.thenReturn(DEFAULT_SUBTITLE);
@@ -292,7 +297,8 @@ public class BiometricServiceTest {
mBiometricService.onStart();
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
- Authenticators.DEVICE_CREDENTIAL);
+ Authenticators.DEVICE_CREDENTIAL, false /* useDefaultSubtitle */,
+ false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1).onError(
eq(BiometricAuthenticator.TYPE_CREDENTIAL),
@@ -312,7 +318,8 @@ public class BiometricServiceTest {
mBiometricService.onStart();
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
- Authenticators.DEVICE_CREDENTIAL);
+ Authenticators.DEVICE_CREDENTIAL, false /* useDefaultSubtitle */,
+ false /* deviceCredentialAllowed */);
waitForIdle();
assertNotNull(mBiometricService.mAuthSession);
@@ -338,7 +345,8 @@ public class BiometricServiceTest {
mBiometricService.onStart();
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
- null /* authenticators */);
+ null /* authenticators */, false /* useDefaultSubtitle */,
+ false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1).onError(
eq(BiometricAuthenticator.TYPE_NONE),
@@ -357,7 +365,8 @@ public class BiometricServiceTest {
mFingerprintAuthenticator);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
- null /* authenticators */);
+ null /* authenticators */, false /* useDefaultSubtitle */,
+ false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1).onError(
eq(TYPE_FINGERPRINT),
@@ -370,7 +379,8 @@ public class BiometricServiceTest {
setupAuthForOnly(TYPE_FINGERPRINT, Authenticators.BIOMETRIC_WEAK);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
- Authenticators.BIOMETRIC_STRONG);
+ Authenticators.BIOMETRIC_STRONG, false /* useDefaultSubtitle */,
+ false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1).onError(
eq(BiometricAuthenticator.TYPE_NONE),
@@ -429,7 +439,8 @@ public class BiometricServiceTest {
mFingerprintAuthenticator);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
- null /* authenticators */);
+ null /* authenticators */, false /* useDefaultSubtitle */,
+ false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1).onError(
eq(TYPE_FINGERPRINT),
@@ -441,9 +452,9 @@ public class BiometricServiceTest {
public void testAuthenticateFace_shouldShowSubtitleForFace() throws Exception {
setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
- invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
- false /* requireConfirmation */,
- null);
+ invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
+ null /* authenticators */, true /* useDefaultSubtitle */,
+ false /* deviceCredentialAllowed */);
waitForIdle();
assertEquals(FACE_SUBTITLE, mBiometricService.mAuthSession.mPromptInfo.getSubtitle());
@@ -453,9 +464,9 @@ public class BiometricServiceTest {
public void testAuthenticateFingerprint_shouldShowSubtitleForFingerprint() throws Exception {
setupAuthForOnly(TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
- invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
- false /* requireConfirmation */,
- null);
+ invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
+ null /* authenticators */, true /* useDefaultSubtitle */,
+ false /* deviceCredentialAllowed */);
waitForIdle();
assertEquals(FINGERPRINT_SUBTITLE,
@@ -463,6 +474,19 @@ public class BiometricServiceTest {
}
@Test
+ public void testAuthenticateFingerprint_shouldShowSubtitleForCredential() throws Exception {
+ setupAuthForOnly(TYPE_CREDENTIAL, Authenticators.DEVICE_CREDENTIAL);
+
+ invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
+ null /* authenticators */, true /* useDefaultSubtitle */,
+ true /* deviceCredentialAllowed */);
+ waitForIdle();
+
+ assertEquals(CREDENTIAL_SUBTITLE,
+ mBiometricService.mAuthSession.mPromptInfo.getSubtitle());
+ }
+
+ @Test
public void testAuthenticateBothFpAndFace_shouldShowDefaultSubtitle() throws Exception {
final int[] modalities = new int[] {
TYPE_FINGERPRINT,
@@ -476,9 +500,9 @@ public class BiometricServiceTest {
setupAuthForMultiple(modalities, strengths);
- invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
- false /* requireConfirmation */,
- null);
+ invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
+ null /* authenticators */, true /* useDefaultSubtitle */,
+ false /* deviceCredentialAllowed */);
waitForIdle();
assertEquals(DEFAULT_SUBTITLE, mBiometricService.mAuthSession.mPromptInfo.getSubtitle());
@@ -492,7 +516,8 @@ public class BiometricServiceTest {
// Disabled in user settings receives onError
when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(false);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
- null /* authenticators */);
+ null /* authenticators */, false /* useDefaultSubtitle */,
+ false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1).onError(
eq(BiometricAuthenticator.TYPE_NONE),
@@ -506,7 +531,8 @@ public class BiometricServiceTest {
anyInt() /* modality */, anyInt() /* userId */))
.thenReturn(true);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
- null /* authenticators */);
+ null /* authenticators */, false /* useDefaultSubtitle */,
+ false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1, never()).onError(anyInt(), anyInt(), anyInt());
final byte[] HAT = generateRandomHAT();
@@ -524,7 +550,8 @@ public class BiometricServiceTest {
anyInt() /* modality */, anyInt() /* userId */))
.thenReturn(false);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
- null /* authenticators */);
+ null /* authenticators */, false /* useDefaultSubtitle */,
+ false /* deviceCredentialAllowed */);
waitForIdle();
mBiometricService.mAuthSession.mSensorReceiver.onAuthenticationSucceeded(
SENSOR_ID_FACE,
@@ -552,7 +579,8 @@ public class BiometricServiceTest {
throws Exception {
// Start testing the happy path
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
- null /* authenticators */);
+ null /* authenticators */, false /* useDefaultSubtitle */,
+ false /* deviceCredentialAllowed */);
waitForIdle();
// Creates a pending auth session with the correct initial states
@@ -632,7 +660,8 @@ public class BiometricServiceTest {
.thenReturn(true);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
true /* requireConfirmation */,
- Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK);
+ Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK,
+ false /* useDefaultSubtitle*/, false /* deviceCredentialAllowed */);
waitForIdle();
assertEquals(STATE_SHOWING_DEVICE_CREDENTIAL,
@@ -702,7 +731,8 @@ public class BiometricServiceTest {
invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
true /* requireConfirmation */,
- Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_STRONG);
+ Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_STRONG,
+ false /* useDefaultSubtitle */, false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1).onError(anyInt() /* modality */,
@@ -754,7 +784,8 @@ public class BiometricServiceTest {
false /* requireConfirmation */, null /* authenticators */);
invokeAuthenticate(mBiometricService.mImpl, mReceiver2, false /* requireConfirmation */,
- null /* authenticators */);
+ null /* authenticators */, false /* useDefaultSubtitle */,
+ false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1).onError(
@@ -887,7 +918,8 @@ public class BiometricServiceTest {
setupAuthForOnly(TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */,
- Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK);
+ Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK,
+ false /* useDefaultSubtitle */, false /* deviceCredentialAllowed */);
waitForIdle();
assertEquals(STATE_AUTH_CALLED, mBiometricService.mAuthSession.getState());
@@ -920,8 +952,9 @@ public class BiometricServiceTest {
public void testErrorFromHal_whilePreparingAuthentication_credentialNotAllowed()
throws Exception {
setupAuthForOnly(TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
- invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
- false /* requireConfirmation */, null /* authenticators */);
+ invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
+ null /* authenticators */, false /* useDefaultSubtitle */,
+ false /* deviceCredentialAllowed */);
waitForIdle();
mBiometricService.mAuthSession.mSensorReceiver.onError(
@@ -957,8 +990,9 @@ public class BiometricServiceTest {
setupAuthForOnly(TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
when(mFingerprintAuthenticator.getLockoutModeForUser(anyInt()))
.thenReturn(lockoutMode);
- invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
- false /* requireConfirmation */, null /* authenticators */);
+ invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
+ null /* authenticators */, false /* useDefaultSubtitle */,
+ false /* deviceCredentialAllowed */);
waitForIdle();
// Modality and error are sent
@@ -996,8 +1030,9 @@ public class BiometricServiceTest {
when(mFingerprintAuthenticator.getLockoutModeForUser(anyInt()))
.thenReturn(lockoutMode);
when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(false);
- invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
- false /* requireConfirmation */, null /* authenticators */);
+ invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
+ null /* authenticators */, false /* useDefaultSubtitle */,
+ false /* deviceCredentialAllowed */);
waitForIdle();
// The lockout error should be sent, instead of ERROR_NONE_ENROLLED. See b/286923477.
@@ -1014,7 +1049,8 @@ public class BiometricServiceTest {
.thenReturn(LockoutTracker.LOCKOUT_PERMANENT);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */,
- Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_STRONG);
+ Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_STRONG,
+ false /* useDefaultSubtitle */, false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1, never()).onError(anyInt(), anyInt(), anyInt());
@@ -1503,7 +1539,8 @@ public class BiometricServiceTest {
assertEquals(BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED,
invokeCanAuthenticate(mBiometricService, authenticators));
long requestId = invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
- false /* requireConfirmation */, authenticators);
+ false /* requireConfirmation */, authenticators, false /* useDefaultSubtitle */,
+ false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1).onError(
eq(TYPE_FINGERPRINT),
@@ -1539,7 +1576,8 @@ public class BiometricServiceTest {
invokeCanAuthenticate(mBiometricService, authenticators));
requestId = invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */,
- authenticators);
+ authenticators, false /* useDefaultSubtitle */,
+ false /* deviceCredentialAllowed */);
waitForIdle();
assertTrue(Utils.isCredentialRequested(mBiometricService.mAuthSession.mPromptInfo));
verify(mBiometricService.mStatusBarService).showAuthenticationDialog(
@@ -1749,6 +1787,11 @@ public class BiometricServiceTest {
mBiometricService.mImpl.registerAuthenticator(SENSOR_ID_FACE, modality, strength,
mFaceAuthenticator);
}
+
+ if ((modality & TYPE_CREDENTIAL) != 0) {
+ when(mTrustManager.isDeviceSecure(anyInt(), anyInt()))
+ .thenReturn(true);
+ }
}
// TODO: Reduce duplicated code, currently we cannot start the BiometricService in setUp() for
@@ -1799,7 +1842,8 @@ public class BiometricServiceTest {
Integer authenticators) throws Exception {
// Request auth, creates a pending session
final long requestId = invokeAuthenticate(
- service, receiver, requireConfirmation, authenticators);
+ service, receiver, requireConfirmation, authenticators,
+ false /* useDefaultSubtitle */, false /* deviceCredentialAllowed */);
waitForIdle();
startPendingAuthSession(mBiometricService);
@@ -1827,7 +1871,8 @@ public class BiometricServiceTest {
private static long invokeAuthenticate(IBiometricService.Stub service,
IBiometricServiceReceiver receiver, boolean requireConfirmation,
- Integer authenticators) throws Exception {
+ Integer authenticators, boolean useDefaultSubtitle,
+ boolean deviceCredentialAllowed) throws Exception {
return service.authenticate(
new Binder() /* token */,
0 /* operationId */,
@@ -1835,7 +1880,8 @@ public class BiometricServiceTest {
receiver,
TEST_PACKAGE_NAME /* packageName */,
createTestPromptInfo(requireConfirmation, authenticators,
- false /* checkDevicePolicy */));
+ false /* checkDevicePolicy */, useDefaultSubtitle,
+ deviceCredentialAllowed));
}
private static long invokeAuthenticateForWorkApp(IBiometricService.Stub service,
@@ -1847,16 +1893,19 @@ public class BiometricServiceTest {
receiver,
TEST_PACKAGE_NAME /* packageName */,
createTestPromptInfo(false /* requireConfirmation */, authenticators,
- true /* checkDevicePolicy */));
+ true /* checkDevicePolicy */, false /* useDefaultSubtitle */,
+ false /* deviceCredentialAllowed */));
}
private static PromptInfo createTestPromptInfo(
boolean requireConfirmation,
Integer authenticators,
- boolean checkDevicePolicy) {
+ boolean checkDevicePolicy,
+ boolean useDefaultSubtitle,
+ boolean deviceCredentialAllowed) {
final PromptInfo promptInfo = new PromptInfo();
promptInfo.setConfirmationRequested(requireConfirmation);
- promptInfo.setUseDefaultSubtitle(true);
+ promptInfo.setUseDefaultSubtitle(useDefaultSubtitle);
if (authenticators != null) {
promptInfo.setAuthenticators(authenticators);
@@ -1864,6 +1913,7 @@ public class BiometricServiceTest {
if (checkDevicePolicy) {
promptInfo.setDisallowBiometricsIfPolicyExists(checkDevicePolicy);
}
+ promptInfo.setDeviceCredentialAllowed(deviceCredentialAllowed);
return promptInfo;
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java
index a4423038a072..437510595ecb 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java
@@ -252,6 +252,14 @@ public class BiometricContextProviderTest {
}
@Test
+ public void testSubscribesWithDifferentState() throws RemoteException {
+ final Consumer<OperationContext> nonEmptyConsumer = mock(Consumer.class);
+ mListener.onDisplayStateChanged(AuthenticateOptions.DISPLAY_STATE_AOD);
+ mProvider.subscribe(mOpContext, nonEmptyConsumer);
+ verify(nonEmptyConsumer).accept(same(mOpContext.toAidlContext()));
+ }
+
+ @Test
public void testUnsubscribes() throws RemoteException {
final Consumer<OperationContext> emptyConsumer = mock(Consumer.class);
mProvider.subscribe(mOpContext, emptyConsumer);
@@ -259,6 +267,9 @@ public class BiometricContextProviderTest {
mListener.onDisplayStateChanged(AuthenticateOptions.DISPLAY_STATE_AOD);
+ //reset to unknown to avoid trigger accept when subscribe
+ mListener.onDisplayStateChanged(AuthenticateOptions.DISPLAY_STATE_UNKNOWN);
+
final Consumer<OperationContext> nonEmptyConsumer = mock(Consumer.class);
mProvider.subscribe(mOpContext, nonEmptyConsumer);
mListener.onDisplayStateChanged(AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN);
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 4512cc025bf0..bcbbcd4456ee 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -363,7 +363,8 @@ public class VirtualDeviceManagerServiceTest {
new CameraAccessController(mContext, mLocalService, mCameraAccessBlockedCallback);
mAssociationInfo = new AssociationInfo(/* associationId= */ 1, 0, null,
- MacAddress.BROADCAST_ADDRESS, "", null, null, true, false, false, 0, 0, -1);
+ null, MacAddress.BROADCAST_ADDRESS, "", null, null, true, false, false,
+ 0, 0, -1);
mVdms = new VirtualDeviceManagerService(mContext);
mLocalService = mVdms.getLocalServiceInstance();
diff --git a/services/tests/servicestests/src/com/android/server/display/TestUtils.java b/services/tests/servicestests/src/com/android/server/display/TestUtils.java
deleted file mode 100644
index 8b45145b160f..000000000000
--- a/services/tests/servicestests/src/com/android/server/display/TestUtils.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.display;
-
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.input.InputSensorInfo;
-import android.os.Parcel;
-import android.os.SystemClock;
-import android.view.DisplayAddress;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-
-public final class TestUtils {
-
- public static SensorEvent createSensorEvent(Sensor sensor, int value) throws Exception {
- final Constructor<SensorEvent> constructor =
- SensorEvent.class.getDeclaredConstructor(int.class);
- constructor.setAccessible(true);
- final SensorEvent event = constructor.newInstance(1);
- event.sensor = sensor;
- event.values[0] = value;
- event.timestamp = SystemClock.elapsedRealtimeNanos();
- return event;
- }
-
-
- public static void setSensorType(Sensor sensor, int type, String strType) throws Exception {
- Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE);
- setter.setAccessible(true);
- setter.invoke(sensor, type);
- if (strType != null) {
- Field f = sensor.getClass().getDeclaredField("mStringType");
- f.setAccessible(true);
- f.set(sensor, strType);
- }
- }
-
- public static void setMaximumRange(Sensor sensor, float maximumRange) throws Exception {
- Method setter = Sensor.class.getDeclaredMethod("setRange", Float.TYPE, Float.TYPE);
- setter.setAccessible(true);
- setter.invoke(sensor, maximumRange, 1);
- }
-
- public static Sensor createSensor(int type, String strType) throws Exception {
- Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
- constr.setAccessible(true);
- Sensor sensor = constr.newInstance();
- setSensorType(sensor, type, strType);
- return sensor;
- }
-
- public static Sensor createSensor(int type, String strType, float maximumRange)
- throws Exception {
- Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
- constr.setAccessible(true);
- Sensor sensor = constr.newInstance();
- setSensorType(sensor, type, strType);
- setMaximumRange(sensor, maximumRange);
- return sensor;
- }
-
- public static Sensor createSensor(String type, String name) {
- return new Sensor(new InputSensorInfo(
- name, "vendor", 0, 0, 0, 1f, 1f, 1, 1, 1, 1,
- type, "", 0, 0, 0));
- }
-
- /**
- * Create a custom {@link DisplayAddress} to ensure we're not relying on any specific
- * display-address implementation in our code. Intentionally uses default object (reference)
- * equality rules.
- */
- public static class TestDisplayAddress extends DisplayAddress {
- @Override
- public void writeToParcel(Parcel out, int flags) { }
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
index f834cb24f245..560a91974692 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
@@ -138,6 +138,17 @@ class AndroidPackageParsingValidationTest {
R.styleable.AndroidManifestApplication_taskAffinity,
1024
)
+ validateTagAttr(
+ tag,
+ "zygotePreloadName",
+ R.styleable.AndroidManifestApplication_zygotePreloadName,
+ 1024
+ )
+ validateTagAttrComponentName(
+ tag,
+ "zygotePreloadName",
+ R.styleable.AndroidManifestApplication_zygotePreloadName
+ )
validateTagCount("profileable", 100, tag)
validateTagCount("uses-native-library", 100, tag)
validateTagCount("receiver", 1000, tag)
@@ -507,8 +518,26 @@ class AndroidPackageParsingValidationTest {
}
}
- val failNames = arrayOf("com.android.TestClass:", "-TestClass", "TestClass.", ".", "..")
- for (name in failNames) {
+ val badNames = arrayOf(
+ ";",
+ ",",
+ "[",
+ "]",
+ "(",
+ ")",
+ "{",
+ "}",
+ ":",
+ "?",
+ "-",
+ "%",
+ "^",
+ "*",
+ "|",
+ "/",
+ "\\"
+ )
+ for (name in badNames) {
val xml = "<$tag $attr=\"$name\" />"
pullParser.setInput(ByteArrayInputStream(xml.toByteArray()), null)
val validator = Validator()
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsTests.java b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsTests.java
deleted file mode 100644
index 48290e5ca1ef..000000000000
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsTests.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.power.stats;
-
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
-
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
- AmbientDisplayPowerCalculatorTest.class,
- AudioPowerCalculatorTest.class,
- BatteryChargeCalculatorTest.class,
- BatteryExternalStatsWorkerTest.class,
- BatteryStatsCpuTimesTest.class,
- BatteryStatsBackgroundStatsTest.class,
- BatteryStatsBinderCallStatsTest.class,
- BatteryStatsCounterTest.class,
- BatteryStatsDualTimerTest.class,
- BatteryStatsDurationTimerTest.class,
- BatteryStatsHistoryIteratorTest.class,
- BatteryStatsHistoryTest.class,
- BatteryStatsImplTest.class,
- BatteryStatsManagerTest.class,
- BatteryStatsNoteTest.class,
- BatteryStatsSamplingTimerTest.class,
- BatteryStatsSensorTest.class,
- BatteryStatsServTest.class,
- BatteryStatsStopwatchTimerTest.class,
- BatteryStatsTimeBaseTest.class,
- BatteryStatsTimerTest.class,
- BatteryUsageStatsProviderTest.class,
- BatteryUsageStatsTest.class,
- BatteryUsageStatsStoreTest.class,
- BatteryStatsUserLifecycleTests.class,
- BluetoothPowerCalculatorTest.class,
- BstatsCpuTimesValidationTest.class,
- CameraPowerCalculatorTest.class,
- CpuPowerCalculatorTest.class,
- CustomEnergyConsumerPowerCalculatorTest.class,
- FlashlightPowerCalculatorTest.class,
- GnssPowerCalculatorTest.class,
- IdlePowerCalculatorTest.class,
- KernelWakelockReaderTest.class,
- LongSamplingCounterTest.class,
- LongSamplingCounterArrayTest.class,
- EnergyConsumerSnapshotTest.class,
- MobileRadioPowerCalculatorTest.class,
- ScreenPowerCalculatorTest.class,
- SensorPowerCalculatorTest.class,
- SystemServerCpuThreadReaderTest.class,
- SystemServicePowerCalculatorTest.class,
- UserPowerCalculatorTest.class,
- VideoPowerCalculatorTest.class,
- WakelockPowerCalculatorTest.class,
- WifiPowerCalculatorTest.class,
-})
-public class BatteryStatsTests {
-}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
index 95fae0707304..22b112746b50 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
@@ -15,8 +15,6 @@
*/
package com.android.server.notification;
-import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.NO_SORT_BY_INTERRUPTIVENESS;
-
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertFalse;
@@ -47,6 +45,8 @@ import android.service.notification.StatusBarNotification;
import android.telecom.TelecomManager;
import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
import com.android.server.UiServiceTestCase;
@@ -54,7 +54,6 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -63,7 +62,7 @@ import java.util.Collections;
import java.util.List;
@SmallTest
-@RunWith(Parameterized.class)
+@RunWith(AndroidJUnit4.class)
public class NotificationComparatorTest extends UiServiceTestCase {
@Mock Context mMockContext;
@Mock TelecomManager mTm;
@@ -97,24 +96,9 @@ public class NotificationComparatorTest extends UiServiceTestCase {
private NotificationRecord mRecordColorized;
private NotificationRecord mRecordColorizedCall;
- @Parameterized.Parameters(name = "sortByInterruptiveness={0}")
- public static Boolean[] getSortByInterruptiveness() {
- return new Boolean[] { true, false };
- }
-
- @Parameterized.Parameter
- public boolean mSortByInterruptiveness;
-
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- SystemUiSystemPropertiesFlags.TEST_RESOLVER = flag -> {
- if (flag.mSysPropKey.equals(NO_SORT_BY_INTERRUPTIVENESS.mSysPropKey)) {
- return !mSortByInterruptiveness;
- }
- return new SystemUiSystemPropertiesFlags.DebugResolver().isEnabled(flag);
- };
-
int userId = UserHandle.myUserId();
final Resources res = mContext.getResources();
@@ -309,13 +293,8 @@ public class NotificationComparatorTest extends UiServiceTestCase {
expected.add(mNoMediaSessionMedia);
expected.add(mRecordCheater);
expected.add(mRecordCheaterColorized);
- if (mSortByInterruptiveness) {
- expected.add(mRecordMinCall);
- expected.add(mRecordMinCallNonInterruptive);
- } else {
- expected.add(mRecordMinCallNonInterruptive);
- expected.add(mRecordMinCall);
- }
+ expected.add(mRecordMinCallNonInterruptive);
+ expected.add(mRecordMinCall);
List<NotificationRecord> actual = new ArrayList<>();
actual.addAll(expected);
@@ -330,11 +309,7 @@ public class NotificationComparatorTest extends UiServiceTestCase {
public void testRankingScoreOverrides() {
NotificationComparator comp = new NotificationComparator(mMockContext);
NotificationRecord recordMinCallNonInterruptive = spy(mRecordMinCallNonInterruptive);
- if (mSortByInterruptiveness) {
- assertTrue(comp.compare(mRecordMinCall, recordMinCallNonInterruptive) < 0);
- } else {
- assertTrue(comp.compare(mRecordMinCall, recordMinCallNonInterruptive) > 0);
- }
+ assertTrue(comp.compare(mRecordMinCall, recordMinCallNonInterruptive) > 0);
when(recordMinCallNonInterruptive.getRankingScore()).thenReturn(1f);
assertTrue(comp.compare(mRecordMinCall, recordMinCallNonInterruptive) > 0);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 939ff97ab02e..c4302db16b98 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -1194,6 +1194,15 @@ public class DisplayRotationTests {
}
@Test
+ public void testIsFixedToUserRotation_displayContentOrientationFixed() throws Exception {
+ mBuilder.build();
+ when(mMockDisplayContent.isDisplayOrientationFixed()).thenReturn(true);
+
+ assertFalse("Display rotation should respect app requested orientation if"
+ + " the display has fixed orientation.", mTarget.isFixedToUserRotation());
+ }
+
+ @Test
public void testIsFixedToUserRotation_FixedToUserRotationIfNoAutoRotation() throws Exception {
mBuilder.build();
mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_IF_NO_AUTO_ROTATION);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java
index 57a397facc61..d85d9b5729a0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java
@@ -34,25 +34,30 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
-import android.app.IWindowToken;
+import android.app.ClientTransactionHandler;
+import android.app.servertransaction.ClientTransactionItem;
+import android.app.servertransaction.WindowContextInfoChangeItem;
import android.content.res.Configuration;
import android.graphics.Rect;
-import android.os.Binder;
import android.os.Bundle;
-import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.view.Display;
import android.view.DisplayInfo;
+import android.window.WindowContextInfo;
+import android.window.WindowTokenClient;
import androidx.test.filters.SmallTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
import org.mockito.Mockito;
/**
@@ -68,20 +73,47 @@ public class WindowContextListenerControllerTests extends WindowTestsBase {
private static final int TEST_UID = 12345;
private static final int ANOTHER_UID = 1000;
+ @Mock
+ private ClientTransactionHandler mHandler;
+ @Mock
+ private WindowTokenClient mClientToken;
+
private WindowProcessController mWpc;
- private final IBinder mClientToken = new Binder();
private WindowContainer<?> mContainer;
@Before
public void setUp() {
+ initMocks(this);
mController = new WindowContextListenerController();
mContainer = createTestWindowToken(TYPE_APPLICATION_OVERLAY, mDisplayContent);
// Make display on to verify configuration propagation.
mDefaultDisplay.getDisplayInfo().state = STATE_ON;
mDisplayContent.getDisplayInfo().state = STATE_ON;
+
mWpc = mSystemServicesTestRule.addProcess(
DEFAULT_COMPONENT_PACKAGE_NAME, DEFAULT_COMPONENT_PACKAGE_NAME, 0 /* pid */,
TEST_UID);
+ // Mock the behaviors on ClientTransaction
+ spyOn(mWpc);
+ doAnswer(invocation -> {
+ // Mock ActivityThread
+ final Object[] args = invocation.getArguments();
+ final WindowTokenClient clientToken = (WindowTokenClient) args[0];
+ final WindowContextInfo info = (WindowContextInfo) args[1];
+ clientToken.onConfigurationChanged(info.getConfiguration(), info.getDisplayId());
+ return null;
+ }).when(mHandler).handleWindowContextInfoChanged(any(), any());
+ doAnswer(invocation -> {
+ // Mock WindowProcessController
+ final Object[] args = invocation.getArguments();
+ final ClientTransactionItem item = (ClientTransactionItem) args[0];
+ if (!(item instanceof WindowContextInfoChangeItem)) {
+ return null;
+ }
+ final WindowContextInfoChangeItem infoChangeItem = (WindowContextInfoChangeItem) item;
+ infoChangeItem.execute(mHandler, null, null);
+ return null;
+ }).when(mWpc).scheduleClientTransactionItem(any());
}
@Test
@@ -91,7 +123,7 @@ public class WindowContextListenerControllerTests extends WindowTestsBase {
assertEquals(1, mController.mListeners.size());
- final IBinder clientToken = mock(IBinder.class);
+ final WindowTokenClient clientToken = mock(WindowTokenClient.class);
mController.registerWindowContainerListener(mWpc, clientToken, mContainer,
TYPE_APPLICATION_OVERLAY, null /* options */);
@@ -304,7 +336,7 @@ public class WindowContextListenerControllerTests extends WindowTestsBase {
assertThat(clientToken.mDisplayId).isEqualTo(mDisplayContent.mDisplayId);
}
- private static class TestWindowTokenClient extends IWindowToken.Stub {
+ private static class TestWindowTokenClient extends WindowTokenClient {
private Configuration mConfiguration;
private int mDisplayId;
private boolean mRemoved;
diff --git a/services/usage/java/com/android/server/usage/TEST_MAPPING b/services/usage/java/com/android/server/usage/TEST_MAPPING
index a3fe6f2876d7..6e845433492b 100644
--- a/services/usage/java/com/android/server/usage/TEST_MAPPING
+++ b/services/usage/java/com/android/server/usage/TEST_MAPPING
@@ -20,22 +20,13 @@
]
},
{
- "name": "CtsUsageStatsTestCases",
+ "name": "CtsBRSTestCases",
"options": [
{
- "include-filter": "android.app.usage.cts.BroadcastResponseStatsTest"
- },
- {
"exclude-annotation": "androidx.test.filters.FlakyTest"
},
{
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.MediumTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
+ "exclude-annotation": "org.junit.Ignore"
}
]
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 78b86d398718..5bdcdf4d63ef 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -2661,7 +2661,9 @@ public final class Call {
// remove ourselves from the Phone. Note that we do this after completing all state updates
// so a client can cleanly transition all their UI to the state appropriate for a
// DISCONNECTED Call while still relying on the existence of that Call in the Phone's list.
- if (mState == STATE_DISCONNECTED) {
+ // Check if the original state is already disconnected, otherwise onCallRemoved will be
+ // triggered before onCallAdded.
+ if (mState == STATE_DISCONNECTED && stateChanged) {
fireCallDestroyed();
}
}
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index 95a8e16ace3d..61e829e75930 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -174,6 +174,9 @@ public final class Phone {
checkCallTree(parcelableCall);
call.internalUpdate(parcelableCall, mCallByTelecomCallId);
fireCallAdded(call);
+ if (call.getState() == Call.STATE_DISCONNECTED) {
+ internalRemoveCall(call);
+ }
} else {
Log.w(this, "Call %s added, but it was already present", call.internalGetCallId());
checkCallTree(parcelableCall);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 314150b3f58c..4907134ffe1f 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -9418,6 +9418,7 @@ public class CarrierConfigManager {
* <li>3 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_SMS}</li>
* <li>4 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_VIDEO}</li>
* <li>5 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_EMERGENCY}</li>
+ * <li>6 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_MMS}</li>
* </ul>
* <p>
* An example config for two PLMNs "123411" and "123412":
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index 6258b9c74282..631013fc485e 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -170,7 +170,7 @@ public final class NetworkRegistrationInfo implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "SERVICE_TYPE_",
value = {SERVICE_TYPE_UNKNOWN, SERVICE_TYPE_VOICE, SERVICE_TYPE_DATA, SERVICE_TYPE_SMS,
- SERVICE_TYPE_VIDEO, SERVICE_TYPE_EMERGENCY})
+ SERVICE_TYPE_VIDEO, SERVICE_TYPE_EMERGENCY, SERVICE_TYPE_MMS})
public @interface ServiceType {}
/**
@@ -203,11 +203,16 @@ public final class NetworkRegistrationInfo implements Parcelable {
*/
public static final int SERVICE_TYPE_EMERGENCY = 5;
+ /**
+ * MMS service
+ */
+ public static final int SERVICE_TYPE_MMS = 6;
+
/** @hide */
public static final int FIRST_SERVICE_TYPE = SERVICE_TYPE_VOICE;
/** @hide */
- public static final int LAST_SERVICE_TYPE = SERVICE_TYPE_EMERGENCY;
+ public static final int LAST_SERVICE_TYPE = SERVICE_TYPE_MMS;
@Domain
private final int mDomain;
@@ -739,6 +744,7 @@ public final class NetworkRegistrationInfo implements Parcelable {
case SERVICE_TYPE_SMS: return "SMS";
case SERVICE_TYPE_VIDEO: return "VIDEO";
case SERVICE_TYPE_EMERGENCY: return "EMERGENCY";
+ case SERVICE_TYPE_MMS: return "MMS";
}
return "Unknown service type " + serviceType;
}
diff --git a/tests/CompanionDeviceMultiDeviceTests/host/Android.bp b/tests/CompanionDeviceMultiDeviceTests/host/Android.bp
index 1167a3e30ed4..03335c7cd576 100644
--- a/tests/CompanionDeviceMultiDeviceTests/host/Android.bp
+++ b/tests/CompanionDeviceMultiDeviceTests/host/Android.bp
@@ -37,7 +37,6 @@ python_test_host {
},
data: [
":cdm_snippet",
- "requirements.txt",
],
version: {
py2: {
diff --git a/tests/CompanionDeviceMultiDeviceTests/host/cdm_transport_test.py b/tests/CompanionDeviceMultiDeviceTests/host/cdm_transport_test.py
index 9cb2d10fd2ee..5516c0f8e09f 100644
--- a/tests/CompanionDeviceMultiDeviceTests/host/cdm_transport_test.py
+++ b/tests/CompanionDeviceMultiDeviceTests/host/cdm_transport_test.py
@@ -25,12 +25,4 @@ class TransportTestClass(cdm_base_test.BaseTestClass):
if __name__ == '__main__':
- try:
- # Take test args and remove standalone '--' from the list
- index = sys.argv.index('--')
- sys.argv = sys.argv[:1] + sys.argv[index + 1:]
- except ValueError:
- # Ignore if '--' is not in args
- pass
-
test_runner.main() \ No newline at end of file
diff --git a/tests/CompanionDeviceMultiDeviceTests/host/requirements.txt b/tests/CompanionDeviceMultiDeviceTests/host/requirements.txt
deleted file mode 100644
index 86a11aa0abf1..000000000000
--- a/tests/CompanionDeviceMultiDeviceTests/host/requirements.txt
+++ /dev/null
@@ -1 +0,0 @@
-mobly==1.12.1
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt
new file mode 100644
index 000000000000..2a2b70e6a20f
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.device.apphelpers.StandardAppHelper
+import android.tools.device.traces.parsers.toFlickerComponent
+import com.android.server.wm.flicker.testapp.ActivityOptions
+
+class TransferSplashscreenAppHelper
+@JvmOverloads
+constructor(
+ instr: Instrumentation,
+ launcherName: String = ActivityOptions.TransferSplashscreenActivity.LABEL,
+ component: ComponentNameMatcher =
+ ActivityOptions.TransferSplashscreenActivity.COMPONENT.toFlickerComponent()
+) : StandardAppHelper(instr, launcherName, component) \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
index 3a784ff30e91..ec792ca27685 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
@@ -53,7 +53,8 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppFromIconColdTest(flicker: LegacyFlickerTest) : OpenAppFromLauncherTransition(flicker) {
+open class OpenAppFromIconColdTest(flicker: LegacyFlickerTest) :
+ OpenAppFromLauncherTransition(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
get() = {
@@ -87,6 +88,7 @@ class OpenAppFromIconColdTest(flicker: LegacyFlickerTest) : OpenAppFromLauncherT
override fun appWindowReplacesLauncherAsTopWindow() {
super.appWindowReplacesLauncherAsTopWindow()
}
+
@FlakyTest(bugId = 240916028)
@Test
override fun appWindowAsTopWindowAtEnd() {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt
new file mode 100644
index 000000000000..1fdef3c53224
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import android.platform.test.annotations.Presubmit
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.helpers.TransferSplashscreenAppHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test cold launching an app from launcher
+ *
+ * To run this test: `atest FlickerTests:OpenTransferSplashscreenAppFromLauncherTransition`
+ *
+ * Actions:
+ * ```
+ * Inherit from OpenAppFromIconColdTest, Launch an app [testApp] with an animated splash screen
+ * by clicking it's icon on all apps, and wait for transfer splash screen complete
+ * ```
+ *
+ * Notes:
+ * ```
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [OpenAppTransition]
+ * 2. Verify no flickering when transfer splash screen to app window.
+ * ```
+ */
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class OpenTransferSplashscreenAppFromLauncherTransition(flicker: LegacyFlickerTest) :
+ OpenAppFromIconColdTest(flicker) {
+ override val testApp = TransferSplashscreenAppHelper(instrumentation)
+
+ /**
+ * Checks that [ComponentNameMatcher.LAUNCHER] window is the top window at the start of the
+ * transition, and is replaced by [ComponentNameMatcher.SPLASH_SCREEN], then [testApp] remains
+ * visible until the end
+ */
+ @Presubmit
+ @Test
+ fun appWindowAfterSplash() {
+ flicker.assertWm {
+ this.isAppWindowOnTop(ComponentNameMatcher.LAUNCHER)
+ .then()
+ .isAppWindowOnTop(ComponentNameMatcher.SPLASH_SCREEN)
+ .then()
+ .isAppWindowOnTop(testApp)
+ .isAppWindowInvisible(ComponentNameMatcher.SPLASH_SCREEN)
+ }
+ }
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt
index b34da72ea5d6..4adcc8bf5f0b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt
@@ -25,10 +25,12 @@ import android.tools.common.flicker.config.FlickerConfig
import android.tools.common.flicker.config.FlickerServiceConfig
import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWithOverlayApp
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(FlickerServiceJUnit4ClassRunner::class)
+@Ignore("b/294418322: no notification launch animation exists when keyguard is occluded")
class OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape :
OpenAppFromLockscreenNotificationWithOverlayApp(NavBar.MODE_3BUTTON, Rotation.ROTATION_90) {
@ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt
index b1638979cd0d..f7211e7287cf 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt
@@ -25,10 +25,12 @@ import android.tools.common.flicker.config.FlickerConfig
import android.tools.common.flicker.config.FlickerServiceConfig
import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWithOverlayApp
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(FlickerServiceJUnit4ClassRunner::class)
+@Ignore("b/294418322: no notification launch animation exists when keyguard is occluded")
class OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait :
OpenAppFromLockscreenNotificationWithOverlayApp(NavBar.MODE_3BUTTON, Rotation.ROTATION_0) {
@ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt
index 19b533ed57af..1ade9560d90f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt
@@ -25,10 +25,12 @@ import android.tools.common.flicker.config.FlickerConfig
import android.tools.common.flicker.config.FlickerServiceConfig
import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWithOverlayApp
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(FlickerServiceJUnit4ClassRunner::class)
+@Ignore("b/294418322: no notification launch animation exists when keyguard is occluded")
class OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape :
OpenAppFromLockscreenNotificationWithOverlayApp(NavBar.MODE_GESTURAL, Rotation.ROTATION_90) {
@ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt
index c9ed4f42af06..ea26f0867c7f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt
@@ -25,10 +25,12 @@ import android.tools.common.flicker.config.FlickerConfig
import android.tools.common.flicker.config.FlickerServiceConfig
import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWithOverlayApp
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(FlickerServiceJUnit4ClassRunner::class)
+@Ignore("b/294418322: no notification launch animation exists when keyguard is occluded")
class OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait :
OpenAppFromLockscreenNotificationWithOverlayApp(NavBar.MODE_GESTURAL, Rotation.ROTATION_0) {
@ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
diff --git a/tests/FlickerTests/test-apps/flickerapp/Android.bp b/tests/FlickerTests/test-apps/flickerapp/Android.bp
index 75e35ee9c765..e3b23b986c83 100644
--- a/tests/FlickerTests/test-apps/flickerapp/Android.bp
+++ b/tests/FlickerTests/test-apps/flickerapp/Android.bp
@@ -24,6 +24,9 @@ package {
android_test {
name: "FlickerTestApp",
srcs: ["**/*.java"],
+ resource_dirs: [
+ "res",
+ ],
sdk_version: "current",
test_suites: ["device-tests"],
static_libs: [
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index ff9799a1c710..704798e11016 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -347,6 +347,17 @@
android:exported="false"
android:theme="@style/CutoutShortEdges"
android:resizeableActivity="true"/>
+ <activity
+ android:name=".TransferSplashscreenActivity"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.TransferSplashscreenActivity"
+ android:label="TransferSplashscreenActivity"
+ android:theme="@style/SplashscreenAppTheme"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
<service
android:name=".AssistantInteractionSessionService"
android:exported="true"
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/drawable/avd_anim.xml b/tests/FlickerTests/test-apps/flickerapp/res/drawable/avd_anim.xml
new file mode 100644
index 000000000000..19205d4d1c14
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/drawable/avd_anim.xml
@@ -0,0 +1,94 @@
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="432dp" android:width="432dp" android:viewportHeight="432" android:viewportWidth="432">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_5_G" android:translateX="216" android:translateY="216" android:scaleX="1.5" android:scaleY="1.5">
+ <path android:name="_R_G_L_5_G_D_0_P_0" android:fillColor="#555555" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M53.82 -56.7 C53.82,-56.7 43.64,-49.06 43.64,-49.06 C43.64,-49.06 0,-16.34 0,-16.34 C0,-16.34 -43.64,-49.06 -43.64,-49.06 C-43.64,-49.06 -53.82,-56.7 -53.82,-56.7 C-64.6,-64.79 -80,-57.09 -80,-43.61 C-80,-43.61 -80,-29.07 -80,-29.07 C-80,-29.07 -80,49.09 -80,49.09 C-80,55.12 -75.12,60 -69.09,60 C-69.09,60 -43.64,60 -43.64,60 C-43.64,60 -43.64,-1.8 -43.64,-1.8 C-43.64,-1.8 0,30.92 0,30.92 C0,30.92 43.64,-1.8 43.64,-1.8 C43.64,-1.8 43.64,60 43.64,60 C43.64,60 69.09,60 69.09,60 C75.12,60 80,55.12 80,49.09 C80,49.09 80,-29.07 80,-29.07 C80,-29.07 80,-43.61 80,-43.61 C80,-57.09 64.61,-64.79 53.82,-56.7c "/>
+ </group>
+ <group android:name="_R_G_L_4_G" android:translateX="216" android:translateY="216" android:scaleX="1.5" android:scaleY="1.5">
+ <clip-path android:name="mask_x" android:pathData="M53.82 -56.7 C53.82,-56.7 43.64,-49.06 43.64,-49.06 C43.64,-49.06 0,-16.34 0,-16.34 C0,-16.34 -43.64,-49.06 -43.64,-49.06 C-43.64,-49.06 -53.82,-56.7 -53.82,-56.7 C-64.6,-64.79 -80,-57.09 -80,-43.61 C-80,-43.61 -80,-29.07 -80,-29.07 C-80,-29.07 -80,49.09 -80,49.09 C-80,55.12 -75.12,60 -69.09,60 C-69.09,60 -43.64,60 -43.64,60 C-43.64,60 -43.64,-1.8 -43.64,-1.8 C-43.64,-1.8 0,30.92 0,30.92 C0,30.92 43.64,-1.8 43.64,-1.8 C43.64,-1.8 43.64,60 43.64,60 C43.64,60 69.09,60 69.09,60 C75.12,60 80,55.12 80,49.09 C80,49.09 80,-29.07 80,-29.07 C80,-29.07 80,-43.61 80,-43.61 C80,-57.09 64.61,-64.79 53.82,-56.7c"/>
+ <path android:name="_R_G_L_4_G_D_0_P_0" android:fillColor="#2684fc" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-80.39 60 C-80.39,60 -105.84,60 -105.84,60 C-111.87,60 -116.75,55.12 -116.75,49.09 C-116.75,49.09 -116.75,-60 -116.75,-60 C-116.75,-60 -80.39,-60 -80.39,-60 C-80.39,-60 -80.39,60 -80.39,60c "/>
+ </group>
+ <group android:name="_R_G_L_3_G" android:translateX="216" android:translateY="216" android:scaleX="1.5" android:scaleY="1.5">
+ <clip-path android:name="mask_x" android:pathData="M53.82 -56.7 C53.82,-56.7 43.64,-49.06 43.64,-49.06 C43.64,-49.06 0,-16.34 0,-16.34 C0,-16.34 -43.64,-49.06 -43.64,-49.06 C-43.64,-49.06 -53.82,-56.7 -53.82,-56.7 C-64.6,-64.79 -80,-57.09 -80,-43.61 C-80,-43.61 -80,-29.07 -80,-29.07 C-80,-29.07 -80,49.09 -80,49.09 C-80,55.12 -75.12,60 -69.09,60 C-69.09,60 -43.64,60 -43.64,60 C-43.64,60 -43.64,-1.8 -43.64,-1.8 C-43.64,-1.8 0,30.92 0,30.92 C0,30.92 43.64,-1.8 43.64,-1.8 C43.64,-1.8 43.64,60 43.64,60 C43.64,60 69.09,60 69.09,60 C75.12,60 80,55.12 80,49.09 C80,49.09 80,-29.07 80,-29.07 C80,-29.07 80,-43.61 80,-43.61 C80,-57.09 64.61,-64.79 53.82,-56.7c"/>
+ <path android:name="_R_G_L_3_G_D_0_P_0" android:fillColor="#00ac47" android:fillAlpha="1" android:fillType="nonZero" android:pathData="M80.64 60 C80.64,60 106.09,60 106.09,60 C112.12,60 117,55.12 117,49.09 C117,49.09 117,-60 117,-60 C117,-60 80.64,-60 80.64,-60 C80.64,-60 80.64,60 80.64,60c "/>
+ </group>
+ <group android:name="_R_G_L_2_G" android:translateX="216" android:translateY="216" android:scaleX="1.5" android:scaleY="1.5">
+ <clip-path android:name="mask_x" android:pathData="M53.82 -56.7 C53.82,-56.7 43.64,-49.06 43.64,-49.06 C43.64,-49.06 0,-16.34 0,-16.34 C0,-16.34 -43.64,-49.06 -43.64,-49.06 C-43.64,-49.06 -53.82,-56.7 -53.82,-56.7 C-64.6,-64.79 -80,-57.09 -80,-43.61 C-80,-43.61 -80,-29.07 -80,-29.07 C-80,-29.07 -80,49.09 -80,49.09 C-80,55.12 -75.12,60 -69.09,60 C-69.09,60 -43.64,60 -43.64,60 C-43.64,60 -43.64,-1.8 -43.64,-1.8 C-43.64,-1.8 0,30.92 0,30.92 C0,30.92 43.64,-1.8 43.64,-1.8 C43.64,-1.8 43.64,60 43.64,60 C43.64,60 69.09,60 69.09,60 C75.12,60 80,55.12 80,49.09 C80,49.09 80,-29.07 80,-29.07 C80,-29.07 80,-43.61 80,-43.61 C80,-57.09 64.61,-64.79 53.82,-56.7c"/>
+ <path android:name="_R_G_L_2_G_D_0_P_0" android:fillColor="#fe2c25" android:fillAlpha="1" android:fillType="nonZero" android:pathData="M53.82 -104.7 C53.82,-104.7 0,-64.34 0,-64.34 C0,-64.34 -53.82,-104.7 -53.82,-104.7 C-64.6,-112.79 -80,-105.09 -80,-91.61 C-80,-91.61 -80,-77.07 -80,-77.07 C-80,-77.07 0,-17.08 0,-17.08 C0,-17.08 80,-77.07 80,-77.07 C80,-77.07 80,-91.61 80,-91.61 C80,-105.09 64.61,-112.79 53.82,-104.7c "/>
+ </group>
+ <group android:name="_R_G_L_1_G" android:translateX="216" android:translateY="216" android:scaleX="1.5" android:scaleY="1.5">
+ <clip-path android:name="mask_x" android:pathData="M43.64 -1.8 C43.64,-1.8 43.64,-49.06 43.64,-49.06 C43.64,-49.06 53.82,-56.7 53.82,-56.7 C64.61,-64.79 80,-57.09 80,-43.61 C80,-43.61 80,-1.8 80,-1.8 C80,-1.8 43.64,-1.8 43.64,-1.8c"/>
+ <path android:name="_R_G_L_1_G_D_0_P_0" android:fillColor="#ffba00" android:fillAlpha="1" android:fillType="nonZero" android:pathData="M80.64 -135 C80.64,-135 117,-135 117,-135 C117,-135 117,-104.07 117,-104.07 C117,-104.07 80.64,-76.8 80.64,-76.8 C80.64,-76.8 80.64,-135 80.64,-135c "/>
+ </group>
+ <group android:name="_R_G_L_0_G" android:translateX="216" android:translateY="216" android:scaleX="1.5" android:scaleY="1.5">
+ <clip-path android:name="mask_x" android:pathData="M-43.64 -1.8 C-43.64,-1.8 -80,-1.8 -80,-1.8 C-80,-1.8 -80,-43.61 -80,-43.61 C-80,-57.09 -64.6,-64.79 -53.82,-56.7 C-53.82,-56.7 -43.64,-49.06 -43.64,-49.06 C-43.64,-49.06 -43.64,-1.8 -43.64,-1.8c"/>
+ <path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#d70007" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M-117 -104.07 C-117,-104.07 -117,-135 -117,-135 C-117,-135 -80.64,-135 -80.64,-135 C-80.64,-135 -80.64,-76.8 -80.64,-76.8 C-80.64,-76.8 -117,-104.07 -117,-104.07c "/>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_4_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="1567" android:startOffset="233" android:valueFrom="M-80.39 60 C-80.39,60 -105.84,60 -105.84,60 C-111.87,60 -116.75,55.12 -116.75,49.09 C-116.75,49.09 -116.75,-60 -116.75,-60 C-116.75,-60 -80.39,-60 -80.39,-60 C-80.39,-60 -80.39,60 -80.39,60c " android:valueTo=" M-43.64 60 C-43.64,60 -69.09,60 -69.09,60 C-75.12,60 -80,55.12 -80,49.09 C-80,49.09 -80,-60 -80,-60 C-80,-60 -43.64,-60 -43.64,-60 C-43.64,-60 -43.64,60 -43.64,60c " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_3_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="1567" android:startOffset="233" android:valueFrom=" M80.64 60 C80.64,60 106.09,60 106.09,60 C112.12,60 117,55.12 117,49.09 C117,49.09 117,-60 117,-60 C117,-60 80.64,-60 80.64,-60 C80.64,-60 80.64,60 80.64,60c " android:valueTo=" M43.64 60 C43.64,60 69.09,60 69.09,60 C75.12,60 80,55.12 80,49.09 C80,49.09 80,-60 80,-60 C80,-60 43.64,-60 43.64,-60 C43.64,-60 43.64,60 43.64,60c " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_2_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="1567" android:startOffset="233" android:valueFrom="M53.82 -104.7 C53.82,-104.7 0,-64.34 0,-64.34 C0,-64.34 -53.82,-104.7 -53.82,-104.7 C-64.6,-112.79 -80,-105.09 -80,-91.61 C-80,-91.61 -80,-77.07 -80,-77.07 C-80,-77.07 0,-17.08 0,-17.08 C0,-17.08 80,-77.07 80,-77.07 C80,-77.07 80,-91.61 80,-91.61 C80,-105.09 64.61,-112.79 53.82,-104.7c" android:valueTo="M53.82 -56.7 C53.82,-56.7 0,-16.34 0,-16.34 C0,-16.34 -53.82,-56.7 -53.82,-56.7 C-64.6,-64.79 -80,-57.09 -80,-43.61 C-80,-43.61 -80,-29.07 -80,-29.07 C-80,-29.07 0,30.92 0,30.92 C0,30.92 80,-29.07 80,-29.07 C80,-29.07 80,-43.61 80,-43.61 C80,-57.09 64.61,-64.79 53.82,-56.7c " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="1567" android:startOffset="233" android:valueFrom=" M80.64 -135 C80.64,-135 117,-135 117,-135 C117,-135 117,-104.07 117,-104.07 C117,-104.07 80.64,-76.8 80.64,-76.8 C80.64,-76.8 80.64,-135 80.64,-135c " android:valueTo=" M43.64 -60 C43.64,-60 80,-60 80,-60 C80,-60 80,-29.07 80,-29.07 C80,-29.07 43.64,-1.8 43.64,-1.8 C43.64,-1.8 43.64,-60 43.64,-60c " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData" android:duration="1567" android:startOffset="233" android:valueFrom=" M-117 -104.07 C-117,-104.07 -117,-135 -117,-135 C-117,-135 -80.64,-135 -80.64,-135 C-80.64,-135 -80.64,-76.8 -80.64,-76.8 C-80.64,-76.8 -117,-104.07 -117,-104.07c " android:valueTo=" M-80 -29.07 C-80,-29.07 -80,-60 -80,-60 C-80,-60 -43.64,-60 -43.64,-60 C-43.64,-60 -43.64,-1.8 -43.64,-1.8 C-43.64,-1.8 -80,-29.07 -80,-29.07c " android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX" android:duration="2017" android:startOffset="0" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml b/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml
index e51ed29adebf..9b742d96e35b 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml
@@ -53,4 +53,11 @@
<style name="no_starting_window" parent="@android:style/Theme.DeviceDefault">
<item name="android:windowDisablePreview">true</item>
</style>
+
+ <style name="SplashscreenAppTheme" parent="@android:style/Theme.DeviceDefault">
+ <!-- Splashscreen Attributes -->
+ <item name="android:windowSplashScreenAnimatedIcon">@drawable/avd_anim</item>
+ <!-- Here we want to match the duration of our AVD -->
+ <item name="android:windowSplashScreenAnimationDuration">900</item>
+ </style>
</resources>
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 2795a6c43015..7c5e9a3f86b5 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -178,6 +178,12 @@ public class ActivityOptions {
FLICKER_APP_PACKAGE + ".LaunchNewActivity");
}
+ public static class TransferSplashscreenActivity {
+ public static final String LABEL = "TransferSplashscreenActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".TransferSplashscreenActivity");
+ }
+
public static class Pip {
// Test App > Pip Activity
public static final String LABEL = "PipActivity";
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/TransferSplashscreenActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/TransferSplashscreenActivity.java
new file mode 100644
index 000000000000..0323286a0e21
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/TransferSplashscreenActivity.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.window.SplashScreen;
+import android.window.SplashScreenView;
+
+public class TransferSplashscreenActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final SplashScreen splashScreen = getSplashScreen();
+ // Register setOnExitAnimationListener to transfer the splash screen window to client.
+ splashScreen.setOnExitAnimationListener(this::onSplashScreenExit);
+ final View content = findViewById(android.R.id.content);
+ // By register preDrawListener to defer app window draw signal about 500ms, which to ensure
+ // the splash screen must show when cold launch.
+ content.getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ final long mCreateTime = SystemClock.uptimeMillis();
+ @Override
+ public boolean onPreDraw() {
+ return SystemClock.uptimeMillis() - mCreateTime > 500;
+ }
+ }
+ );
+ }
+
+ private void onSplashScreenExit(SplashScreenView view) {
+ view.remove();
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java
index e2d17cdbe9e6..1f4c6c53b260 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java
@@ -17,6 +17,7 @@
package com.android.test.hwui;
import android.app.Activity;
+import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorSpace;
@@ -72,6 +73,10 @@ public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callb
private int[] mGradientEndColors = {0xFFFFFFFF, 0xFFFF0000, 0xFF00FF00, 0xFF0000FF};
private String[] mGradientColorNames = {"Grayscale", "Red", "Green", "Blue"};
+ private int mColorMode = ActivityInfo.COLOR_MODE_DEFAULT;
+ private int[] mColorModes = {ActivityInfo.COLOR_MODE_DEFAULT, ActivityInfo.COLOR_MODE_HDR};
+ private String[] mColorModeNames = {"DEFAULT", "HDR"};
+
private final ExecutorService mBufferFenceExecutor = Executors.newFixedThreadPool(1);
private final ExecutorService mBufferExecutor = Executors.newFixedThreadPool(1);
@@ -139,6 +144,15 @@ public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callb
gradientColorSpinner
.setOnItemSelectedListener(new GradientColorOnItemSelectedListener());
+ ArrayAdapter<String> colorModeAdapter = new ArrayAdapter<>(
+ this, android.R.layout.simple_spinner_item, mColorModeNames);
+
+ colorModeAdapter
+ .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ Spinner colorModeSpinner = new Spinner(this);
+ colorModeSpinner.setAdapter(colorModeAdapter);
+ colorModeSpinner.setOnItemSelectedListener(new ColorModeOnItemSelectedListener());
+
mGradientBuffer = getGradientBuffer().get();
LinearLayout linearLayout = new LinearLayout(this);
@@ -169,6 +183,10 @@ public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callb
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
+ spinnerLayout.addView(colorModeSpinner, new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
+
linearLayout.addView(spinnerLayout, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
@@ -187,6 +205,8 @@ public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callb
linearLayout.addView(mSurfaceView, new LinearLayout.LayoutParams(WIDTH, HEIGHT));
setContentView(linearLayout);
+
+ getWindow().setColorMode(mColorMode);
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -312,4 +332,22 @@ public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callb
}
}
+
+ private final class ColorModeOnItemSelectedListener
+ implements AdapterView.OnItemSelectedListener {
+
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ ColorBitmapActivity.this.mColorMode = ColorBitmapActivity.this.mColorModes[position];
+ ColorBitmapActivity.this.getMainExecutor()
+ .execute(() -> {
+ ColorBitmapActivity.this.getWindow().setColorMode(mColorMode);
+ });
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+
+ }
+ }
}
diff --git a/tests/testables/src/android/testing/TestableResources.java b/tests/testables/src/android/testing/TestableResources.java
index 27d5b66b355e..0ec106e329f6 100644
--- a/tests/testables/src/android/testing/TestableResources.java
+++ b/tests/testables/src/android/testing/TestableResources.java
@@ -15,9 +15,11 @@
package android.testing;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.util.Log;
import android.util.SparseArray;
@@ -54,6 +56,16 @@ public class TestableResources {
}
/**
+ * Sets a configuration for {@link #getResources()} to return to allow custom configs to
+ * be set and tested.
+ *
+ * @param configuration the configuration to return from resources.
+ */
+ public void overrideConfiguration(Configuration configuration) {
+ when(mResources.getConfiguration()).thenReturn(configuration);
+ }
+
+ /**
* Sets the return value for the specified resource id.
* <p>
* Since resource ids are unique there is a single addOverride that will override the value